Spring 源码解析一:SpringMVC 的加载机制

x33g5p2x  于2022-02-11 发布在 Spring  
字(32.8k)|赞(0)|评价(0)|浏览(607)

1. spring-framework 包含的模块

在解析 SpringMVC 的加载机制之前,先来看看官方 spring-framework 包含有哪些模块,各有什么用。

spring-framework 官方仓库

  • spring-jclspring 框架的通用日志处理
  • spring-corespring 框架的核心机制模块,包括 Java 字节码的操作处理与动态生成、依赖注入机制(也叫控制反转)、工具类库、
    注解操作、编码处理与数据转换、资源加载与处理、环境加载机制等
  • spring-beansspring bean 的定义、加载、解析、编辑等
  • spring-contextspring 框架的上下文环境,包括应用缓存、应用事件、应用配置、核心注解定义与处理、资源加载、异步与定时任务、数据验证与格式化等
  • spring-aop:面向切面编程的封装与处理
  • spring-aspects:使用 AspectJ 作为底层实现的面向切面编程
  • spring-tx:事务的封装与处理
  • spring-jdbc:数据库链接的封装与处理
  • spring-context-indexer:对注解 @Indexed 的支持
  • spring-context-support:对一些第三方库的可选支持,如 ehcache, javamail, quartz, freemarker
  • spring-oxm:对 O/X Mapper 的封装
  • spring-messaging:对 http, rsocket, simp 等消息传递协议的封装
  • spring-jms:对 JMS(Java 消息服务) 的封装
  • spring-expressionSpring Expression Language (SpEL) Spring 表达式语言的实现
  • spring-r2dbc:对 R2DBC 的封装
  • spring-orm:对 JPAhibernate 的封装
  • spring-web:提供了 Web 框架的基础结构与技术,如 Http 的调用、过滤、处理等
  • spring-webmvc:Web MVC 架构的实现,包括 Servlet 容器初始化、路由映射、视图渲染、响应处理等
  • spring-websocket:对 WebSocket 的支持
  • spring-webflux:Reactive Web 框架的实现,与 spring-webmvc 相对

SpringMVC 框架的核心模块主要是:spring-corespring-beansspring-contextspring-webspring-webmvc,后面也主要从这几个模块来解析。

1.1. spring-core

spring-core 的核心功能有几点需要在这里简单介绍一下:

  1. spring-core 有强大的 Java 字节码操作处理功能与动态生成功能,这是面向切面编程、数据类型转换、SpEL 表达式等功能的基础
  2. spring-core 提供了依赖注入机制,这是 spring bean 加载的基础,也是我们可以使用 @Autowired 自动装载对象等功能的底层机制
  3. spring-core 提供了环境加载的机制,所以我们可以使用 application-dev.yml, application-test.yml, application-prod.yml, ...
    来根据环境加载不同的配置
  4. spring-core 提供了一个类似 Java SPI 的的扩展机制,可以自动实例化其他包指定的类,spring-boot, spring-cloud 都依赖这个机制自动加载资源。
    META-INF/spring.factories 文件中定义需要自动加载的类,详细介绍可以参考 Spring Factories

1.2. spring-beans

Spring bean 的加载与扩展机制有几点需要在这里简单介绍一下:

  1. Spring bean 的定义主要是两种:基于注解的定义、基于 XML 文件的定义
  2. spring-beans 提供了基于 XML 配置的、第三方对 bean 的命令空间扩展机制,主要是在
    META-INF/spring.handlers, META-INF/spring.schemas 文件中定义需要扩展的命令空间,
    比如 <dubbo:application name="name"/>, <dubbo:registry address="address"/>
  3. 基于注解的自定义扩展,需要依赖 spring-boot 的扩展加载机制

1.3. spring-context

spring-context 是应用的核心处理部分,包括:

  • 应用缓存
  • 应用事件
  • 应用配置
  • 核心注解定义与处理
  • 资源加载
  • 异步与定时任务
  • 数据验证与格式化

等,@ComponentScan, @Profile, @Conditional, @Bean, @Async, @Controller, @Service, @Component, @Validated 等这类框架核心注解便是在这里定义的。

1.4. spring-web

spring-web 是 Http 的核心处理部分,主要包含:

  • 核心 Http 请求与响应处理(包括 Cookie、缓存、多媒体等)
  • Http 请求与响应编解码与转换(包括 Json、XML、ProtoBuf 等)
  • Reactive Web 框架基础处理
  • 调用客户端(如 RestTemplate
  • Servlet 上下文环境
  • 请求过滤器
  • Multipart 文件上传处理

等,@RequestMapping, @RequestParam, @PathVariable, @ResponseBody, @RestController 等这类 Web 核心注解便是在这里定义的。

1.5. spring-webmvc

spring-webmvc 依赖于 spring-web,主要功能包括:

  • Servlet 容器初始化
  • 路由映射
  • 视图渲染
  • 响应处理

等,如果不使用 Spring MVC ,但想要借助其它 Spring 支持的 web 相关技术的优势,那么只需依赖 spring-web,如 spring-webflux

1.6. spring-webflux

spring-webfluxspring-webmvc 相对应,webmvc 是同步阻塞框架,而 webflux 是异步非阻塞框架,
是 Spring Framework 5.0 中引入的新的响应式 web 框架。

参考:Spring WebFlux 入门
Spring WebFlux :: Spring Docs

2. 一个简单的 spring-webmvc 项目配置

WEB-INF/web.xml 文件中如下配置:

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  3. xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
  4. xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
  5. version="3.0">
  6. <display-name>springMVC</display-name>
  7. <!-- 部署 DispatcherServlet -->
  8. <servlet>
  9. <servlet-name>springmvc</servlet-name>
  10. <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
  11. <init-param>
  12. <param-name>contextConfigLocation</param-name>
  13. <param-value>classpath:springmvc-servlet.xml</param-value>
  14. </init-param>
  15. <!-- 容器再启动时立即加载servlet -->
  16. <load-on-startup>1</load-on-startup>
  17. </servlet>
  18. <servlet-mapping>
  19. <servlet-name>springmvc</servlet-name>
  20. <!-- 处理所有URL -->
  21. <url-pattern>/</url-pattern>
  22. </servlet-mapping>
  23. <!-- 定义应用程序监听器 -->
  24. <listener>
  25. <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  26. </listener>
  27. </web-app>

这里有两个入口类:

这两个类分别定义在 spring-webmvcspring-web 中,下面对他们一一进行解析。

3. DispatcherServlet

先来看看 DispatcherServlet 的继承关系:

  1. - javax.servlet.Servlet
  2. - javax.servlet.GenericServlet
  3. - javax.servlet.http.HttpServlet
  4. - HttpServletBean
  5. - FrameworkServlet
  6. - DispatcherServlet

3.1. javax.servlet.Servlet

首先看看 javax.servlet.Servlet

javax.servlet.Servlet 主要定义了 2 个方法:

  • init:初始化 Servlet,只执行一次
  • service:响应请求,每次 http 请求都会调用这个方法
  1. public interface Servlet {
  2. // 初始化 Servlet,只执行一次
  3. public void init(ServletConfig config) throws ServletException;
  4. // 响应请求,每次http请求都会调用这个方法
  5. public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException;
  6. // 销毁 Servlet
  7. public void destroy();
  8. }

3.2. javax.servlet.GenericServlet

再来看看 javax.servlet.GenericServlet

javax.servlet.GenericServlet 主要是重载了 init 方法

  1. public abstract class GenericServlet implements Servlet, ServletConfig, java.io.Serializable {
  2. public GenericServlet() {}
  3. // 添加配置初始化
  4. public void init(ServletConfig config) throws ServletException {
  5. this.config = config;
  6. this.init();
  7. }
  8. // 保留无参初始化
  9. public void init() throws ServletException {}
  10. // 留给子类实现
  11. public abstract void service(ServletRequest req, ServletResponse res) throws ServletException, IOException;
  12. }

3.3. javax.servlet.http.HttpServlet

再来看看 javax.servlet.http.HttpServlet

javax.servlet.http.HttpServlet 主要是重载了 service 方法,并扩展了 7 个方法:

  • doGet:处理 GET 请求,只输入错误信息,未实现
  • doHead:处理 HEAD 请求,只输入错误信息,未实现
  • doPost:处理 POST 请求,只输入错误信息,未实现
  • doPut:处理 PUT 请求,只输入错误信息,未实现
  • doDelete:处理 DELETE 请求,只输入错误信息,未实现
  • doOptions:处理 OPTIONS 请求
  • doTrace:处理 TRACE 请求
  1. public abstract class HttpServlet extends GenericServlet {
  2. private static final String METHOD_DELETE = "DELETE";
  3. private static final String METHOD_HEAD = "HEAD";
  4. private static final String METHOD_GET = "GET";
  5. private static final String METHOD_OPTIONS = "OPTIONS";
  6. private static final String METHOD_POST = "POST";
  7. private static final String METHOD_PUT = "PUT";
  8. private static final String METHOD_TRACE = "TRACE";
  9. protected void doGet(HttpServletRequest req, HttpServletResponse resp)
  10. throws ServletException, IOException
  11. {
  12. String protocol = req.getProtocol();
  13. String msg = lStrings.getString("http.method_get_not_supported");
  14. if (protocol.endsWith("1.1")) {
  15. resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg);
  16. } else {
  17. resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg);
  18. }
  19. }
  20. protected void doHead(HttpServletRequest req, HttpServletResponse resp)
  21. throws ServletException, IOException
  22. {
  23. NoBodyResponse response = new NoBodyResponse(resp);
  24. // 调用 doGet,但body设为空body
  25. doGet(req, response);
  26. response.setContentLength();
  27. }
  28. protected void doPost(HttpServletRequest req, HttpServletResponse resp)
  29. throws ServletException, IOException
  30. {
  31. // ... 代码省略
  32. }
  33. protected void doPut(HttpServletRequest req, HttpServletResponse resp)
  34. throws ServletException, IOException
  35. {
  36. // ... 代码省略
  37. }
  38. protected void doDelete(HttpServletRequest req, HttpServletResponse resp)
  39. throws ServletException, IOException
  40. {
  41. // ... 代码省略
  42. }
  43. protected void doOptions(HttpServletRequest req, HttpServletResponse resp)
  44. throws ServletException, IOException
  45. {
  46. // ... 代码省略
  47. }
  48. protected void doTrace(HttpServletRequest req, HttpServletResponse resp)
  49. throws ServletException, IOException
  50. {
  51. // ... 代码省略
  52. }
  53. // 实现了GET, HEAD, POST PUT, DELETE, OPTIONS, TRACE七个Http方法
  54. protected void service(HttpServletRequest req, HttpServletResponse resp)
  55. throws ServletException, IOException
  56. {
  57. String method = req.getMethod();
  58. if (method.equals(METHOD_GET)) {
  59. // ... 代码省略
  60. doGet(req, resp);
  61. // ... 代码省略
  62. } else if (method.equals(METHOD_HEAD)) {
  63. long lastModified = getLastModified(req);
  64. maybeSetLastModified(resp, lastModified);
  65. doHead(req, resp);
  66. } else if (method.equals(METHOD_POST)) {
  67. doPost(req, resp);
  68. } else if (method.equals(METHOD_PUT)) {
  69. doPut(req, resp);
  70. } else if (method.equals(METHOD_DELETE)) {
  71. doDelete(req, resp);
  72. } else if (method.equals(METHOD_OPTIONS)) {
  73. doOptions(req,resp);
  74. } else if (method.equals(METHOD_TRACE)) {
  75. doTrace(req,resp);
  76. } else {
  77. String errMsg = lStrings.getString("http.method_not_implemented");
  78. Object[] errArgs = new Object[1];
  79. errArgs[0] = method;
  80. errMsg = MessageFormat.format(errMsg, errArgs);
  81. resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg);
  82. }
  83. }
  84. // 把 Servlet 转化为 HttpServlet
  85. @Override
  86. public void service(ServletRequest req, ServletResponse res)
  87. throws ServletException, IOException
  88. {
  89. HttpServletRequest request;
  90. HttpServletResponse response;
  91. if (!(req instanceof HttpServletRequest &&
  92. res instanceof HttpServletResponse)) {
  93. throw new ServletException("non-HTTP request or response");
  94. }
  95. request = (HttpServletRequest) req;
  96. response = (HttpServletResponse) res;
  97. service(request, response);
  98. }
  99. }

3.4. HttpServletBean

再来看看 HttpServletBean

HttpServletBean 主要是重载了 init 方法,并扩展了 2 个方法:

  • initBeanWrapper:初始化由 Servlet Config 定义的 Java Bean,由子类实现,默认不实现
  • initServletBean:初始化 Servlet bean,由子类实现
  1. public abstract class HttpServletBean extends HttpServlet implements EnvironmentCapable, EnvironmentAware {
  2. // 初始化
  3. @Override
  4. public final void init() throws ServletException {
  5. // 把Servlet配置参数设置到bean属性中
  6. PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties);
  7. if (!pvs.isEmpty()) {
  8. try {
  9. BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);
  10. ResourceLoader resourceLoader = new ServletContextResourceLoader(getServletContext());
  11. bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, getEnvironment()));
  12. initBeanWrapper(bw);
  13. bw.setPropertyValues(pvs, true);
  14. }
  15. catch (BeansException ex) {
  16. if (logger.isErrorEnabled()) {
  17. logger.error("Failed to set bean properties on servlet '" + getServletName() + "'", ex);
  18. }
  19. throw ex;
  20. }
  21. }
  22. // 初始化Servlet bean
  23. initServletBean();
  24. }
  25. // 初始化由Servlet Config定义的Java Bean,由子类实现,默认不实现
  26. protected void initBeanWrapper(BeanWrapper bw) throws BeansException {
  27. }
  28. // 初始化Servlet bean,由子类实现
  29. protected void initServletBean() throws ServletException {
  30. }
  31. }

3.5. FrameworkServlet

再来看看 FrameworkServlet

FrameworkServlet 是框架的核心 Servlet,主要是重载了 initServletBean 方法,并扩展了 2 个方法:

  • initFrameworkServlet:初始化框架 Servlet,由子类实现,默认不实现
  • onRefresh:刷新上下文数据,由子类实现

重载了 service, doGet, doPost, doPut, doDelete, doOptions, doTrace 方法,并扩展了 1 个方法:

  • doService:处理响应请求

3.5.1. FrameworkServlet.initServletBean

父类 HttpServletBean 初始化后,留下两个钩子 initBeanWrapper, initServletBeaninitBeanWrapper 默认并不实现,
所以来看看 initServletBean 钩子的实现:FrameworkServlet.initServletBean

  1. public abstract class FrameworkServlet extends HttpServletBean implements ApplicationContextAware {
  2. @Override
  3. protected final void initServletBean() throws ServletException {
  4. // ... 代码省略
  5. try {
  6. // 初始化Web应用上下文
  7. this.webApplicationContext = initWebApplicationContext();
  8. // 初始化Web框架Servlet
  9. initFrameworkServlet();
  10. }
  11. catch (ServletException | RuntimeException ex) {
  12. logger.error("Context initialization failed", ex);
  13. throw ex;
  14. }
  15. // ... 代码省略
  16. }
  17. // 初始化框架Servlet,由子类实现,默认不实现
  18. protected void initFrameworkServlet() throws ServletException {}
  19. }

