注解启动SpringMVC的原理
Web容器在启动的时候,会扫描每个jar包下的
META-INF/services/javax.servlet.ServletContainerInitializer
(SPI机制), 加载这个文件指定的类SpringServletContainerInitializerSpringServletContainerInitializer
使用HandleTypes注解
获取了所有实现了WebApplicationInitializer接口的非抽象非接口类,然后实例化他们,并调用该接口的onStartUp(ServletContext ctx)
方法.
于是Spring就是通过WebApplicationInitializer接口,将DispatcherServlet给注册了, 注册流程:
- AbstractContextLoaderInitializer:
- 创建根容器;createRootApplicationContext();(模版模式,让子类实现)
- AbstractDispatcherServletInitializer:
- 创建一个web的ioc容器;createServletApplicationContext();
- 创建了DispatcherServlet;createDispatcherServlet();
- 将创建的DispatcherServlet添加到ServletContext中;getServletMappings();
- AbstractAnnotationConfigDispatcherServletInitializer:注解方式配置的DispatcherServlet初始化器:
- 创建根容器(主要管理业务bean)createRootApplicationContext()
- 抽象方法:getRootConfigClasses(); 以模版模式的方式,传入根容器的配置类
- 创建web子容器(主要管理web相关bean,如controller)createServletApplicationContext
- 抽象方法:getServletConfigClasses(); 以模版模式的方式,传入web子容器的配置类
- AbstractContextLoaderInitializer:
对(3)做个总结的话,Spring通过WebApplicationInitializer接口做了如下几个事情:
- 创建根容器,管理业务bean
- 创建web子容器,管理web相关bean
- 通过模版模式来配置根容器和子容器
- 将dispatcherServlet注册到ContextServlet中,使其能够生效(因此,在Tomcat初始化前,就已经把DispatcherServlet注册起来了)
接下来就是讨论DispatcherServlet了(这才是SpringMVC的核心,请求分发)
在Tomcat启动进行初始化的时候,会调用
init()
方法,此时会触发DispatcherServlet的初始化,其中最重要的一个是”对HandlerMappings”的初始化!作为Servlet,Tomcat容器会通过调用service方法来决定调用doGet, doPost等方法,在这些方法里面,最终都会收束到
processRequest(req, resp)
方法中.在
processRequets(req, resp)
方法中,会push events,最主要的还是到doService()
方法中(这里也是模版模式,doService由子类实现)造
doService
中,做了一些全局化配置,即将一些之后会使用到的变量加到request中(用setAttribute
方法),使得之后能够使用, 然后最重要的,就是会调用doDispatcher
方法,看名字也能知道,分发(dispatch)的故事,从此开始。
1 | protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception { |
Key Point:
在对servletBean进行初始化的时候,初始化DispatcherServlet的时候,会初始化HandlerMapping(tomcat启动的时候,调用
init
的时候)使用request去到HandlerMappings中去尝试匹配handler( 例如:ControllerMethod,因为实现这种映射的方式不只有@Controller, 还有Controller接口的方法等,因此,这里的handler指待执行的那个方法,包括且不限于ControllerMethod ),这一步主要是在doDispatcher的getHandler里获取,这里同时也会处理Interceptor,最终返回一个HandlerExecutionChain。
1
2
3
4
5
6
7
8
9
10
11
12
13public class HandlerExecutionChain {
...
private final Object handler;
private List<HandlerInterceptor> interceptorList;
private int interceptorIndex = -1;
....
}选择合适的adapter,然后调用HandlerChain,最终返回一个ModelAndView,然后使用合适的Resolver去处理这个ModelAndView
最后,放一张流程图