一、如何在代码中配置DispatcherServlet以及其中的原理
DispatcherServlet是SpringMVC的核心,担任着请求分发的责任。
在SpringMVC中配置DispatcherServlet有两种方式:
1. 在Servlet容器的web.xml文件中配置;
2. 用Java代码将DispatcherServlet配置到Servlet容器中
文本主要讲解一下第二种配置方法
首先直接看在代码中如何配置DispatcherServlet
package com.windcloud.config; import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer; public class FyWebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer { @Override protected Class<?>[] getRootConfigClasses() { return new Class[] { RootConfig.class }; } //指定配置类 @Override protected Class<?>[] getServletConfigClasses() { return new Class[] { WebConfig.class }; } //将DispatcherServlet映射到“/” @Override protected String[] getServletMappings() { return new String[] { "/" }; } }
通过扩展AbstractAnnotationConfigDispatcherServletInitializer抽象类,可以将DispatcherServlet和Spring应用上下文配置到Servlet容器中。其原理如下:
在Servlet3.0的环境中,即如果Servlet容器遵循的是Servlet3.0接口,那么Servlet容器会在类路径中寻找实现javax.servlet.ServletContainerInitializer接口的类,然后用它来配置Servlet容器。
幸运的是Spring已经为我们提供了这个接口的实现类,名为SpringServletContainerInitializer,在这个类中又会查找WebApplicationInitializer接口的实现类,然后将配置的任务交给这个接口的实现类来完成。
从上面的源码中可以看到,在WebApplicationInitializer接口的onStartup方法中实现在servletContext中加载Servlet.
在Spring3.2中引入了WebApplicationInitializer接口的基础实现类(这是一个抽象类),就是AbstractAnnotationConfigDispatcherServletInitializer.但是AbstractAnnotationConfigDispatcherServletInitializer并不是直接实现WebApplicationInitializer接口的,它的实现路径如下:
AbstractAnnotationConfigDispatcherServletInitializer
在AbstractAnnotationConfigDispatcherServletInitializer中,给我们留下了三个抽象方法要求我们去实现:
- AbstractDispatcherServletInitializer 中,这个方法可以将一个或多个路径映射到DispatcherServlet上,如果路径设置为“/”,则所有的请求都会由DispatcherServlet处理。
- protected abstract Class<?>[] getRootConfigClasses();AbstractAnnotationConfigDispatcherServletInitializer中
- protected abstract Class<?>[] getServletConfigClasses();
所以我们需要写一个继承AbstractAnnotationConfigDispatcherServletInitializer的配置类,如开头的FyWebAppInitializer所示。
下面着重解释一下getRootConfigClasses()和getServletConfigClasses()方法。
在解释这两个方法之前,我们需要知道Spring应用上下文的一些基础知识。
Spring中通常由两个应用上下文:
- 一个是DispatcherServlet启动的时候创建的上下文(上下文一)
在创建这个上下文的时候会加载配置文件或配置类中声明的bean,getServletConfigClasses返回的配置类(如案例中的WebConfig类)中配置的bean会在这个时候被加载到该上下文中
- 另一个上下文是由ContextLoaderListener创建的(上下文二)
方法getRootConfigClasses返回的配置类(如案例中的RootConfig类)中配置的bean会被加载到这个上下文中
上面两个上下文的区别是:上下文一中加载的通常是Web组件的bean,如控制器、视图解析器、处理器映射器等。而上下文二中加载的往往是一些中间层和数据层的组件。
其实,在AbstractAnnotationConfigDispatcherServletInitializer中会同时创建DispatcherServlet和ContextLoaderListener.
下面分别给出示例中WebConfig和RootConfig的实现
实现如下:
package com.windcloud.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.ViewResolver; import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer; import org.springframework.web.servlet.config.annotation.EnableWebMvc; import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; import org.springframework.web.servlet.view.InternalResourceViewResolver; @Configuration @EnableWebMvc //启用SpringMVC @ComponentScan("com.windcloud.config") //启用组件扫描 public class WebConfig extends WebMvcConfigurerAdapter { //配置JSP视图解析器 @Bean public ViewResolver viewResolver() { InternalResourceViewResolver resolver = new InternalResourceViewResolver(); resolver.setPrefix("/WEB-INF/views"); resolver.setSuffix(".jsp"); resolver.setExposeContextBeansAsAttributes(true); return resolver; } //配置静态资源的处理 @Override public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) { configurer.enable(); } }
实现如下:
package com.windcloud.config; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.FilterType; import org.springframework.web.servlet.config.annotation.EnableWebMvc; @Configuration @ComponentScan(basePackages = { "com.windcloud.controller" }, excludeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION, value = EnableWebMvc.class)}) public class RootConfig { }
以上就是关于DispatcherServlet在代码中的配置过程。
二、总结
1. 上述的在代码中配置DispatcherServlet只能在支持Servlet3.0及以上版本的服务器中才可以使用,如Tomcat7及以上,如果版本低于Servlet3.0,那只能在web.xml中配置了
2. 配置DispatcherServlet有三个步骤:
- 编写继承了AbstractAnnotationConfigDispatcherServletInitializer类的初始化类,并实现其中的三个抽象方法
- 编写一个配置类(如WebConfig),在该类中配置视图解析器等组件
- 再编写一个配置类(如RootConfig),在该类中配置扫描路径,通过componentScann可以将service层和dao层组件配置到Spring的上下文中(由ContextLoaderListener创建的上下文)