再来看看 FrameworkServlet.initWebApplicationContext

  1. public abstract class FrameworkServlet extends HttpServletBean implements ApplicationContextAware {
  2. protected WebApplicationContext initWebApplicationContext() {
  3. // 获取应用根上下文
  4. WebApplicationContext rootContext =
  5. WebApplicationContextUtils.getWebApplicationContext(getServletContext());
  6. WebApplicationContext wac = null;
  7. if (this.webApplicationContext != null) {
  8. // 对webApplicationContext进行配置
  9. wac = this.webApplicationContext;
  10. if (wac instanceof ConfigurableWebApplicationContext) {
  11. ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac;
  12. // 未激活
  13. if (!cwac.isActive()) {
  14. if (cwac.getParent() == null) {
  15. cwac.setParent(rootContext);
  16. }
  17. // 配置并刷新应用上下文
  18. configureAndRefreshWebApplicationContext(cwac);
  19. }
  20. }
  21. }
  22. if (wac == null) {
  23. // 如果没有,则在ServletContext中查找是否注册过
  24. wac = findWebApplicationContext();
  25. }
  26. if (wac == null) {
  27. // 如果任然没有,则以rootContext为父上下文创建一个新的上下文
  28. // 并调用 configureAndRefreshWebApplicationContext(cwac) 配置并刷新新的上下文
  29. // 默认使用 XmlWebApplicationContext(基于XML加载)作为应用上下文
  30. wac = createWebApplicationContext(rootContext);
  31. }
  32. if (!this.refreshEventReceived) {
  33. // 重载上下文数据
  34. synchronized (this.onRefreshMonitor) {
  35. onRefresh(wac);
  36. }
  37. }
  38. if (this.publishContext) {
  39. // 把上下文注册到ServletContext中
  40. String attrName = getServletContextAttributeName();
  41. getServletContext().setAttribute(attrName, wac);
  42. }
  43. return wac;
  44. }
  45. // 以parent为父上下文创建一个新的上下文
  46. // 并调用 configureAndRefreshWebApplicationContext(cwac) 配置并刷新新的上下文
  47. // 默认使用 XmlWebApplicationContext(基于XML加载)作为应用上下文
  48. protected WebApplicationContext createWebApplicationContext(@Nullable ApplicationContext parent) {
  49. // 这里默认使用 XmlWebApplicationContext(基于XML加载)
  50. Class<?> contextClass = getContextClass();
  51. ConfigurableWebApplicationContext wac =
  52. (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);
  53. wac.setEnvironment(getEnvironment());
  54. wac.setParent(parent);
  55. String configLocation = getContextConfigLocation();
  56. if (configLocation != null) {
  57. wac.setConfigLocation(configLocation);
  58. }
  59. configureAndRefreshWebApplicationContext(wac);
  60. return wac;
  61. }
  62. }

这其中有两个方法需要深入解析:configureAndRefreshWebApplicationContext, onRefresh

再来看看 FrameworkServlet.configureAndRefreshWebApplicationContext

  1. public abstract class FrameworkServlet extends HttpServletBean implements ApplicationContextAware {
  2. protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac) {
  3. // ... 代码省略
  4. // 设置ServletContext
  5. wac.setServletContext(getServletContext());
  6. // 设置ServletConfig
  7. wac.setServletConfig(getServletConfig());
  8. wac.setNamespace(getNamespace());
  9. // 添加应用事件监听器,应用事件会触发当前对象的onApplicationEvent方法
  10. // 进一步,会调用当前对象的onRefresh方法,刷新上下文数据
  11. wac.addApplicationListener(new SourceFilteringListener(wac, new ContextRefreshListener()));
  12. // ... 代码省略
  13. // 初始化一些需要初始加载的类,调用这些类的initialize方法
  14. applyInitializers(wac);
  15. // 应用上下文刷新
  16. wac.refresh();
  17. }
  18. // 应用事件会触发此方法,然后调用当前对象的onRefresh方法,刷新上下文数据
  19. public void onApplicationEvent(ContextRefreshedEvent event) {
  20. this.refreshEventReceived = true;
  21. synchronized (this.onRefreshMonitor) {
  22. onRefresh(event.getApplicationContext());
  23. }
  24. }
  25. }

再来看看 FrameworkServlet.onRefresh

  1. public abstract class FrameworkServlet extends HttpServletBean implements ApplicationContextAware {
  2. protected void onRefresh(ApplicationContext context) {
  3. // 由子类来实现
  4. }
  5. }

3.5.2. FrameworkServlet.service

再来看看 FrameworkServlet.service

  1. public abstract class FrameworkServlet extends HttpServletBean implements ApplicationContextAware {
  2. @Override
  3. protected void service(HttpServletRequest request, HttpServletResponse response)
  4. throws ServletException, IOException {
  5. HttpMethod httpMethod = HttpMethod.resolve(request.getMethod());
  6. // 如果Http方法是Patch或没有,扩展处理
  7. if (httpMethod == HttpMethod.PATCH || httpMethod == null) {
  8. processRequest(request, response);
  9. }
  10. else {
  11. super.service(request, response);
  12. }
  13. }
  14. @Override
  15. protected final void doGet(HttpServletRequest request, HttpServletResponse response)
  16. throws ServletException, IOException {
  17. // 扩展处理
  18. processRequest(request, response);
  19. }
  20. @Override
  21. protected final void doPost(HttpServletRequest request, HttpServletResponse response)
  22. throws ServletException, IOException {
  23. // 扩展处理
  24. processRequest(request, response);
  25. }
  26. @Override
  27. protected final void doPut(HttpServletRequest request, HttpServletResponse response)
  28. throws ServletException, IOException {
  29. // 扩展处理
  30. processRequest(request, response);
  31. }
  32. @Override
  33. protected final void doDelete(HttpServletRequest request, HttpServletResponse response)
  34. throws ServletException, IOException {
  35. // 扩展处理
  36. processRequest(request, response);
  37. }
  38. @Override
  39. protected void doOptions(HttpServletRequest request, HttpServletResponse response)
  40. throws ServletException, IOException {
  41. if (this.dispatchOptionsRequest || CorsUtils.isPreFlightRequest(request)) {
  42. // 扩展处理
  43. processRequest(request, response);
  44. if (response.containsHeader("Allow")) {
  45. return;
  46. }
  47. }
  48. // ... 代码省略
  49. }
  50. @Override
  51. protected void doTrace(HttpServletRequest request, HttpServletResponse response)
  52. throws ServletException, IOException {
  53. if (this.dispatchTraceRequest) {
  54. // 扩展处理
  55. processRequest(request, response);
  56. if ("message/http".equals(response.getContentType())) {
  57. return;
  58. }
  59. }
  60. super.doTrace(request, response);
  61. }
  62. }

