3

Spring source code analysis 1: SpringMVC loading mechanism

1. spring-framework included in 06177cd001242e

Before analyzing SpringMVC , let's take a look at spring-framework , and what are the functions of each.

spring-framework official warehouse

  • spring-jcl : General log processing of the spring
  • spring-core : spring framework, including the operation processing and dynamic generation of Java bytecode, dependency injection mechanism (also called inversion of control), tool library,
    Annotation operation, coding processing and data conversion, resource loading and processing, environment loading mechanism, etc.
  • spring-beans : Definition, loading, analysis, editing, etc. of spring bean
  • spring-context : spring framework, including application caching, application events, application configuration, core annotation definition and processing, resource loading, asynchronous and timing tasks, data verification and formatting, etc.
  • spring-aop : Encapsulation and processing of aspect-oriented programming
  • spring-aspects : -oriented programming using 16177cd001262d AspectJ as the underlying implementation
  • spring-tx : Encapsulation and processing of transactions
  • spring-jdbc : Encapsulation and processing of database links
  • spring-context-indexer : Support for annotation @Indexed
  • spring-context-support : Optional support for some third-party libraries, such as ehcache, javamail, quartz, freemarker
  • spring-oxm : Packaging of O/X Mapper
  • spring-messaging : http, rsocket, simp messaging protocols such as 06177cd001271c
  • spring-jms : Encapsulation of JMS (Java Message Service)
  • spring-expression : Spring Expression Language ( ) 16177cd0012787 Spring Expression Language Implementation
  • spring-r2dbc : package R2DBC
  • spring-orm : JPA and hibernate
  • spring-web : Provides the basic structure and technology of the Web framework, such as Http calling, filtering, processing, etc.
  • spring-webmvc : Implementation of Web MVC architecture, including Servlet container initialization, route mapping, view rendering, response processing, etc.
  • spring-websocket : Support for WebSocket
  • spring-webflux : Implementation of the Reactive Web framework, as opposed spring-webmvc

The core modules of the SpringMVC framework are mainly: spring-core , spring-beans , spring-context , spring-web , spring-webmvc , which are mainly analyzed later.

1.1. spring-core

spring-core that need to be briefly introduced here:

  1. spring-core has powerful Java bytecode operation processing functions and dynamic generation functions, which are the basis for aspect-oriented programming, data type conversion, SpEL expressions and other functions
  2. spring-core provides a dependency injection mechanism, which is spring bean loading, and it is also the underlying mechanism by which we can use @Autowired automatically load objects and other functions
  3. spring-core provides a mechanism for environment loading, so we can use application-dev.yml, application-test.yml, application-prod.yml, ...
    To load different configurations according to the environment
  4. spring-core provides an extension mechanism similar to Java SPI, which can automatically instantiate classes specified by other packages. spring-boot, spring-cloud all rely on this mechanism to automatically load resources.
    Define the classes that need to be automatically loaded in the META-INF/spring.factories Spring Factories

1.2. spring-beans

There are several points of Spring bean loading and extension mechanism that need to be briefly introduced here:

  1. There are two main types of Spring bean definitions: annotation-based definitions and XML file-based definitions
  2. spring-beans provides a third-party command space expansion mechanism for beans based on XML configuration, mainly in
    The command space that needs to be expanded is defined in the META-INF/spring.handlers, META-INF/spring.schemas
    Such as <dubbo:application name="name"/>, <dubbo:registry address="address"/>
  3. Annotation-based custom extensions need to rely on the extension loading mechanism of spring-boot

1.3. spring-context

spring-context is the core processing part of the application, including:

  • App cache
  • Application event
  • Application configuration
  • Core annotation definition and processing
  • Resource loading
  • Asynchronous and timed tasks
  • Data verification and formatting

Etc., such framework core annotations @ComponentScan, @Profile, @Conditional, @Bean, @Async, @Controller, @Service, @Component, @Validated

1.4. spring-web

spring-web is the core processing part of Http, mainly including:

  • Core Http request and response processing (including cookies, caching, multimedia, etc.)
  • Http request and response codec and conversion (including Json, XML, ProtoBuf, etc.)
  • Reactive web framework basic processing
  • Call the client (such as RestTemplate )
  • Servlet context
  • Request filter
  • Multipart file upload processing

Etc., such Web core annotations such @RequestMapping, @RequestParam, @PathVariable, @ResponseBody, @RestController

1.5. spring-webmvc

spring-webmvc depends on spring-web , the main functions include:

  • Servlet container initialization
  • Route map
  • View rendering
  • Response processing

Wait, if you don't use Spring MVC, but want to take advantage of other web-related technologies supported by Spring, you only need to rely on spring-web , such as spring-webflux .

1.6. spring-webflux

spring-webflux corresponds to spring-webmvc , webmvc is a synchronous blocking framework, and webflux is an asynchronous non-blocking framework,
It is a new responsive web framework introduced in Spring Framework 5.0.

Reference: Spring WebFlux
Spring WebFlux :: Spring Docs

2. A simple spring-webmvc project configuration

Configure the following in the 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>

There are two entry classes:

These two classes are defined in spring-webmvc and spring-web respectively, and we will analyze them one by one below.

3. DispatcherServlet

Let's take a look at the inheritance relationship of DispatcherServlet

- javax.servlet.Servlet
  - javax.servlet.GenericServlet
    - javax.servlet.http.HttpServlet
      - HttpServletBean
        - FrameworkServlet
          - DispatcherServlet

3.1. javax.servlet.Servlet

First look at javax.servlet.Servlet

javax.servlet.Servlet mainly defines 2 methods:

  • init : Initialize Servlet, only execute once
  • service : In response to a request, this method will be called every time an http request
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

