3

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

 2 years ago
source link: https://segmentfault.com/a/1190000040786453
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

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-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 文件中如下配置:

<?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>

这里有两个入口类:

这两个类分别定义在 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.AcceptHeaderLocaleResolver

org.springframework.web.servlet.ThemeResolver=org.springframework.web.servlet.theme.FixedThemeResolver

org.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,\
    org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping,\
    org.springframework.web.servlet.function.support.RouterFunctionMapping

org.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.HandlerFunctionAdapter


org.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.DefaultHandlerExceptionResolver

org.springframework.web.servlet.RequestToViewNameTranslator=org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator

org.springframework.web.servlet.ViewResolver=org.springframework.web.servlet.view.InternalResourceViewResolver

org.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 这个类的解析基本上就差不多了,但还有几点没有解析:

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

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 应用上下文环境

再来看看 ContextLoaderinitWebApplicationContextcloseWebApplicationContext

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 {
            // ... 代码省略
        }
    }
}

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. 进行视图渲染

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

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

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

作者:深予之 (@senntyou)

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


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK