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 文件中定义须要扩大的标签,比方 <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 文件中如下配置:

<?xml version="1.0" encoding="UTF-8"?><web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"    xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"    version="3.0">  <display-name>springMVC</display-name>  <!-- 部署 DispatcherServlet -->  <servlet>    <servlet-name>springmvc</servlet-name>    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>    <init-param>      <param-name>contextConfigLocation</param-name>      <param-value>classpath:springmvc-servlet.xml</param-value>    </init-param>    <!-- 容器再启动时立刻加载servlet -->    <load-on-startup>1</load-on-startup>  </servlet>  <servlet-mapping>    <servlet-name>springmvc</servlet-name>    <!-- 解决所有URL -->    <url-pattern>/</url-pattern>  </servlet-mapping>  <!-- 定义应用程序监听器 -->  <listener>    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>  </listener></web-app>

这里有两个入口类:

  • 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    {        HttpServletRequest  request;        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<String, HandlerMapping> 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 <T> List<T> getDefaultStrategies(ApplicationContext context, Class<T> 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 = defaultStrategies.getProperty(key);        if (value != null) {            String[] classNames = StringUtils.commaDelimitedListToStringArray(value);            List<T> 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<String, HandlerAdapter> 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<String, HandlerExceptionResolver> 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<String, ViewResolver> 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)

版权申明:自在转载-非商用-非衍生-放弃署名(创意共享 3.0 许可证)