Let's take a look at javax.servlet.GenericServlet

javax.servlet.GenericServlet mainly overloads the init method

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

Let's take a look at javax.servlet.http.HttpServlet

javax.servlet.http.HttpServlet mainly overloads the service method and extends 7 methods:

  • doGet : Processing GET request, only input error information, not implemented
  • doHead : Processing HEAD request, only input error information, not implemented
  • doPost : Processing POST request, only input error information, not implemented
  • doPut : Processing PUT request, only input error information, not implemented
  • doDelete : Processing DELETE request, only input error information, not implemented
  • doOptions : Handling OPTIONS requests
  • doTrace : Process TRACE requests
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

Let's take a look at HttpServletBean

HttpServletBean mainly overloads the init method and extends 2 methods:

  • initBeanWrapper : Initialize the Java Bean defined by Servlet Config, implemented by subclasses, and not implemented by default
  • initServletBean : Initialize Servlet bean, implemented by subclass
public abstract class HttpServletBean extends HttpServlet implements EnvironmentCapable, EnvironmentAware {
    // 初始化
    @Override
    public final void init() throws ServletException {
        // 把Servlet配置参数设置到bean属性中
        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;
            }
        }

        // 初始化Servlet bean
        initServletBean();
    }

    // 初始化由Servlet Config定义的Java Bean,由子类实现,默认不实现
    protected void initBeanWrapper(BeanWrapper bw) throws BeansException {
    }

    // 初始化Servlet bean,由子类实现
    protected void initServletBean() throws ServletException {
    }
}

3.5. FrameworkServlet

Let's take a look at FrameworkServlet

FrameworkServlet is the core Servlet of the framework, which mainly overloads the initServletBean method and extends 2 methods:

  • initFrameworkServlet : Initialize the framework Servlet, implemented by subclasses, not implemented by default
  • onRefresh : refresh context data, implemented by subclasses

Overloaded the service, doGet, doPost, doPut, doDelete, doOptions, doTrace method, and extended 1 method:

  • doService : Processing response request
3.5.1. FrameworkServlet.initServletBean

After the parent class HttpServletBean initialized, two hooks initBeanWrapper, initServletBean left. initBeanWrapper is not implemented by default.
So take a look at the implementation of the 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 {}
}

Let's take a look at 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) {
            // 对webApplicationContext进行配置
            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;
    }
}

There are two methods that need to be analyzed in depth: configureAndRefreshWebApplicationContext , onRefresh

Let's take a look at 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());
        }
    }
}

Let's take a look at FrameworkServlet.onRefresh

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

Let's take a look at 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")) {
                return;
            }
        }

        // ... 代码省略
    }

    @Override
    protected void doTrace(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        if (this.dispatchTraceRequest) {
            // 扩展处理
            processRequest(request, response);
            if ("message/http".equals(response.getContentType())) {
                return;
            }
        }
        super.doTrace(request, response);
    }
}

Let's take a look at the extended processing method 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 mainly extends 2 methods: onRefresh , doService , so take a look at DispatcherServlet
How is it achieved

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
The files (the developer cannot customize the coverage) are as follows:

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 file specifies:

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

Just finished parsing DispatcherServlet.onRefresh , now let’s take a look at 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. Several points that need to be resolved later

DispatcherServlet the class 06177cd002a94c is basically the same, but there are still a few points that are not resolved:

We will analyze these points later.

4. ContextLoaderListener

Let's take a look at the inheritance relationship of ContextLoaderListener

- ContextLoader
  - ContextLoaderListener

ContextLoaderListener
Relatively simple, there are only two methods to monitor events

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
Static initialization

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
The content of the file is as follows:

# 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 file specifies the use of XmlWebApplicationContext as the default Web application context environment

Let's take a look at ContextLoader
initWebApplicationContext and closeWebApplicationContext

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.configureAndRefreshWebApplicationContext and FrameworkServlet.configureAndRefreshWebApplicationContext
The treatment is basically the same.

In other words, when the container starts (such as Tomcat, Jetty, Undertow, etc.), the Spring framework will automatically initialize.

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. Summary

DispatcherServlet.init and ContextLoaderListener.contextInitialized will initialize the application context. The main process is:

  1. Initialize the Web application context, use XmlWebApplicationContext (based on XML loading) as the application context by refresh method
  2. Instantiate the classes defined globalInitializerClasses and contextInitializerClasses
  3. Instantiate the necessary components of WebMVC: MultipartResolver , LocaleResolver , ThemeResolver , HandlerMapping ,
    HandlerAdapter, HandlerExceptionResolver, RequestToViewNameTranslator, ViewResolver, FlashMapManager

Each request will enter DispatcherServlet.service , the main process is:

  1. Initialize the request object so that subsequent processing can be applied
  2. Process Multipart file upload, get the processor to process the current request
  3. If an exception occurs in the current request processing, perform exception handling
  4. Perform view rendering

6. Unfinished

So far, the analysis only ends with the DispatcherServlet ContextLoaderListener . The next article will delve into other classes and continue to explore.

  • ConfigurableWebApplicationContext.refresh refresh context
  • ApplicationContext.getBean Get the bean from the context
  • The policy processing defined in the DispatcherServlet.properties
  • The policy processing defined in the ContextLoader.properties
  • View.render view rendering

Follow-up

For more blogs, check out https://github.com/senntyou/blogs

Author: Shen Yuzhi (@senntyou)

Copyright statement: Freely reprinted-non-commercial-non-derivative-keep the signature ( Creative Commons 3.0 License )


深雨
12.7k 声望6.5k 粉丝

达则兼济天下,穷则独善其身。