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(一个很不错的视图框架)。