Spring|Spring 源码解析一(SpringMVC 的加载机制)

Spring 源码解析一:SpringMVC 的加载机制 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-expression:Spring Expression Language (SpEL) Spring 表达式语言的实现
  • spring-r2dbc:对 R2DBC 的封装
  • spring-orm:对 JPA 和 hibernate 的封装
  • 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 文件中定义需要扩展的标签,比如 ,
  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 文件中如下配置:
springMVCspringmvc org.springframework.web.servlet.DispatcherServlet contextConfigLocationclasspath:springmvc-servlet.xml 1springmvc/ org.springframework.web.context.ContextLoaderListener

这里有两个入口类:
  • servlet-class org.springframework.web.servlet.DispatcherServlet: 指定用来处理对应 URL 请求的类
  • listener-class org.springframework.web.context.ContextLoaderListener: 设置事件监听器,事件监听程序在建立、修改和删除会话或 servlet 环境时得到通知
这两个类分别定义在 spring-webmvcspring-web 中,下面对他们一一进行解析。
3. DispatcherServlet 先来看看 DispatcherServlet 的继承关系:
- javax.servlet.Servlet - javax.servlet.GenericServlet - javax.servlet.http.HttpServlet - HttpServletBean - FrameworkServlet - DispatcherServlet

3.1. javax.servlet.Servlet
首先看看 javax.servlet.Servlet
javax.servlet.Servlet 主要定义了 2 个方法:
  • init:初始化 Servlet,只执行一次
  • service:响应请求,每次 http 请求都会调用这个方法
public interface Servlet { // 初始化 Servlet,只执行一次 public void init(ServletConfig config) throws ServletException; // 响应请求,每次http请求都会调用这个方法 public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException; // 销毁 Servlet public void destroy(); }

3.2. javax.servlet.GenericServlet
再来看看 javax.servlet.GenericServlet
javax.servlet.GenericServlet 主要是重载了 init 方法
public abstract class GenericServlet implements Servlet, ServletConfig, java.io.Serializable { public GenericServlet() {}// 添加配置初始化 public void init(ServletConfig config) throws ServletException { this.config = config; this.init(); }// 保留无参初始化 public void init() throws ServletException {}// 留给子类实现 public abstract void service(ServletRequest req, ServletResponse res) throws ServletException, IOException; }

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 请求
public abstract class HttpServlet extends GenericServlet { private static final String METHOD_DELETE = "DELETE"; private static final String METHOD_HEAD = "HEAD"; private static final String METHOD_GET = "GET"; private static final String METHOD_OPTIONS = "OPTIONS"; private static final String METHOD_POST = "POST"; private static final String METHOD_PUT = "PUT"; private static final String METHOD_TRACE = "TRACE"; protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String protocol = req.getProtocol(); String msg = lStrings.getString("http.method_get_not_supported"); if (protocol.endsWith("1.1")) { resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg); } else { resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg); } }protected void doHead(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { NoBodyResponse response = new NoBodyResponse(resp); // 调用 doGet,但body设为空body doGet(req, response); response.setContentLength(); }protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // ... 代码省略 }protected void doPut(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // ... 代码省略 }protected void doDelete(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // ... 代码省略 }protected void doOptions(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // ... 代码省略 }protected void doTrace(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // ... 代码省略 }// 实现了GET, HEAD, POST PUT, DELETE, OPTIONS, TRACE七个Http方法 protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String method = req.getMethod(); if (method.equals(METHOD_GET)) { // ... 代码省略 doGet(req, resp); // ... 代码省略 } else if (method.equals(METHOD_HEAD)) { long lastModified = getLastModified(req); maybeSetLastModified(resp, lastModified); doHead(req, resp); } else if (method.equals(METHOD_POST)) { doPost(req, resp); } else if (method.equals(METHOD_PUT)) { doPut(req, resp); } else if (method.equals(METHOD_DELETE)) { doDelete(req, resp); } else if (method.equals(METHOD_OPTIONS)) { doOptions(req,resp); } else if (method.equals(METHOD_TRACE)) { doTrace(req,resp); } else { String errMsg = lStrings.getString("http.method_not_implemented"); Object[] errArgs = new Object[1]; errArgs[0] = method; errMsg = MessageFormat.format(errMsg, errArgs); resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg); } }// 把 Servlet 转化为 HttpServlet @Override public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException { HttpServletRequestrequest; HttpServletResponse response; if (!(req instanceof HttpServletRequest && res instanceof HttpServletResponse)) { throw new ServletException("non-HTTP request or response"); }request = (HttpServletRequest) req; response = (HttpServletResponse) res; service(request, response); } }

3.4. HttpServletBean
再来看看 HttpServletBean
HttpServletBean 主要是重载了 init 方法,并扩展了 2 个方法:
  • initBeanWrapper:初始化由 Servlet Config 定义的 Java Bean,由子类实现,默认不实现
  • initServletBean:初始化 Servlet bean,由子类实现
public abstract class HttpServletBean extends HttpServlet implements EnvironmentCapable, EnvironmentAware { // 初始化 @Override public final void init() throws ServletException { // Set bean properties from init parameters. PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties); if (!pvs.isEmpty()) { try { BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this); ResourceLoader resourceLoader = new ServletContextResourceLoader(getServletContext()); bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, getEnvironment())); initBeanWrapper(bw); bw.setPropertyValues(pvs, true); } catch (BeansException ex) { if (logger.isErrorEnabled()) { logger.error("Failed to set bean properties on servlet '" + getServletName() + "'", ex); } throw ex; } }// Let subclasses do whatever initialization they like. initServletBean(); }// 初始化由Servlet Config定义的Java Bean,由子类实现,默认不实现 protected void initBeanWrapper(BeanWrapper bw) throws BeansException { }// 初始化Servlet bean,由子类实现 protected void initServletBean() throws ServletException { } }

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
public abstract class FrameworkServlet extends HttpServletBean implements ApplicationContextAware { @Override protected final void initServletBean() throws ServletException { // ... 代码省略try { // 初始化Web应用上下文 this.webApplicationContext = initWebApplicationContext(); // 初始化Web框架Servlet initFrameworkServlet(); } catch (ServletException | RuntimeException ex) { logger.error("Context initialization failed", ex); throw ex; }// ... 代码省略 }// 初始化框架Servlet,由子类实现,默认不实现 protected void initFrameworkServlet() throws ServletException {} }

再来看看 FrameworkServlet.initWebApplicationContext
public abstract class FrameworkServlet extends HttpServletBean implements ApplicationContextAware { protected WebApplicationContext initWebApplicationContext() { // 获取应用根上下文 WebApplicationContext rootContext = WebApplicationContextUtils.getWebApplicationContext(getServletContext()); WebApplicationContext wac = null; if (this.webApplicationContext != null) { // A context instance was injected at construction time -> use it wac = this.webApplicationContext; if (wac instanceof ConfigurableWebApplicationContext) { ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac; // 未激活 if (!cwac.isActive()) { if (cwac.getParent() == null) { cwac.setParent(rootContext); } // 配置并刷新应用上下文 configureAndRefreshWebApplicationContext(cwac); } } } if (wac == null) { // 如果没有,则在ServletContext中查找是否注册过 wac = findWebApplicationContext(); } if (wac == null) { // 如果任然没有,则以rootContext为父上下文创建一个新的上下文 // 并调用 configureAndRefreshWebApplicationContext(cwac) 配置并刷新新的上下文 // 默认使用 XmlWebApplicationContext(基于XML加载)作为应用上下文 wac = createWebApplicationContext(rootContext); }if (!this.refreshEventReceived) { // 重载上下文数据 synchronized (this.onRefreshMonitor) { onRefresh(wac); } }if (this.publishContext) { // 把上下文注册到ServletContext中 String attrName = getServletContextAttributeName(); getServletContext().setAttribute(attrName, wac); }return wac; }// 以parent为父上下文创建一个新的上下文 // 并调用 configureAndRefreshWebApplicationContext(cwac) 配置并刷新新的上下文 // 默认使用 XmlWebApplicationContext(基于XML加载)作为应用上下文 protected WebApplicationContext createWebApplicationContext(@Nullable ApplicationContext parent) { // 这里默认使用 XmlWebApplicationContext(基于XML加载) Class contextClass = getContextClass(); ConfigurableWebApplicationContext wac = (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass); wac.setEnvironment(getEnvironment()); wac.setParent(parent); String configLocation = getContextConfigLocation(); if (configLocation != null) { wac.setConfigLocation(configLocation); } configureAndRefreshWebApplicationContext(wac); return wac; } }

这其中有两个方法需要深入解析:configureAndRefreshWebApplicationContext, onRefresh
再来看看 FrameworkServlet.configureAndRefreshWebApplicationContext
public abstract class FrameworkServlet extends HttpServletBean implements ApplicationContextAware { protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac) { // ... 代码省略// 设置ServletContext wac.setServletContext(getServletContext()); // 设置ServletConfig wac.setServletConfig(getServletConfig()); wac.setNamespace(getNamespace()); // 添加应用事件监听器,应用事件会触发当前对象的onApplicationEvent方法 // 进一步,会调用当前对象的onRefresh方法,刷新上下文数据 wac.addApplicationListener(new SourceFilteringListener(wac, new ContextRefreshListener())); // ... 代码省略// 初始化一些需要初始加载的类,调用这些类的initialize方法 applyInitializers(wac); // 应用上下文刷新 wac.refresh(); }// 应用事件会触发此方法,然后调用当前对象的onRefresh方法,刷新上下文数据 public void onApplicationEvent(ContextRefreshedEvent event) { this.refreshEventReceived = true; synchronized (this.onRefreshMonitor) { onRefresh(event.getApplicationContext()); } } }

再来看看 FrameworkServlet.onRefresh
public abstract class FrameworkServlet extends HttpServletBean implements ApplicationContextAware { protected void onRefresh(ApplicationContext context) { // 由子类来实现 } }

3.5.2. FrameworkServlet.service 再来看看 FrameworkServlet.service
public abstract class FrameworkServlet extends HttpServletBean implements ApplicationContextAware { @Override protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {HttpMethod httpMethod = HttpMethod.resolve(request.getMethod()); // 如果Http方法是Patch或没有,扩展处理 if (httpMethod == HttpMethod.PATCH || httpMethod == null) { processRequest(request, response); } else { super.service(request, response); } }@Override protected final void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 扩展处理 processRequest(request, response); }@Override protected final void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 扩展处理 processRequest(request, response); }@Override protected final void doPut(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 扩展处理 processRequest(request, response); }@Override protected final void doDelete(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 扩展处理 processRequest(request, response); }@Override protected void doOptions(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {if (this.dispatchOptionsRequest || CorsUtils.isPreFlightRequest(request)) { // 扩展处理 processRequest(request, response); if (response.containsHeader("Allow")) { // Proper OPTIONS response coming from a handler - we're done. return; } }// ... 代码省略 }@Override protected void doTrace(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {if (this.dispatchTraceRequest) { // 扩展处理 processRequest(request, response); if ("message/http".equals(response.getContentType())) { // Proper TRACE response coming from a handler - we're done. return; } } super.doTrace(request, response); } }

再来看看扩展处理方法 FrameworkServlet.processRequest
public abstract class FrameworkServlet extends HttpServletBean implements ApplicationContextAware { protected final void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {// ... 代码省略// 记录请求属性与上下文环境,请求处理完后派发事件 LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext(); LocaleContext localeContext = buildLocaleContext(request); RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes(); ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes); WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request); asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor()); initContextHolders(request, localeContext, requestAttributes); try { doService(request, response); } // ... 代码省略finally { resetContextHolders(request, previousLocaleContext, previousAttributes); if (requestAttributes != null) { requestAttributes.requestCompleted(); } logResult(request, response, failureCause, asyncManager); publishRequestHandledEvent(request, response, startTime, failureCause); } }// 由子类来实现 protected abstract void doService(HttpServletRequest request, HttpServletResponse response) throws Exception; }

3.6. DispatcherServlet
DispatcherServlet 主要扩展了 2 个方法:onRefreshdoService,所以来看看 DispatcherServlet 是如何实现的
3.6.1. DispatcherServlet.onRefresh DispatcherServlet.onRefresh
public class DispatcherServlet extends FrameworkServlet { @Override protected void onRefresh(ApplicationContext context) { initStrategies(context); }protected void initStrategies(ApplicationContext context) { // 初始化Multipart文件上传处理 initMultipartResolver(context); // 初始化本地化处理 initLocaleResolver(context); // 初始化主题处理 initThemeResolver(context); // 初始化处理器映射 initHandlerMappings(context); // 初始化处理器适配 initHandlerAdapters(context); // 初始化处理器异常 initHandlerExceptionResolvers(context); // 初始化视图查找处理 initRequestToViewNameTranslator(context); // 初始化视图解析处理 initViewResolvers(context); // 初始化内存暂存session数据管理器 initFlashMapManager(context); }private void initMultipartResolver(ApplicationContext context) { try { // 获取bean this.multipartResolver = context.getBean(MULTIPART_RESOLVER_BEAN_NAME, MultipartResolver.class); // ... 代码省略 } catch (NoSuchBeanDefinitionException ex) { // ... 代码省略 } }private void initLocaleResolver(ApplicationContext context) { try { // 获取bean this.localeResolver = context.getBean(LOCALE_RESOLVER_BEAN_NAME, LocaleResolver.class); // ... 代码省略 } catch (NoSuchBeanDefinitionException ex) { // ... 代码省略 } }private void initThemeResolver(ApplicationContext context) { try { // 获取bean this.themeResolver = context.getBean(THEME_RESOLVER_BEAN_NAME, ThemeResolver.class); // ... 代码省略 } catch (NoSuchBeanDefinitionException ex) { // ... 代码省略 } }private void initFlashMapManager(ApplicationContext context) { try { // 获取bean this.flashMapManager = context.getBean(FLASH_MAP_MANAGER_BEAN_NAME, FlashMapManager.class); } catch (NoSuchBeanDefinitionException ex) { // 没有bean,则获取默认策略 this.flashMapManager = getDefaultStrategy(context, FlashMapManager.class); } } }

3.6.1.1. DispatcherServlet.initHandlerMappings DispatcherServlet.initHandlerMappings
public class DispatcherServlet extends FrameworkServlet { private void initHandlerMappings(ApplicationContext context) { this.handlerMappings = null; // 默认是探测所有的HandlerMapping,包括父上下文 if (this.detectAllHandlerMappings) { Map matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false); if (!matchingBeans.isEmpty()) { this.handlerMappings = new ArrayList<>(matchingBeans.values()); AnnotationAwareOrderComparator.sort(this.handlerMappings); } } else { // 否则直接获取bean try { HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class); this.handlerMappings = Collections.singletonList(hm); } catch (NoSuchBeanDefinitionException ex) {} }// 如果以上两种都没有定义,则获取默认的处理策略 if (this.handlerMappings == null) { this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class); }// ... 代码省略 }// 获取默认的处理策略 protected List getDefaultStrategies(ApplicationContext context, Class strategyInterface) { // 尝试从DispatcherServlet.properties文件中加载 if (defaultStrategies == null) { try { ClassPathResource resource = new ClassPathResource(DEFAULT_STRATEGIES_PATH, DispatcherServlet.class); defaultStrategies = PropertiesLoaderUtils.loadProperties(resource); } catch (IOException ex) { throw new IllegalStateException("Could not load '" + DEFAULT_STRATEGIES_PATH + "': " + ex.getMessage()); } }String key = strategyInterface.getName(); String value = https://www.it610.com/article/defaultStrategies.getProperty(key); if (value != null) { String[] classNames = StringUtils.commaDelimitedListToStringArray(value); List strategies = new ArrayList<>(classNames.length); for (String className : classNames) { try { Class clazz = ClassUtils.forName(className, DispatcherServlet.class.getClassLoader()); // 创建bean Object strategy = createDefaultStrategy(context, clazz); // 装载到 strategies 中 strategies.add((T) strategy); } catch (ClassNotFoundException ex) { // ... 代码省略 } catch (LinkageError err) { // ... 代码省略 } } return strategies; } else { return Collections.emptyList(); } }// 创建bean protected Object createDefaultStrategy(ApplicationContext context, Class clazz) { return context.getAutowireCapableBeanFactory().createBean(clazz); } }

DispatcherServlet.properties 文件(开发者不能自定义覆盖)如下:
# Default implementation classes for DispatcherServlet's strategy interfaces. # Used as fallback when no matching beans are found in the DispatcherServlet context. # Not meant to be customized by application developers.org.springframework.web.servlet.LocaleResolver=org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolverorg.springframework.web.servlet.ThemeResolver=org.springframework.web.servlet.theme.FixedThemeResolverorg.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,\ org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping,\ org.springframework.web.servlet.function.support.RouterFunctionMappingorg.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,\ org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,\ org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter,\ org.springframework.web.servlet.function.support.HandlerFunctionAdapterorg.springframework.web.servlet.HandlerExceptionResolver=org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver,\ org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver,\ org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolverorg.springframework.web.servlet.RequestToViewNameTranslator=org.springframework.web.servlet.view.DefaultRequestToViewNameTranslatororg.springframework.web.servlet.ViewResolver=org.springframework.web.servlet.view.InternalResourceViewResolverorg.springframework.web.servlet.FlashMapManager=org.springframework.web.servlet.support.SessionFlashMapManager

DispatcherServlet.properties 文件中指明:
  • AcceptHeaderLocaleResolver 作为默认的本地化解析器
  • FixedThemeResolver 作为默认的主题解析器
  • BeanNameUrlHandlerMapping, RequestMappingHandlerMapping, RouterFunctionMapping 作为默认的处理器映射组件
  • HttpRequestHandlerAdapter, SimpleControllerHandlerAdapter, RequestMappingHandlerAdapter, HandlerFunctionAdapter 作为默认的处理器适配组件
  • ExceptionHandlerExceptionResolver, ResponseStatusExceptionResolver, DefaultHandlerExceptionResolver 作为默认的处理器异常解析器
  • DefaultRequestToViewNameTranslator 作为默认的视图查找处理器
  • InternalResourceViewResolver 作为默认的视图解析器
  • SessionFlashMapManager 作为默认的内存暂存 session 数据管理器
3.6.1.2. DispatcherServlet.initHandlerAdapters DispatcherServlet.initHandlerAdapters
public class DispatcherServlet extends FrameworkServlet { private void initHandlerAdapters(ApplicationContext context) { this.handlerAdapters = null; // 默认是探测所有的HandlerAdapter,包括父上下文 if (this.detectAllHandlerAdapters) { Map matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerAdapter.class, true, false); if (!matchingBeans.isEmpty()) { this.handlerAdapters = new ArrayList<>(matchingBeans.values()); AnnotationAwareOrderComparator.sort(this.handlerAdapters); } } else { // 否则直接获取bean try { HandlerAdapter ha = context.getBean(HANDLER_ADAPTER_BEAN_NAME, HandlerAdapter.class); this.handlerAdapters = Collections.singletonList(ha); } catch (NoSuchBeanDefinitionException ex) {} }// 如果以上两种都没有定义,则获取默认的处理策略 if (this.handlerAdapters == null) { this.handlerAdapters = getDefaultStrategies(context, HandlerAdapter.class); } } }

3.6.1.3. DispatcherServlet.initHandlerExceptionResolvers DispatcherServlet.initHandlerExceptionResolvers
public class DispatcherServlet extends FrameworkServlet { private void initHandlerExceptionResolvers(ApplicationContext context) { this.handlerExceptionResolvers = null; // 默认是探测所有的HandlerExceptionResolver,包括父上下文 if (this.detectAllHandlerExceptionResolvers) { Map matchingBeans = BeanFactoryUtils .beansOfTypeIncludingAncestors(context, HandlerExceptionResolver.class, true, false); if (!matchingBeans.isEmpty()) { this.handlerExceptionResolvers = new ArrayList<>(matchingBeans.values()); AnnotationAwareOrderComparator.sort(this.handlerExceptionResolvers); } } else { // 否则直接获取bean try { HandlerExceptionResolver her = context.getBean(HANDLER_EXCEPTION_RESOLVER_BEAN_NAME, HandlerExceptionResolver.class); this.handlerExceptionResolvers = Collections.singletonList(her); } catch (NoSuchBeanDefinitionException ex) {} }// 如果以上两种都没有定义,则获取默认的处理策略 if (this.handlerExceptionResolvers == null) { this.handlerExceptionResolvers = getDefaultStrategies(context, HandlerExceptionResolver.class); } } }

3.6.1.4. DispatcherServlet.initRequestToViewNameTranslator DispatcherServlet.initRequestToViewNameTranslator
public class DispatcherServlet extends FrameworkServlet { private void initRequestToViewNameTranslator(ApplicationContext context) { try { // 获取bean this.viewNameTranslator = context.getBean(REQUEST_TO_VIEW_NAME_TRANSLATOR_BEAN_NAME, RequestToViewNameTranslator.class); } catch (NoSuchBeanDefinitionException ex) { // 如果没有定义bean,则获取默认的处理策略 this.viewNameTranslator = getDefaultStrategy(context, RequestToViewNameTranslator.class); } } }

3.6.1.5. DispatcherServlet.initViewResolvers DispatcherServlet.initViewResolvers
public class DispatcherServlet extends FrameworkServlet { private void initViewResolvers(ApplicationContext context) { this.viewResolvers = null; // 默认是探测所有的ViewResolver,包括父上下文 if (this.detectAllViewResolvers) { Map matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(context, ViewResolver.class, true, false); if (!matchingBeans.isEmpty()) { this.viewResolvers = new ArrayList<>(matchingBeans.values()); AnnotationAwareOrderComparator.sort(this.viewResolvers); } } else { // 否则直接获取bean try { ViewResolver vr = context.getBean(VIEW_RESOLVER_BEAN_NAME, ViewResolver.class); this.viewResolvers = Collections.singletonList(vr); } catch (NoSuchBeanDefinitionException ex) {} }// 如果以上两种都没有定义,则获取默认的处理策略 if (this.viewResolvers == null) { this.viewResolvers = getDefaultStrategies(context, ViewResolver.class); } } }

3.6.2. DispatcherServlet.doService 刚刚解析完了 DispatcherServlet.onRefresh,现在来看看 DispatcherServlet.doService
public class DispatcherServlet extends FrameworkServlet { @Override protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception { // ... 代码省略// 给请求对象添加一些上下文数据 request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext()); request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver); request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver); request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource()); // ... 代码省略try { doDispatch(request, response); } finally { // ... 代码省略 } }protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception { HttpServletRequest processedRequest = request; // 处理器链 HandlerExecutionChain mappedHandler = null; // 是Multipart文件上传 boolean multipartRequestParsed = false; // 异步处理管理器 WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request); try { ModelAndView mv = null; Exception dispatchException = null; try { // 检测Multipart文件上传 processedRequest = checkMultipart(request); multipartRequestParsed = (processedRequest != request); // 获取处理器,从handlerMappings中查找符合请求的处理器 mappedHandler = getHandler(processedRequest); if (mappedHandler == null) { // 未找到处理器,404 noHandlerFound(processedRequest, response); return; }// 获取处理器适配器,从handlerAdapters中查找符合处理器的适配器 HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler()); String method = request.getMethod(); // 如果是GET或HEAD请求,检查Last-Modified boolean isGet = "GET".equals(method); if (isGet || "HEAD".equals(method)) { long lastModified = ha.getLastModified(request, mappedHandler.getHandler()); if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) { return; } }// 前置处理,调用处理器的preHandle方法,如果有一个不成功,返回 if (!mappedHandler.applyPreHandle(processedRequest, response)) { return; }// 调用处理器 mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); // ... 代码省略// 如果没有视图名字,添加默认的视图名 applyDefaultViewName(processedRequest, mv); // 后置处理,调用处理器的postHandle方法 mappedHandler.applyPostHandle(processedRequest, response, mv); } catch (Exception ex) { // ... 代码省略 } catch (Throwable err) { // ... 代码省略 }// 处理handler返回的结果 processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException); } catch (Exception ex) { // ... 代码省略 } catch (Throwable err) { // ... 代码省略 } finally { // ... 代码省略 } }// 处理handler返回的结果 private void processDispatchResult(HttpServletRequest request, HttpServletResponse response, @Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv, @Nullable Exception exception) throws Exception {boolean errorView = false; if (exception != null) { // ... 代码省略,如果有异常,调用handlerExceptionResolvers处理 }if (mv != null && !mv.wasCleared()) { // 渲染视图 render(mv, request, response); if (errorView) { WebUtils.clearErrorRequestAttributes(request); } } // ... 代码省略 }// 渲染视图 protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception { // ... 代码省略View view; String viewName = mv.getViewName(); if (viewName != null) { // 调用viewResolvers来解析视图 view = resolveViewName(viewName, mv.getModelInternal(), locale, request); // ... 代码省略 } else { // ... 代码省略 }// ... 代码省略 try { if (mv.getStatus() != null) { // 设置http状态码 response.setStatus(mv.getStatus().value()); } // 真实渲染 view.render(mv.getModelInternal(), request, response); } catch (Exception ex) { // ... 代码省略 } } }

3.6.3. 需要后面再解析的几个点 DispatcherServlet 这个类的解析基本上就差不多了,但还有几点没有解析:
  • FrameworkServlet(L702): ConfigurableWebApplicationContext.refresh
  • DispatcherServlet(L514): ApplicationContext.getBean
  • DispatcherServlet.properties 文件中定义的策略处理
  • DispatcherServlet(L1393): View.render
这几点,我们后面再来解析。
4. ContextLoaderListener 先来看看 ContextLoaderListener 的继承关系:
- ContextLoader - ContextLoaderListener

ContextLoaderListener 比较简单,只有两个监听事件方法
public class ContextLoaderListener extends ContextLoader implements ServletContextListener { @Override public void contextInitialized(ServletContextEvent event) { // ContextLoader.initWebApplicationContext initWebApplicationContext(event.getServletContext()); }@Override public void contextDestroyed(ServletContextEvent event) { // ContextLoader.closeWebApplicationContext closeWebApplicationContext(event.getServletContext()); // 销毁上下文中以"org.springframework."开头的可销毁bean ContextCleanupListener.cleanupAttributes(event.getServletContext()); } }

ContextLoader 的静态初始化
public class ContextLoader { static { try { // 从ContextLoader.properties文件中加载默认的策略 ClassPathResource resource = new ClassPathResource(DEFAULT_STRATEGIES_PATH, ContextLoader.class); defaultStrategies = PropertiesLoaderUtils.loadProperties(resource); } catch (IOException ex) { throw new IllegalStateException("Could not load 'ContextLoader.properties': " + ex.getMessage()); } } }

ContextLoader.properties 文件的内容如下:
# Default WebApplicationContext implementation class for ContextLoader. # Used as fallback when no explicit context implementation has been specified as context-param. # Not meant to be customized by application developers.org.springframework.web.context.WebApplicationContext=org.springframework.web.context.support.XmlWebApplicationContext

ContextLoader.properties 文件中指明使用 XmlWebApplicationContext 作为默认的 Web 应用上下文环境
再来看看 ContextLoader 的 initWebApplicationContextcloseWebApplicationContext
4.1. ContextLoaderListener.initWebApplicationContext
ContextLoaderListener.initWebApplicationContext
public class ContextLoader { public WebApplicationContext initWebApplicationContext(ServletContext servletContext) { // ... 代码省略try { // 如果没有上下文对象,则创建一个新的上下文 // 并调用 configureAndRefreshWebApplicationContext(cwac) 配置并刷新新的上下文 // 默认使用 XmlWebApplicationContext(基于XML加载)作为应用上下文 if (this.context == null) { this.context = createWebApplicationContext(servletContext); } if (this.context instanceof ConfigurableWebApplicationContext) { ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) this.context; // 未激活 if (!cwac.isActive()) { if (cwac.getParent() == null) { ApplicationContext parent = loadParentContext(servletContext); cwac.setParent(parent); } // 配置并刷新应用上下文 configureAndRefreshWebApplicationContext(cwac, servletContext); } }// 把上下文注册到ServletContext中 servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context); // ... 代码省略return this.context; } catch (RuntimeException | Error ex) { // ... 代码省略 } } }

ContextLoader.configureAndRefreshWebApplicationContextFrameworkServlet.configureAndRefreshWebApplicationContext 的处理基本上一致。
也就是说,当容器启动(如 Tomcat、Jetty、Undertow 等)时,Spring 框架会自动进行初始化。
4.2. ContextLoaderListener.closeWebApplicationContext
ContextLoaderListener.closeWebApplicationContext
public class ContextLoader { public void closeWebApplicationContext(ServletContext servletContext) { try { if (this.context instanceof ConfigurableWebApplicationContext) { // 调用上下文对象的close方法 ((ConfigurableWebApplicationContext) this.context).close(); } } finally { // ... 代码省略 } } }

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)
【Spring|Spring 源码解析一(SpringMVC 的加载机制)】版权声明:自由转载-非商用-非衍生-保持署名(创意共享 3.0 许可证)

    推荐阅读