再来看看扩展处理方法 FrameworkServlet.processRequest

  1. public abstract class FrameworkServlet extends HttpServletBean implements ApplicationContextAware {
  2. protected final void processRequest(HttpServletRequest request, HttpServletResponse response)
  3. throws ServletException, IOException {
  4. // ... 代码省略
  5. // 记录请求属性与上下文环境,请求处理完后派发事件
  6. LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();
  7. LocaleContext localeContext = buildLocaleContext(request);
  8. RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();
  9. ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes);
  10. WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
  11. asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor());
  12. initContextHolders(request, localeContext, requestAttributes);
  13. try {
  14. doService(request, response);
  15. }
  16. // ... 代码省略
  17. finally {
  18. resetContextHolders(request, previousLocaleContext, previousAttributes);
  19. if (requestAttributes != null) {
  20. requestAttributes.requestCompleted();
  21. }
  22. logResult(request, response, failureCause, asyncManager);
  23. publishRequestHandledEvent(request, response, startTime, failureCause);
  24. }
  25. }
  26. // 由子类来实现
  27. protected abstract void doService(HttpServletRequest request, HttpServletResponse response)
  28. throws Exception;
  29. }

3.6. DispatcherServlet

DispatcherServlet 主要扩展了 2 个方法:onRefreshdoService,所以来看看 DispatcherServlet
是如何实现的

3.6.1. DispatcherServlet.onRefresh

DispatcherServlet.onRefresh

  1. public class DispatcherServlet extends FrameworkServlet {
  2. @Override
  3. protected void onRefresh(ApplicationContext context) {
  4. initStrategies(context);
  5. }
  6. protected void initStrategies(ApplicationContext context) {
  7. // 初始化Multipart文件上传处理
  8. initMultipartResolver(context);
  9. // 初始化本地化处理
  10. initLocaleResolver(context);
  11. // 初始化主题处理
  12. initThemeResolver(context);
  13. // 初始化处理器映射
  14. initHandlerMappings(context);
  15. // 初始化处理器适配
  16. initHandlerAdapters(context);
  17. // 初始化处理器异常
  18. initHandlerExceptionResolvers(context);
  19. // 初始化视图查找处理
  20. initRequestToViewNameTranslator(context);
  21. // 初始化视图解析处理
  22. initViewResolvers(context);
  23. // 初始化内存暂存session数据管理器
  24. initFlashMapManager(context);
  25. }
  26. private void initMultipartResolver(ApplicationContext context) {
  27. try {
  28. // 获取bean
  29. this.multipartResolver = context.getBean(MULTIPART_RESOLVER_BEAN_NAME, MultipartResolver.class);
  30. // ... 代码省略
  31. }
  32. catch (NoSuchBeanDefinitionException ex) {
  33. // ... 代码省略
  34. }
  35. }
  36. private void initLocaleResolver(ApplicationContext context) {
  37. try {
  38. // 获取bean
  39. this.localeResolver = context.getBean(LOCALE_RESOLVER_BEAN_NAME, LocaleResolver.class);
  40. // ... 代码省略
  41. }
  42. catch (NoSuchBeanDefinitionException ex) {
  43. // ... 代码省略
  44. }
  45. }
  46. private void initThemeResolver(ApplicationContext context) {
  47. try {
  48. // 获取bean
  49. this.themeResolver = context.getBean(THEME_RESOLVER_BEAN_NAME, ThemeResolver.class);
  50. // ... 代码省略
  51. }
  52. catch (NoSuchBeanDefinitionException ex) {
  53. // ... 代码省略
  54. }
  55. }
  56. private void initFlashMapManager(ApplicationContext context) {
  57. try {
  58. // 获取bean
  59. this.flashMapManager = context.getBean(FLASH_MAP_MANAGER_BEAN_NAME, FlashMapManager.class);
  60. }
  61. catch (NoSuchBeanDefinitionException ex) {
  62. // 没有bean,则获取默认策略
  63. this.flashMapManager = getDefaultStrategy(context, FlashMapManager.class);
  64. }
  65. }
  66. }
3.6.1.1. DispatcherServlet.initHandlerMappings

DispatcherServlet.initHandlerMappings

  1. public class DispatcherServlet extends FrameworkServlet {
  2. private void initHandlerMappings(ApplicationContext context) {
  3. this.handlerMappings = null;
  4. // 默认是探测所有的HandlerMapping,包括父上下文
  5. if (this.detectAllHandlerMappings) {
  6. Map<String, HandlerMapping> matchingBeans =
  7. BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
  8. if (!matchingBeans.isEmpty()) {
  9. this.handlerMappings = new ArrayList<>(matchingBeans.values());
  10. AnnotationAwareOrderComparator.sort(this.handlerMappings);
  11. }
  12. }
  13. else {
  14. // 否则直接获取bean
  15. try {
  16. HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class);
  17. this.handlerMappings = Collections.singletonList(hm);
  18. }
  19. catch (NoSuchBeanDefinitionException ex) {}
  20. }
  21. // 如果以上两种都没有定义,则获取默认的处理策略
  22. if (this.handlerMappings == null) {
  23. this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
  24. }
  25. // ... 代码省略
  26. }
  27. // 获取默认的处理策略
  28. protected <T> List<T> getDefaultStrategies(ApplicationContext context, Class<T> strategyInterface) {
  29. // 尝试从DispatcherServlet.properties文件中加载
  30. if (defaultStrategies == null) {
  31. try {
  32. ClassPathResource resource = new ClassPathResource(DEFAULT_STRATEGIES_PATH, DispatcherServlet.class);
  33. defaultStrategies = PropertiesLoaderUtils.loadProperties(resource);
  34. }
  35. catch (IOException ex) {
  36. throw new IllegalStateException("Could not load '" + DEFAULT_STRATEGIES_PATH + "': " + ex.getMessage());
  37. }
  38. }
  39. String key = strategyInterface.getName();
  40. String value = defaultStrategies.getProperty(key);
  41. if (value != null) {
  42. String[] classNames = StringUtils.commaDelimitedListToStringArray(value);
  43. List<T> strategies = new ArrayList<>(classNames.length);
  44. for (String className : classNames) {
  45. try {
  46. Class<?> clazz = ClassUtils.forName(className, DispatcherServlet.class.getClassLoader());
  47. // 创建bean
  48. Object strategy = createDefaultStrategy(context, clazz);
  49. // 装载到 strategies 中
  50. strategies.add((T) strategy);
  51. }
  52. catch (ClassNotFoundException ex) {
  53. // ... 代码省略
  54. }
  55. catch (LinkageError err) {
  56. // ... 代码省略
  57. }
  58. }
  59. return strategies;
  60. }
  61. else {
  62. return Collections.emptyList();
  63. }
  64. }
  65. // 创建bean
  66. protected Object createDefaultStrategy(ApplicationContext context, Class<?> clazz) {
  67. return context.getAutowireCapableBeanFactory().createBean(clazz);
  68. }
  69. }

DispatcherServlet.properties
文件(开发者不能自定义覆盖)如下:

  1. org.springframework.web.servlet.LocaleResolver=org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver
  2. org.springframework.web.servlet.ThemeResolver=org.springframework.web.servlet.theme.FixedThemeResolver
  3. org.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,\
  4. org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping,\
  5. org.springframework.web.servlet.function.support.RouterFunctionMapping
  6. org.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,\
  7. org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,\
  8. org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter,\
  9. org.springframework.web.servlet.function.support.HandlerFunctionAdapter
  10. org.springframework.web.servlet.HandlerExceptionResolver=org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver,\
  11. org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver,\
  12. org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver
  13. org.springframework.web.servlet.RequestToViewNameTranslator=org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator
  14. org.springframework.web.servlet.ViewResolver=org.springframework.web.servlet.view.InternalResourceViewResolver
  15. org.springframework.web.servlet.FlashMapManager=org.springframework.web.servlet.support.SessionFlashMapManager

DispatcherServlet.properties 文件中指明:

3.6.1.2. DispatcherServlet.initHandlerAdapters

DispatcherServlet.initHandlerAdapters

  1. public class DispatcherServlet extends FrameworkServlet {
  2. private void initHandlerAdapters(ApplicationContext context) {
  3. this.handlerAdapters = null;
  4. // 默认是探测所有的HandlerAdapter,包括父上下文
  5. if (this.detectAllHandlerAdapters) {
  6. Map<String, HandlerAdapter> matchingBeans =
  7. BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerAdapter.class, true, false);
  8. if (!matchingBeans.isEmpty()) {
  9. this.handlerAdapters = new ArrayList<>(matchingBeans.values());
  10. AnnotationAwareOrderComparator.sort(this.handlerAdapters);
  11. }
  12. }
  13. else {
  14. // 否则直接获取bean
  15. try {
  16. HandlerAdapter ha = context.getBean(HANDLER_ADAPTER_BEAN_NAME, HandlerAdapter.class);
  17. this.handlerAdapters = Collections.singletonList(ha);
  18. }
  19. catch (NoSuchBeanDefinitionException ex) {}
  20. }
  21. // 如果以上两种都没有定义,则获取默认的处理策略
  22. if (this.handlerAdapters == null) {
  23. this.handlerAdapters = getDefaultStrategies(context, HandlerAdapter.class);
  24. }
  25. }
  26. }
3.6.1.3. DispatcherServlet.initHandlerExceptionResolvers

DispatcherServlet.initHandlerExceptionResolvers

  1. public class DispatcherServlet extends FrameworkServlet {
  2. private void initHandlerExceptionResolvers(ApplicationContext context) {
  3. this.handlerExceptionResolvers = null;
  4. // 默认是探测所有的HandlerExceptionResolver,包括父上下文
  5. if (this.detectAllHandlerExceptionResolvers) {
  6. Map<String, HandlerExceptionResolver> matchingBeans = BeanFactoryUtils
  7. .beansOfTypeIncludingAncestors(context, HandlerExceptionResolver.class, true, false);
  8. if (!matchingBeans.isEmpty()) {
  9. this.handlerExceptionResolvers = new ArrayList<>(matchingBeans.values());
  10. AnnotationAwareOrderComparator.sort(this.handlerExceptionResolvers);
  11. }
  12. }
  13. else {
  14. // 否则直接获取bean
  15. try {
  16. HandlerExceptionResolver her =
  17. context.getBean(HANDLER_EXCEPTION_RESOLVER_BEAN_NAME, HandlerExceptionResolver.class);
  18. this.handlerExceptionResolvers = Collections.singletonList(her);
  19. }
  20. catch (NoSuchBeanDefinitionException ex) {}
  21. }
  22. // 如果以上两种都没有定义,则获取默认的处理策略
  23. if (this.handlerExceptionResolvers == null) {
  24. this.handlerExceptionResolvers = getDefaultStrategies(context, HandlerExceptionResolver.class);
  25. }
  26. }
  27. }
3.6.1.4. DispatcherServlet.initRequestToViewNameTranslator

DispatcherServlet.initRequestToViewNameTranslator

  1. public class DispatcherServlet extends FrameworkServlet {
  2. private void initRequestToViewNameTranslator(ApplicationContext context) {
  3. try {
  4. // 获取bean
  5. this.viewNameTranslator =
  6. context.getBean(REQUEST_TO_VIEW_NAME_TRANSLATOR_BEAN_NAME, RequestToViewNameTranslator.class);
  7. }
  8. catch (NoSuchBeanDefinitionException ex) {
  9. // 如果没有定义bean,则获取默认的处理策略
  10. this.viewNameTranslator = getDefaultStrategy(context, RequestToViewNameTranslator.class);
  11. }
  12. }
  13. }
