DispatcherServlet配置及源码分析
DispatcherServlet是前端控制器,它负责拦截特定类型得请求并分发至对应的Controller。DispatcherServlet和其它Servlet一样,需要在Java配置类或者web.xml
里进行声明和配置映射。反过来,DispatcherServlet也利用Spring配置来寻找组件、视图解析或者异常处理等。
配置DispatcherServlet
利用Java配置类
这种方法可以直接被Spring容器检测到
public class MyWebApplicationInitializer implements WebApplicationInitializer {
@Override
public void onStartup(ServletContext servletCxt) {
// 读取Spring配置类
AnnotationConfigWebApplicationContext ac = new AnnotationConfigWebApplicationContext();
ac.register(AppConfig.class);
ac.refresh();
// 创建并注册DispatcherServlet
DispatcherServlet servlet = new DispatcherServlet(ac);
ServletRegistration.Dynamic registration = servletCxt.addServlet("app", servlet);
registration.setLoadOnStartup(1);
registration.addMapping("/app/*");
}
}
那么这背后发生了什么呢?
第一行AnnotationConfigWebApplicationContext ac = new AnnotationConfigWebApplicationContext();
创建了一个AnnotationConfigWebApplicationContext对象。
可以看到,该类是接口WebApplicationContext的一个实现。
第二行ac.register(AppConfig.class);
字面意思上看,它是对Spring配置类进行一个解析和注册。
进入方法去看,第一行是来一个断言,表示应该至少有一个被注解的类被传进方法。第二行是将这些类添加到这个叫annotatedClasses的LinkedHashSet中,注意,此时还没有真正开始注册,所以方法上面的注释写道,一定要在之后调用refresh()方法;还有由于Set这个数据结构的特点,里面的元素没有重复的。
第三行ac.refresh();
这个refresh()方法是接口ConfigurableApplicationContext的,由于类AnnotationConfigApplicationContext继承了类GenericApplicationContext,GenericApplicationContext又继承了抽象类AbstractApplicationContext,而AbstractApplicationContext实现了接口ConfigurableApplicationContext并对该方法进行实现,所以类AnnotationConfigApplicationContext也有这个方法但没有对其进行重写,而是直接调用。
来看接口ConfigurableApplicationContext中的声明,这个方法的作用就是字面意思——“刷新”。目的是加载或者刷新配置,它会销毁所有已存在的单例,这个方法执行后,只有两种情况发生,一是实例化所有单例;二是没有单例被实例化。同时,该方法还应考虑执行失败的收尾清理工作。
第四行DispatcherServlet servlet = new DispatcherServlet(ac);
通过有参构造,传入一个WebApplicationContext,创建一个DispatcherServlet对象。上面我们提到AnnotationConfigWebApplicationContext是接口WebApplicationContext的一个实现,所以这操作没毛病。构造方法的第一行呢,是调用了它的父类FrameworkServlet(抽象类)的有参构造。
第二行它明显设置了一个flag,为true的时候表示HTTP的Option请求会和其他普通请求一样走常规调度链,就是会走doService()方法
DispatcherServlet类里面有这样一个静态代码块,作用是从属性文件中导入默认的策略实现,并且不接受DIY。
最后三行就是JavaEE的常规操作了,这里不作深入分析。
利用web.xml
<web-app>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/app-context.xml</param-value>
</context-param>
<servlet>
<servlet-name>app</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value></param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>app</servlet-name>
<url-pattern>/app/*</url-pattern>
</servlet-mapping>
</web-app>