国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

如何向一個WebApp引入Spring與Spring MVC

maochunguang / 3148人閱讀

摘要:可以發現,這兩個類都是可以被實例化的,且構造器不需要參數。這段代碼的后半部分其實沒有什么新意,但下半部分的第一行非常關鍵接受一個作為構造器參數這實際上解決了我們在第四章測試失敗后反思的可能的疑惑我們配置的容器實際上并沒有和融合起來。

如何向一個WebApp引入Spring與Spring MVC 1

在Servlet 3.0環境中,容器(加載運行webapp的軟件,如Tomcat)會在類路徑中查找實現==javax.servlet.ServletContainerInitializer==接口的類(這一行為本質上是Java EE標準和協定所要求的,Tomcat是基于該協定的一種實現),如果能發現的話,就會用它來配置Servlet容器。

Spring提供了這個接口的實現,名為SpringServletContainerInitializer,因此一個引入的SringMVC的web項目在沒有其它設置的情況下會被Tomcat找到SpringServletContainerInitializer。

SpringServletContainerInitializer

2

==SpringServletContainerInitializer==又會查找實現==WebApplicationInitializer==接口的類并調用其onStartup(ServletContext servletContext)方法,其中ServletContext對象由其負責將服務器生成的唯一的ServletContext實例傳入。

WebApplicationInitializer

Interface to be implemented in Servlet 3.0+ environments in order to configure the ServletContext programmatically -- as opposed to (or possibly in conjunction with) the traditional web.xml-based approach.

ServletContext

Defines a set of methods that a servlet uses to communicate with its servlet container, for example,

到目前位置,我們已經可以使用SpringMVC來增設Servlet了,雖然這看起來并不美觀也不簡便。代碼如下所示。

package spittr.config;

import org.springframework.web.WebApplicationInitializer;
import spittr.web.AServlet;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration;

public class SpittrWebAppInitializer implements WebApplicationInitializer {
    @Override
    public void onStartup(ServletContext servletContext) throws ServletException {
        //增加一個Servelt 其中AServlet是Servlet接口的實現類,我的實現直接繼承了HttpServlet
        ServletRegistration.Dynamic aServlet = servletContext.addServlet("AServlet", AServlet.class);
        //為AServlet增設映射路徑,其作用等同于@WebServlet(urlPatterns={"/AServlet"})
        aServlet.addMapping(new String[]{"/AServlet"});
    }
}
package spittr.web;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

public class AServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setCharacterEncoding("UTF-8");
        resp.setContentType("text/html;charset=utf-8");

        PrintWriter writer = resp.getWriter();

        writer.write("我收到了你的GET");
    }
}

現在我們可以向瀏覽器直接訪問AServlet

然而,這樣的實現在美觀和便利上遠遠不如使用Servlet3.0引入和更新的@WebServlet等機制。

并且完全沒有涉及Spring和Spring MVC,只是按照Servlet3.0的標準的一種添加Servlet的方式罷了。

那么接下來我們就要開始引入Spring和Spring MVC了。

3

第一步肯定是引入Spring,也即引入一個Spring的容器。

這很簡單,在onStartup中實例化一個ApplicationContext的實例即可。查詢ApplicationContext的javadoc,看到目前所有的ApplicationContext實現類:

All Known Implementing Classes:
AbstractApplicationContext, AbstractRefreshableApplicationContext, AbstractRefreshableConfigApplicationContext, AbstractRefreshableWebApplicationContext, AbstractXmlApplicationContext, AnnotationConfigApplicationContext, AnnotationConfigWebApplicationContext, ClassPathXmlApplicationContext, FileSystemXmlApplicationContext, GenericApplicationContext, GenericGroovyApplicationContext, GenericWebApplicationContext, GenericXmlApplicationContext, GroovyWebApplicationContext, ResourceAdapterApplicationContext, StaticApplicationContext, StaticWebApplicationContext, XmlWebApplicationContext

