0%

springmvc工作流程

注解启动SpringMVC的原理

  1. Web容器在启动的时候,会扫描每个jar包下的
    META-INF/services/javax.servlet.ServletContainerInitializer(SPI机制), 加载这个文件指定的类SpringServletContainerInitializer

  2. SpringServletContainerInitializer使用HandleTypes注解
    获取了所有实现了WebApplicationInitializer接口的非抽象非接口类,然后实例化他们,并调用该接口的onStartUp(ServletContext ctx)方法.

  1. 于是Spring就是通过WebApplicationInitializer接口,将DispatcherServlet给注册了, 注册流程:

    1. AbstractContextLoaderInitializer:
      • 创建根容器;createRootApplicationContext();(模版模式,让子类实现)
    2. AbstractDispatcherServletInitializer:
      • 创建一个web的ioc容器;createServletApplicationContext();
      • 创建了DispatcherServlet;createDispatcherServlet();
      • 将创建的DispatcherServlet添加到ServletContext中;getServletMappings();
    3. AbstractAnnotationConfigDispatcherServletInitializer:注解方式配置的DispatcherServlet初始化器:
      • 创建根容器(主要管理业务bean)createRootApplicationContext()
      • 抽象方法:getRootConfigClasses(); 以模版模式的方式,传入根容器的配置类
      • 创建web子容器(主要管理web相关bean,如controller)createServletApplicationContext
      • 抽象方法:getServletConfigClasses(); 以模版模式的方式,传入web子容器的配置类
  2. 对(3)做个总结的话,Spring通过WebApplicationInitializer接口做了如下几个事情:

    1. 创建根容器,管理业务bean
    2. 创建web子容器,管理web相关bean
    3. 通过模版模式来配置根容器和子容器
    4. 将dispatcherServlet注册到ContextServlet中,使其能够生效(因此,在Tomcat初始化前,就已经把DispatcherServlet注册起来了)

接下来就是讨论DispatcherServlet了(这才是SpringMVC的核心,请求分发)

  1. 在Tomcat启动进行初始化的时候,会调用init()方法,此时会触发DispatcherServlet的初始化,其中最重要的一个是”对HandlerMappings”的初始化!

  2. 作为Servlet,Tomcat容器会通过调用service方法来决定调用doGet, doPost等方法,在这些方法里面,最终都会收束到processRequest(req, resp)方法中.

  3. processRequets(req, resp)方法中,会push events,最主要的还是到doService()方法中(这里也是模版模式,doService由子类实现)

  4. doService中,做了一些全局化配置,即将一些之后会使用到的变量加到request中(用setAttribute方法),使得之后能够使用, 然后最重要的,就是会调用doDispatcher方法,看名字也能知道,分发(dispatch)的故事,从此开始。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
boolean multipartRequestParsed = false;

WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);

try {
ModelAndView mv = null;
Exception dispatchException = null;

try {
// 1. 检查是否是mutipart的格式(即上传的内容格式是否是二进制的,如图片,音频等...) 如果是的话,就相应的转换下request, 因为毕竟是二进制的内容..
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);

// 2. 下一个要分析的方法,根据request里的信息(如URI,请求方法等)匹配到合适的Handler去执行(其实handler就是Controller中的一个Method),这里返回一个HandlerExecutionChain(就是一个interceptor数组和一个handler,类似aop那样)
mappedHandler = getHandler(processedRequest);

if (mappedHandler == null) {
noHandlerFound(processedRequest, response);
return;
}

// Determine handler adapter for the current request.
// 3. 选择合适的adapter,并使用这个adapter去执行handler
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

// Process last-modified header, if supported by the handler.
String method = request.getMethod();
boolean isGet = "GET".equals(method);
if (isGet || "HEAD".equals(method)) {
long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
if (logger.isDebugEnabled()) {
logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
}
if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
return;
}
}

// 4. 因为是handlerChain,先执行前置interceptor
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}

// Actually invoke the handler.
// 5. 真正的执行handler
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

if (asyncManager.isConcurrentHandlingStarted()) {
return;
}

applyDefaultViewName(processedRequest, mv);
// 6. 因为是handlerChain,执行后置interceptor
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
catch (Exception ex) {
dispatchException = ex;
}
catch (Throwable err) {
// As of 4.3, we're processing Errors thrown from handler methods as well,
// making them available for @ExceptionHandler methods and other scenarios.
dispatchException = new NestedServletException("Handler dispatch failed", err);
}
// 7. 在doDispatch的时候,最终会有2个结果:
// 1. handler顺利执行: 得到ModelAndView
// 2. 执行过程中出现异常.
//
// 而processDispatchResult 做的事情,就是对上面的两个情况的处理,
// 对于ModelAndView,则选出合适的ViewResolver对其进行处理, 得到View后再发给Render进行渲染,最后返回响应结果。
// 若出现异常,都是暂时将异常赋值给dispatchException变量,然后在processDispatchResult方法中统一进行处理

processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
catch (Exception ex) {
triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
}
catch (Throwable err) {
triggerAfterCompletion(processedRequest, response, mappedHandler,
new NestedServletException("Handler processing failed", err));
}
finally {
if (asyncManager.isConcurrentHandlingStarted()) {
// Instead of postHandle and afterCompletion
if (mappedHandler != null) {
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
}
}
else {
// Clean up any resources used by a multipart request.
if (multipartRequestParsed) {
cleanupMultipart(processedRequest);
}
}
}
}
  1. Key Point:

    1. 在对servletBean进行初始化的时候,初始化DispatcherServlet的时候,会初始化HandlerMapping(tomcat启动的时候,调用init的时候)

    2. 使用request去到HandlerMappings中去尝试匹配handler( 例如:ControllerMethod,因为实现这种映射的方式不只有@Controller, 还有Controller接口的方法等,因此,这里的handler指待执行的那个方法,包括且不限于ControllerMethod ),这一步主要是在doDispatcher的getHandler里获取,这里同时也会处理Interceptor,最终返回一个HandlerExecutionChain。

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      public class HandlerExecutionChain {

      ...

      private final Object handler;

      @Nullable
      private List<HandlerInterceptor> interceptorList;

      private int interceptorIndex = -1;

      ....
      }
    3. 选择合适的adapter,然后调用HandlerChain,最终返回一个ModelAndView,然后使用合适的Resolver去处理这个ModelAndView


最后,放一张流程图
pic