Serlvet 3以後,我們可以使用註解來配置Servlet,對於像Spring這類的框架來說是一個很好的適應。Spring也對此特性加入了很多的新功能。本文就將簡單的對之前的xml配置轉換爲java代碼的配置。代碼配置讓程序員們覺得更加具有流程化,不像配置很多代碼程序員們都不願意look into。
接下來,進行替換我們之前的web.xml和spring-mvc.xml的配置。也就是在你的web工程裏面看不到這兩個配置文件了。(可能有的童鞋會說,這樣配置可能對以後的修改不方便,無法達到只修改配置文件就切換某些環境。其實不是,零配置文件只是修改了類定義的配置,並沒有修改之前配置文件的靈活性。我想無論誰也不會在之前的web.xml中去修改某個servlet的配置吧。況且這些所謂的配置文件靈活性,只是針對某個值,我們可以寫在我們的properties文件裏面,而且Spring對這類配置文件有很好的支持,而且使用很方便,有興趣的童鞋可以去search一下。所以請打消這個配置不靈活的念頭)。
切入正題,首先我們要替換web.xml。在Spring MVC中配置DispatchServlet,該類是 Spring MVC的核心類(該類具體作用請參考Spring MVC相關文檔)。也就是在容器啓動的時候就要初始化該類,並且配置相應的參數。
之前我們的web.xml中對DispatchServlet的配置如下:
<servlet> <servlet-name>dispatcher</servlet-name> <servlet-class> org.springframework.web.servlet.DispatcherServlet </servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/spring/dispatcher-config.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>dispatcher</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping>
Servlet3 以後,支持動態的添加Servlet配置,請參考ServletContext.addServlet方法。因此我們可以使用Spring MVC提供的AbstractDispatcherServletInitializer類。該類是的類關係是AbstractDispatcherServletInitializer -> WebApplicationInitializer,(點擊查看WebApplicationInitializer詳解)在AbstractDispatcherServletInitializer中重寫onStartup方法,調用ServletContext.addServlet來實現註冊該servlet。通過查看AbstractDispatcherServletInitializer源碼,發現只需用重寫他的三個方法既可以完成對DispatchServlet的註冊。詳細請看示例代碼:
public class WebInitialConfiguration extends AbstractDispatcherServletInitializer { @Override protected WebApplicationContext createServletApplicationContext() { AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext(); // scan the class under the demo.config package with @Configuration annotation // You can add it by manually such as: // context.register(Class<?>... annotatedClasses) -> context.register(WebMVCConfiguration.class, AppConfig.class, ....) // This configuration like: // <init-param> // <param-name>contextConfigLocation</param-name> // <param-value>/WEB-INF/spring/dispatcher-config.xml</param-value> // </init-param> // all the configuration classes are in the same package, so use the getClass() method to get the package. Here the package name is com.sample.config context.scan(ClassUtils.getPackageName(getClass())); return context; } @Override protected String[] getServletMappings() { // Set the URL mapping return new String[] { "/" }; } @Override protected WebApplicationContext createRootApplicationContext() { return null; } }
細心的童鞋可以查看一下AbstractDispatcherServletInitializer的源碼,會發現在代碼中調用了ContextServlet.addServlet方法的:
DispatcherServlet dispatcherServlet = new DispatcherServlet(servletAppContext); ServletRegistration.Dynamic registration = servletContext.addServlet(servletName, dispatcherServlet);
這時我們啓動servlet3容器(本文使用tomcat7), 你會看到如下啓動信息:
INFO: Initializing Spring FrameworkServlet 'dispatcher' INFO: FrameworkServlet 'dispatcher': initialization started Mapped URL path [/**] onto handler of type [class org.springframework.web.servlet.resource.DefaultServletHttpRequestHandler] INFO: FrameworkServlet 'dispatcher': initialization completed in 843 ms
接下,替換spring-mvc.xml,在該配置中,我們只需用去配置很少幾部分就可以藉助Spring提供的接口完成對所有controller的註冊和對視圖解析的配置。
xml配置如下:
<context:component-scan base-package="com.sample.controller"/> <context:annotation-config/> <!-- This tag registers the DefaultAnnotationHandlerMapping and AnnotationMethodHandlerAdapter beans that are required for Spring MVC --> <mvc:annotation-driven/> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <propertyname="prefix"value="/WEB-INF/pages/"/> <propertyname="suffix"value=".jsp"/> </bean> <!-- This tag allows for mapping the DispatcherServlet to "/" --> <mvc:default-servlet-handler/>
首先,在Spring MVC中,我們可以使用@Configuration來進行Spring的配置,我們剛纔也有需要去掃描這一類的配置類。接下來就是需要開啓Spring MVC的具體配置。使用@EnableWebMvc,該註解等同於<mvc:annotation-driven/>,該標籤具體的意思請看xml配置中對該標籤的解釋。
接下來我們要去掃描我們的controller,即有@Controller的類。因此我們使用@ComponentScan進行掃描,該註解等同於<context:componet-scan>。
Spring MVC需要對視圖的解析進行一次定義,因此我們需要在該類中實例化一個ResourceViewResolver,該類的定義視具體需要而定。
具體的代碼如下:
@Configuration // <mvc:annotation-driven/> @EnableWebMvc @ComponentScan(basePackages={"com.sample.controller"}) public class WebMVCConfiguration extends WebMvcConfigurerAdapter { // equals: <mvc:default-servlet-handler/> @Override public void configureDefaultServletHandling( DefaultServletHandlerConfigurer configurer) { configurer.enable(); } // add the resolver @Bean public InternalResourceViewResolver internalResourceViewResolver() { InternalResourceViewResolver resolver = new InternalResourceViewResolver(); resolver.setPrefix("/WEB-INF/pages/"); resolver.setSuffix(".jsp"); return resolver; } }
此時我們添加我們的controller到com.sample.controller包下,然後定義我們的requestmapping,再次啓動server,你會看到會增加之前檢測到的controller的信息。
INFO: Mapped "{[/test],methods=[GET],params=[],headers=[],consumes=[],produces=[],custom=[]}" onto public java.lang.String com.sample.controller.TestController.test()
至此,簡單的替換已經完成,更多的功能會在後續的文章中繼續加入,如:spring-security, thymeleaf(一個很不錯的視圖框架)。