而我們打算使用基于Java代碼的配置并開啟基于注解的自動掃描,同時應用場景為webapp,所以應該使用AnnotationConfigWebApplicationContext實現類。

綜上所述,可以得到如下代碼:

package spittr.config;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.web.WebApplicationInitializer;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;

public class SpittrWebAppInitializer implements WebApplicationInitializer {
    @Override
    public void onStartup(ServletContext servletContext) throws ServletException {
        AnnotationConfigWebApplicationContext ac = new AnnotationConfigWebApplicationContext();
        ac.register(AppConfig.class);
    }
}
@Configuration
@ComponentScan("spittr.web")
public class AppConfig {
}

至此,我們已經在這個webapp中集成了Spring容器,從理論上講,我們應該可以對一個Servlet標注@Controller后使其自動被注冊和使用。但是由于@RequestMapping我們還不知道能不能用,實際上無法對其進行測試(因為即便將服務器注冊到了Spring容器中,我們也無法為它配置映射路徑)。

那么現在就該去解決@RequestMapping了。

4

javadoc:@RequestMapping。

@RequestMapping javadoc這一注解做了如下解讀

Annotation for mapping web requests onto methods in request-handling classes with flexible method signatures.

Both Spring MVC and Spring WebFlux support this annotation through a RequestMappingHandlerMapping and RequestMappingHandlerAdapter in their respective modules and package structure. For the exact list of supported handler method arguments and return types in each, please use the reference documentation links below:

Spring MVC Method Arguments and Return Values

Spring WebFlux Method Arguments and Return Values

Note: This annotation can be used both at the class and at the method level. In most cases, at the method level applications will prefer to use one of the HTTP method specific variants @GetMapping, @PostMapping, @PutMapping, @DeleteMapping, or @PatchMapping.

NOTE: When using controller interfaces (e.g. for AOP proxying), make sure to consistently put all your mapping annotations - such as @RequestMapping and @SessionAttributes - on the controller interface rather than on the implementation class.

其中最重要的在第二段,它說明了Spring MVC通過使用RequestMappingHandlerMappingRequestMappingHandlerAdapter 得以支持@RequestMappin注解。

javadoc:RequestMappingHandlerMapping

javadoc:RequestMappingHandlerAdapter

可以發現,這兩個類都是可以被實例化的,且構造器不需要參數。

既然如此,我們可以試著在AppConfig中配置這兩個類。

@Configuration
@ComponentScan("spittr.web")
public class AppConfig {
    @Bean
    public RequestMappingHandlerAdapter requestMappingHandlerAdapter(){
        return new RequestMappingHandlerAdapter();
    }
    @Bean
    public RequestMappingHandlerMapping requestMappingHandlerMapping(){
        return new RequestMappingHandlerMapping();
    }
}

然后使用帶@Controller和@RequestMapping的類

package spittr.web;

@Controller
@RequestMapping("/BServlet")
public class BServlet{
    @RequestMapping(method = RequestMethod.GET)
    public void doGet() {
        System.out.println("BServlet:我收到了你的GET");
    }
}

不過測試結果是糟糕的,我們沒有如愿實現訪問BServlet。

失敗的原因沒有官方文檔直接告知,但結合之后進一步的學習,不難猜測理由應該是:我們AppConfig的Spring-beans容器其實沒有和Servlet容器結合起來。我們只是在onStartUp方法中實例化了一個Spring-beans容器,甚至可以認為在方法的生命周期結束之后,這個實例就直接沒了。如若真的如此,我們就連實際上把Spring集成到這個WebApp中都沒有做到,怎么可能做到開啟Spring MVC注解呢。

5

事已至此,就只能閱讀官方文檔了。官方文檔

開門見山地:

Spring MVC, as many other web frameworks, is designed around the front controller pattern where a central Servlet, the DispatcherServlet, provides a shared algorithm for request processing, while actual work is performed by configurable delegate components. This model is flexible and supports diverse workflows.