3.6.1.5. DispatcherServlet.initViewResolvers

DispatcherServlet.initViewResolvers

  1. public class DispatcherServlet extends FrameworkServlet {
  2. private void initViewResolvers(ApplicationContext context) {
  3. this.viewResolvers = null;
  4. // 默认是探测所有的ViewResolver,包括父上下文
  5. if (this.detectAllViewResolvers) {
  6. Map<String, ViewResolver> matchingBeans =
  7. BeanFactoryUtils.beansOfTypeIncludingAncestors(context, ViewResolver.class, true, false);
  8. if (!matchingBeans.isEmpty()) {
  9. this.viewResolvers = new ArrayList<>(matchingBeans.values());
  10. AnnotationAwareOrderComparator.sort(this.viewResolvers);
  11. }
  12. }
  13. else {
  14. // 否则直接获取bean
  15. try {
  16. ViewResolver vr = context.getBean(VIEW_RESOLVER_BEAN_NAME, ViewResolver.class);
  17. this.viewResolvers = Collections.singletonList(vr);
  18. }
  19. catch (NoSuchBeanDefinitionException ex) {}
  20. }
  21. // 如果以上两种都没有定义,则获取默认的处理策略
  22. if (this.viewResolvers == null) {
  23. this.viewResolvers = getDefaultStrategies(context, ViewResolver.class);
  24. }
  25. }
  26. }

3.6.2. DispatcherServlet.doService

刚刚解析完了 DispatcherServlet.onRefresh,现在来看看 DispatcherServlet.doService

  1. public class DispatcherServlet extends FrameworkServlet {
  2. @Override
  3. protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
  4. // ... 代码省略
  5. // 给请求对象添加一些上下文数据
  6. request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());
  7. request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
  8. request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
  9. request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource());
  10. // ... 代码省略
  11. try {
  12. doDispatch(request, response);
  13. }
  14. finally {
  15. // ... 代码省略
  16. }
  17. }
  18. protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
  19. HttpServletRequest processedRequest = request;
  20. // 处理器链
  21. HandlerExecutionChain mappedHandler = null;
  22. // 是Multipart文件上传
  23. boolean multipartRequestParsed = false;
  24. // 异步处理管理器
  25. WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
  26. try {
  27. ModelAndView mv = null;
  28. Exception dispatchException = null;
  29. try {
  30. // 检测Multipart文件上传
  31. processedRequest = checkMultipart(request);
  32. multipartRequestParsed = (processedRequest != request);
  33. // 获取处理器,从handlerMappings中查找符合请求的处理器
  34. mappedHandler = getHandler(processedRequest);
  35. if (mappedHandler == null) {
  36. // 未找到处理器,404
  37. noHandlerFound(processedRequest, response);
  38. return;
  39. }
  40. // 获取处理器适配器,从handlerAdapters中查找符合处理器的适配器
  41. HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
  42. String method = request.getMethod();
  43. // 如果是GET或HEAD请求,检查Last-Modified
  44. boolean isGet = "GET".equals(method);
  45. if (isGet || "HEAD".equals(method)) {
  46. long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
  47. if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
  48. return;
  49. }
  50. }
  51. // 前置处理,调用处理器的preHandle方法,如果有一个不成功,返回
  52. if (!mappedHandler.applyPreHandle(processedRequest, response)) {
  53. return;
  54. }
  55. // 调用处理器
  56. mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
  57. // ... 代码省略
  58. // 如果没有视图名字,添加默认的视图名
  59. applyDefaultViewName(processedRequest, mv);
  60. // 后置处理,调用处理器的postHandle方法
  61. mappedHandler.applyPostHandle(processedRequest, response, mv);
  62. }
  63. catch (Exception ex) {
  64. // ... 代码省略
  65. }
  66. catch (Throwable err) {
  67. // ... 代码省略
  68. }
  69. // 处理handler返回的结果
  70. processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
  71. }
  72. catch (Exception ex) {
  73. // ... 代码省略
  74. }
  75. catch (Throwable err) {
  76. // ... 代码省略
  77. }
  78. finally {
  79. // ... 代码省略
  80. }
  81. }
  82. // 处理handler返回的结果
  83. private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
  84. @Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,
  85. @Nullable Exception exception) throws Exception {
  86. boolean errorView = false;
  87. if (exception != null) {
  88. // ... 代码省略,如果有异常,调用handlerExceptionResolvers处理
  89. }
  90. if (mv != null && !mv.wasCleared()) {
  91. // 渲染视图
  92. render(mv, request, response);
  93. if (errorView) {
  94. WebUtils.clearErrorRequestAttributes(request);
  95. }
  96. }
  97. // ... 代码省略
  98. }
  99. // 渲染视图
  100. protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
  101. // ... 代码省略
  102. View view;
  103. String viewName = mv.getViewName();
  104. if (viewName != null) {
  105. // 调用viewResolvers来解析视图
  106. view = resolveViewName(viewName, mv.getModelInternal(), locale, request);
  107. // ... 代码省略
  108. }
  109. else {
  110. // ... 代码省略
  111. }
  112. // ... 代码省略
  113. try {
  114. if (mv.getStatus() != null) {
  115. // 设置http状态码
  116. response.setStatus(mv.getStatus().value());
  117. }
  118. // 真实渲染
  119. view.render(mv.getModelInternal(), request, response);
  120. }
  121. catch (Exception ex) {
  122. // ... 代码省略
  123. }
  124. }
  125. }

3.6.3. 需要后面再解析的几个点

DispatcherServlet 这个类的解析基本上就差不多了,但还有几点没有解析:

这几点,我们后面再来解析。

4. ContextLoaderListener

先来看看 ContextLoaderListener 的继承关系:

  1. - ContextLoader
  2. - ContextLoaderListener

ContextLoaderListener
比较简单,只有两个监听事件方法

  1. public class ContextLoaderListener extends ContextLoader implements ServletContextListener {
  2. @Override
  3. public void contextInitialized(ServletContextEvent event) {
  4. // ContextLoader.initWebApplicationContext
  5. initWebApplicationContext(event.getServletContext());
  6. }
  7. @Override
  8. public void contextDestroyed(ServletContextEvent event) {
  9. // ContextLoader.closeWebApplicationContext
  10. closeWebApplicationContext(event.getServletContext());
  11. // 销毁上下文中以"org.springframework."开头的可销毁bean
  12. ContextCleanupListener.cleanupAttributes(event.getServletContext());
  13. }
  14. }

ContextLoader
的静态初始化

  1. public class ContextLoader {
  2. static {
  3. try {
  4. // 从ContextLoader.properties文件中加载默认的策略
  5. ClassPathResource resource = new ClassPathResource(DEFAULT_STRATEGIES_PATH, ContextLoader.class);
  6. defaultStrategies = PropertiesLoaderUtils.loadProperties(resource);
  7. }
  8. catch (IOException ex) {
  9. throw new IllegalStateException("Could not load 'ContextLoader.properties': " + ex.getMessage());
  10. }
  11. }
  12. }

ContextLoader.properties
文件的内容如下:

  1. # Default WebApplicationContext implementation class for ContextLoader.
  2. # Used as fallback when no explicit context implementation has been specified as context-param.
  3. # Not meant to be customized by application developers.
  4. org.springframework.web.context.WebApplicationContext=org.springframework.web.context.support.XmlWebApplicationContext

ContextLoader.properties 文件中指明使用 XmlWebApplicationContext 作为默认的 Web 应用上下文环境

再来看看 ContextLoader
initWebApplicationContextcloseWebApplicationContext

4.1. ContextLoaderListener.initWebApplicationContext

ContextLoaderListener.initWebApplicationContext

  1. public class ContextLoader {
  2. public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {
  3. // ... 代码省略
  4. try {
  5. // 如果没有上下文对象,则创建一个新的上下文
  6. // 并调用 configureAndRefreshWebApplicationContext(cwac) 配置并刷新新的上下文
  7. // 默认使用 XmlWebApplicationContext(基于XML加载)作为应用上下文
  8. if (this.context == null) {
  9. this.context = createWebApplicationContext(servletContext);
  10. }
  11. if (this.context instanceof ConfigurableWebApplicationContext) {
  12. ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) this.context;
  13. // 未激活
  14. if (!cwac.isActive()) {
  15. if (cwac.getParent() == null) {
  16. ApplicationContext parent = loadParentContext(servletContext);
  17. cwac.setParent(parent);
  18. }
  19. // 配置并刷新应用上下文
  20. configureAndRefreshWebApplicationContext(cwac, servletContext);
  21. }
  22. }
  23. // 把上下文注册到ServletContext中
  24. servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);
  25. // ... 代码省略
  26. return this.context;
  27. }
  28. catch (RuntimeException | Error ex) {
  29. // ... 代码省略
  30. }
  31. }
  32. }

ContextLoader.configureAndRefreshWebApplicationContextFrameworkServlet.configureAndRefreshWebApplicationContext
的处理基本上一致。

也就是说,当容器启动(如 Tomcat、Jetty、Undertow 等)时,Spring 框架会自动进行初始化。

4.2. ContextLoaderListener.closeWebApplicationContext

ContextLoaderListener.closeWebApplicationContext

  1. public class ContextLoader {
  2. public void closeWebApplicationContext(ServletContext servletContext) {
  3. try {
  4. if (this.context instanceof ConfigurableWebApplicationContext) {
  5. // 调用上下文对象的close方法
  6. ((ConfigurableWebApplicationContext) this.context).close();
  7. }
  8. }
  9. finally {
  10. // ... 代码省略
  11. }
  12. }
  13. }

5. 综述

DispatcherServlet.initContextLoaderListener.contextInitialized 都会进行应用上下文的初始化,主要过程是:

  1. 初始化 Web 应用上下文,默认使用 XmlWebApplicationContext(基于 XML 加载)作为应用上下文,并调用 refresh 方法
  2. 实例化由 globalInitializerClassescontextInitializerClasses 定义的类
  3. 实例化 WebMVC 必要的组件:MultipartResolver, LocaleResolver, ThemeResolver, HandlerMapping,
    HandlerAdapter, HandlerExceptionResolver, RequestToViewNameTranslator, ViewResolver, FlashMapManager

每个请求都会进入到 DispatcherServlet.service,其主要过程是:

  1. 初始化请求对象,以便应用后续处理
  2. 处理 Multipart 文件上传,获取处理器处理当前请求
  3. 如果当前请求处理发生异常,进行异常处理
  4. 进行视图渲染

6. 未完

到这里为止,解析仅仅止于 DispatcherServletContextLoaderListener 两个类,下一篇将深入其他类,继续探索。

  • ConfigurableWebApplicationContext.refresh 刷新上下文
  • ApplicationContext.getBean 从上下文中获取 bean
  • DispatcherServlet.properties 文件中定义的策略处理
  • ContextLoader.properties 文件中定义的策略处理
  • View.render 视图渲染

后续

更多博客,查看 https://github.com/senntyou/blogs

作者:深予之 (@senntyou)

版权声明:自由转载-非商用-非衍生-保持署名(创意共享 3.0 许可证

相关文章