→Spring MVC圍繞一個前線控制器模式(front controller pattern)而設計,在這種模式下一個核心Servlet,也就是DispatchereServlet(由Spring實現的Servlet類),會為處理客戶端請求提供了算法,而真正的工作(處理請求)由可配置的代理組件來執行。

因此可以認為,要充分利用SpringMVC,必然要加載SpringMVC自行實現的Servlet類:org.springframework.web.servlet.DispatcherServlet

org.springframework.web.servlet.DispatcherServlet

官方文檔給出了一段初始化代碼:

public class MyWebApplicationInitializer implements WebApplicationInitializer {

    @Override
    public void onStartup(ServletContext servletCxt) {

        // Load Spring web application configuration
        AnnotationConfigWebApplicationContext ac = new AnnotationConfigWebApplicationContext();
        //AppConfig是自定義的帶@Configuration注解的類
        ac.register(AppConfig.class);
        ac.refresh();

        // Create and register the DispatcherServlet
        // 將Spring容器與DispatcherServlet綁定
        DispatcherServlet servlet = new DispatcherServlet(ac);
        ServletRegistration.Dynamic registration = servletCxt.addServlet("app", servlet);
        registration.setLoadOnStartup(1);
        registration.addMapping("/app/*");
    }
}

這段代碼的前半部分,我們是很熟悉的。第三章就做過。

這段代碼的后半部分其實沒有什么新意,但下半部分的第一行非常關鍵

DispatcherServlet servlet = new DispatcherServlet(ac);

接受一個AnnotationConfigWebApplicationContext作為構造器參數!這實際上解決了我們在第四章測試失敗后反思的可能的疑惑——我們配置的Spring容器實際上并沒有和tomcat融合起來。

那么現在,將官方代碼中的ac換成我們自己的,是不是就能成功了呢?不妨一試

public class SpittrWebAppInitializer implements WebApplicationInitializer {
    @Override
    public void onStartup(ServletContext servletContext) throws ServletException {
        AnnotationConfigWebApplicationContext ac = new AnnotationConfigWebApplicationContext();
        ac.register(AppConfig.class);

        DispatcherServlet dispatcher = new DispatcherServlet(ac);
        ServletRegistration.Dynamic d = servletContext.addServlet("dispatcher", dispatcher);
        d.setLoadOnStartup(1);
        d.addMapping("/");
    }
}
/*
AppConfig
BServlet
相較之前完全沒有變化,所以不展示
*/

結果是喜人的,我們嘗試成功了。可以看到輸出BServlet:我收到了你的GET

官方文檔進一步說明:

The DispatcherServlet, as any Servlet, needs to be declared and mapped according to the Servlet specification by using Java configuration or in web.xml.  In turn, the DispatcherServlet uses Spring configuration to discover the delegate components it needs for request mapping, view resolution, exception handling, and more.

The following example of the Java configuration registers and initializes the DispatcherServlet, which is auto-detected by the Servlet container (see Servlet Config):

這段話應該分成這兩個部分:

The DispatcherServlet, as any Servlet, needs to be declared and mapped according to the Servlet specification by using Java configuration or in web.xml.The following example of the Java configuration registers and initializes the DispatcherServlet, which is auto-detected by the Servlet container (see Servlet Config):

這一部分上來先說,DispatcherServlet就像任何Servlet一樣,也是需要做好聲明和映射的。下面的代碼介紹了使用Servlet container提供的自動探測注冊功能來注冊和初始化DispatcherServlet。這里所謂的Servlet container的自動探測,其實就是指之前提到的1,2兩個階段。

In turn, the DispatcherServlet uses Spring configuration to discover the delegate components it needs for request mapping, view resolution, exception handling, and more.

這一部分說,DispatcherServlet被配置注冊好之后,也可以反過來使用Spring配置來發現和委派為它為請求映射,視圖渲染,異常處理所需要的組件。
那么,DispatcherServlet要如何反過來配置它自己的組件呢?帶著這一疑問,我們繼續往下看。

6

官方文檔緊接著提到了一個WebApplicationInitializer的Spring實現類AbstractAnnotationConfigDispatcherServletInitializer,它可以避免直接使用ServletContext(它自己已經用了),通過重寫特定的方法完成配置。

In addition to using the ServletContext API directly, you can also extendAbstractAnnotationConfigDispatcherServletInitializer and override specific methods (see the example under Context Hierarchy).

跟隨Context Hierarchy超鏈接一探究竟。先放上example code:

public class MyWebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {

    @Override
    protected Class[] getRootConfigClasses() {
        return new Class[] { RootConfig.class };
    }

    @Override
    protected Class[] getServletConfigClasses() {
        return new Class[] { App1Config.class };
    }

    @Override
    protected String[] getServletMappings() {
        return new String[] { "/app1/*" };
    }
}

再看文字說明

DispatcherServlet expects a WebApplicationContext (an extension of a plain ApplicationContext) for its own configuration.

DispatcherServlet為它自己的配置需要一個WebApplicationContext(ApplicationContext的子接口)即一個Spring容器的配置實現類。

WebApplicationContext has a link to the ServletContext and the Servlet with which it is associated. It is also bound to the ServletContext such that applications can use static methods on RequestContextUtils to look up the WebApplicationContextif they need access to it.

一個Spring容器與ServletContext和與它共生的Servlet又關聯。這個Spring容器因為綁定ServletContext,所以也可以通過類RequestContextUtils的靜態方法去得到。

For many applications, having a single WebApplicationContext is simple and suffices. It is also possible to have a context hierarchy where one root WebApplicationContext is shared across multiple DispatcherServlet (or other Servlet) instances, each with its own child WebApplicationContext configuration. See Additional Capabilities of the ApplicationContext for more on the context hierarchy feature.

絕大部分應用來說,一個Spring容器就夠用了。但也可以有一個有層級的容器結構——一個根Spring容器在多個(全部)Servlet實例中共享,同時每個Servlet實例也有自己的WebApplicationContext配置。

Java EE和Servlet3.0標準的Servlet接口其實是不支持Servlet實例共生一個ApplicationContext的,因為后者畢竟是Spring的專屬。所以這里的Servlet實例考慮為像DispatcherServlet這樣由Spring實現并提供的類,而不包括用戶自定義的符合Java EE和Servlet3.0標準的Servlet接口的Servlet。

The root WebApplicationContext typically contains infrastructure beans, such as data repositories and business services that need to be shared across multiple Servlet instances. Those beans are effectively inherited and can be overridden (that is, re-declared) in the Servlet-specific child WebApplicationContext, which typically contains beans local to the given Servlet.

在層級話的Spring容器結構中,根Spring容器通常包含基礎設施的組件,比如數據持久化層,商業服務層這種需要在各種Servlet中共享的組件。這些組件能夠被有效地繼承地同時,也可以被在Servlet相關的子Spring容器中被重新配置,使得組件可以針對給定的Servlet因地制宜。

到這里再回看代碼。

    protected Class[] getRootConfigClasses() {
        return new Class[] { RootConfig.class };
    }

顯然,這里的RootConfig.class是用戶自定義的帶@Configuration注解的Spring容器配置類,用以實現根Spring容器。

    @Override
    protected Class[] getServletConfigClasses() {
        return new Class[] { App1Config.class };
    }

這個就是AbstractAnnotationConfigDispatcherServletInitializer默認實現的那個DispatcherServlet的伴生Spring容器配置。

    protected String[] getServletMappings() {
        return new String[] { "/app1/*" };
    }

這個則是確定AbstractAnnotationConfigDispatcherServletInitializer默認實現的那個DispatcherServlet所要管理的request URI映射。

至此1.1.1 Context Hierarchy結束,我們之前就是根據超鏈接跳到這一章節的,這一章節結束后,我們返回之前的位置繼續閱讀文檔。

發現緊接著就又是1.1.1 Context Hierarchy,直接跳過讀下一章。

7
1.1.2. Special Bean Types

The DispatcherServlet delegates special beans to process requests and render the appropriate responses. By “special beans” we mean Spring-managed Object instances that implement framework contracts. Those usually come with built-in contracts, but you can customize their properties and extend or replace them.

1.1.3. Web MVC Config

Applications can declare the infrastructure beans listed in Special Bean Types that are required to process requests. The DispatcherServlet checks the WebApplicationContext for each special bean. If there are no matching bean types, it falls back on the default types listed in DispatcherServlet.properties.

In most cases, the MVC Config is the best starting point. It declares the required beans in either Java or XML and provides a higher-level configuration callback API to customize it.

這兩個部分回答了我們的問題——DispatcherServlet要如何反過來配置它自己的組件——DispatcherServlet將會搜索它可以訪問的WebApplicationContext(這包括根Spring容器和它自己伴生的子Spring容器)來查找每個special bean——即被委派來處理請求渲染回應等工作的組件——的設置。如果沒有的話,它將使用默認的,保存在DispatcherServlet.properties中的設定。
很好理解的,我們之前所寫的AppConfig中的兩個Bean,它們是那么的基礎——由Spring提供和實現,我們只是new出來什么自定義也沒有——以至于使用DispatcherServlet的默認配置也不會更糟糕。所以我們去掉之前的AppConfig的配置,僅僅留下一個空的AppConfig,其它代碼不變。

再次測試,仍然能夠收到BServlet的輸出。

總結

到這里,對于如何將Spring和Spring MVC集成到一個WebApp中的過程以及為什么可以集成進來已經分析得差不多了。

更進一步得學習Spring MVC,就繼續仔細閱讀官方文檔吧!

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/75500.html

相關文章

  • SpringMVC之源碼分析--HandlerAdapter(三)

    摘要:概述回顧上兩章,我們主要分析了的概念作業以及如何使用的組件,本節以及后續幾章,將介紹為我們提供的的具體實現類,基于源碼和設計層面進行介紹,歡迎大家關注。本系列文章是基于。 概述 回顧上兩章,我們主要分析了HandlerAdapter的概念、作業以及Spring MVC如何使用的HandlerAdapter組件,本節以及后續幾章,將介紹Spring為我們提供的HandlerAdapter...

    Dionysus_go 評論0 收藏0
  • springboot-jsp打jar問題

    摘要:前情提要最近做了一個項目,項目是結構的,但是在發布生產環境的時候又需要用打成包,但是一開始的默認配置都不成功。壹項目結構貳異常現象使用的為,版本為打成的只包含文件,沒有見資源文件引入。 【前情提要】最近做了一個項目,項目是springboot+jsp結構的,但是在發布生產環境的時候又需要用maven打成jar包,但是一開始的默認配置都不成功。下面的文章就是具體的解決過程。 壹、項目結...

    Luosunce 評論0 收藏0
  • SpringMVC之初體驗--Code-based

    摘要:最后創建了群方便大家交流,可掃描加入,同時也可加我,共同學習共同進步,謝謝 創建項目 創建web項目,使用maven webapp模板進行構建,創建完成后,在pom中引入Spring MVC依賴,如下: org.springframework spring-webmvc 5.0.5.RELEASE javax.servlet ja...

    happyfish 評論0 收藏0
  • Spring MVC之基于java config無xml配置的web應用構建

    摘要:更多相關博文參考前一篇博文講了的方式創建應用,用過的童鞋都知道,早就沒有什么事情了,其實的版本,就已經支持,不用再寫本篇將介紹下,如何利用取代配置本篇博文,建議和上一篇對比看,貼出上一篇地址之基于配置的應用構建構建項目依賴對于依賴 更多spring相關博文參考: http://spring.hhui.top 前一篇博文講了SpringMVC+web.xml的方式創建web應用,用過S...

    chunquedong 評論0 收藏0

發表評論

0條評論

最新活動
閱讀需要支付1元查看
<