SpringMVC 源码分析(四)

文章详细解析了SpringMVC中的DispatcherServlet在接收到第一个请求时的初始化过程,包括Tomcat如何调用Servlet的生命周期方法,以及DispatcherServlet如何通过init方法进行初始化。在这个过程中,重点讨论了WebApplicationContext的创建和配置,以及如何通过模板方法设计模式初始化DispatcherServlet的各种策略组件,如MultipartResolver、LocaleResolver等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

SpringMVC 源码分析(一)中我们知道当请求第一次过来的时候,Servlet容器(如:Tomcat,本文使用Tomcat来作为Servlet容器)会依次调用Servlet的无参构造器、init、service方法,无参构造器是tomcat将项目中的Servlet加载到Tomcat容器中所调用的。也可以在web.xml中设置Servlet的参数load-on-startup大于0,Tomcat就会在启动的时候便调用无参构造器。使用无参主要为了能顺利启动,因为调用有参构造器可能会因为业务原因而报错导致无法启动,所以也是一种规范,不用多说。

当我们的Spring boot项目启动之后,从SpringMVC 源码分析(二)中可以知道我们的Controller的url映射关系也都已初始化好了,这个时候用户就可以向服务发送请求了,

当我们项目引入Spring MVC后,就不需要那么多Servlet了,所有请求全部由DispatcherServlet来代理并分发给Controller中的方法。

那么本片文章我们先一起看下DispatcherServlet的初始化方法init

当我们的第一次请求过来的时候,首先由Tomcat中的StandardWrapper#allocate来选择最终干活的Servlet类,并且判断这个Servlet类有没有调用init方法初始化过,没有的话就会去调用该方法,可以看到此时我们的Servlet类(instance)就是DispatcherServlet。

继续进入StandardWrapper#initServlet方法中,可以看到最终调用了Servlet的init方法,那么我们的DispatcherServlet初始化就从这里开始了

因为有参init方法DispatcherServlet没有实现,最终调用的是父类GenericServlet的init方法,GenericServlet#init(javax.servlet.ServletConfig),此时的this为DispatcherServlet,接下来调用无参的init方法。

调用DispatcherServlet的init方法,该方法由父类(FrameworkServlet)的父类HttpServletBean实现,init方法使用了模版方法设计模式,可以看到该方法最后调用了initServletBean方法,initServletBean方法由子类去实现。

进入initServletBean方法继续深入探索,该方法是由DispatcherServlet的父类FrameworkServlet实现的,我们去掉其他打印日志的逻辑代码,最终initServletBean只有这几行代码,也是使用了模版方法设计模式,其中initFrameworkServlet方法是一个空方法,留给子类扩展,目前我们的DispatcherServlet类并没有去实现它,所以不用看。我们主要看的核心逻辑就在initWebApplicationContext方法中。

我们继续进入initWebApplicationContext方法中

protected WebApplicationContext initWebApplicationContext() {
        // 先获取父类容器,用来设置当前容器的父容器。
        // 因为我的是SpringBoot项目,所以容器是AnnotationConfigServletWebServerApplicationContext
        WebApplicationContext rootContext =
                WebApplicationContextUtils.getWebApplicationContext(getServletContext());
        WebApplicationContext wac = null;

        if (this.webApplicationContext != null) {
            // 如果当前容器已经存在,就使用该容器
            // 我debug过来,容器仍是AnnotationConfigServletWebServerApplicationContext,同rootContext,是同一个对象
            wac = this.webApplicationContext;
            if (wac instanceof ConfigurableWebApplicationContext) {
                ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac;
                // 判断该容器是否刷新过,是AbstractApplicationContext的一个变量,调用refresh时设置为true
                // 即是否调用过refresh方法,这里直接跳出if判断,走下一个逻辑,因为springboot在启动的时候会调用
                if (!cwac.isActive()) {
                    // 如果父容器为空,设置父容器,该逻辑在这里不会走
                    if (cwac.getParent() == null) {
                        cwac.setParent(rootContext);
                    }
                    // 配置并刷新容器,该逻辑在这里不会走
                    configureAndRefreshWebApplicationContext(cwac);
                }
            }
        }
        if (wac == null) {
            //容器不存在,就通过FrameworkServlet的属性contextAttribute找容器
            wac = findWebApplicationContext();
        }
        if (wac == null) {
            // 容器仍不存在的话,创建一个容器
            wac = createWebApplicationContext(rootContext);
        }

        // refreshEventReceived默认为false
        // refreshEventReceived在FrameworkServlet的内部类ContextRefreshListener监听ContextRefreshedEvent事件设置为true的
        // 但在Springboot项目启动的时候并没有将该监听器添加进去,所以ContextRefreshListener的onApplicationEvent方法最终没有被调用
        // 该监听器可能是在哪里配置的,所以没有被加载进ContextRefreshedEvent监听器集合中,这里我们不深究,
        if (!this.refreshEventReceived) {
            synchronized (this.onRefreshMonitor) {
                // 模版方法,空实现,留给子类去覆写扩展
                onRefresh(wac);
            }
        }

        if (this.publishContext) {
            // Publish the context as a servlet context attribute.
            String attrName = getServletContextAttributeName();
            getServletContext().setAttribute(attrName, wac);
        }

        return wac;
    }

我们重点关注最后的onRefresh方法,该方法被子类DispatcherServlet覆写,用于初始化DispatcherServlet的功能组件,在DispatcherServlet的onRefresh方法中又调用了initStrategies方法,也是Spring代码的功能模块化体现,onRefresh是顶层逻辑,而同一个功能直接封装到单个方法中处理,增加可读性,后面onRefresh有其他功能逻辑处理就可以再写一个封装的方法,接下来我们在initStrategies方法就可以直观明了的看出也是这种写法。

在initStrategies方法中看到,每一个功能组件的初始化都封装了一个方法,代码结构一目了然,可读性大大增加,其实这个方法就是对DispatcherServlet中的成员变量组件进行初始化,在DispatcherServlet处理请求的过程中扮演着不同的角色,下面把初始化的代码贴上,都是一个套路,从容器中获取注册的bean,如果没有就设置一个默认的组件类

private void initMultipartResolver(ApplicationContext context) {
        try {
            // 从容器中直接获取该类,MULTIPART_RESOLVER_BEAN_NAME = "multipartResolver"
            // multipartResolver 为 org.springframework.web.multipart.support.StandardServletMultipartResolver
            this.multipartResolver = context.getBean(MULTIPART_RESOLVER_BEAN_NAME, MultipartResolver.class);
            if (logger.isTraceEnabled()) {
                logger.trace("Detected " + this.multipartResolver);
            }
            else if (logger.isDebugEnabled()) {
                logger.debug("Detected " + this.multipartResolver.getClass().getSimpleName());
            }
        }
        catch (NoSuchBeanDefinitionException ex) {
            // Default is no multipart resolver.
            this.multipartResolver = null;
            if (logger.isTraceEnabled()) {
                logger.trace("No MultipartResolver '" + MULTIPART_RESOLVER_BEAN_NAME + "' declared");
            }
        }
private void initLocaleResolver(ApplicationContext context) {
        try {
            // 从容器中直接获取该类,LOCALE_RESOLVER_BEAN_NAME = "localeResolver"
            // 在容器中没有获取到,进入catch中获取默认的组件
            // localeResolver 为 org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver
            this.localeResolver = context.getBean(LOCALE_RESOLVER_BEAN_NAME, LocaleResolver.class);
            if (logger.isTraceEnabled()) {
                logger.trace("Detected " + this.localeResolver);
            }
            else if (logger.isDebugEnabled()) {
                logger.debug("Detected " + this.localeResolver.getClass().getSimpleName());
            }
        }
        catch (NoSuchBeanDefinitionException ex) {
            // We need to use the default.
            this.localeResolver = getDefaultStrategy(context, LocaleResolver.class);
            if (logger.isTraceEnabled()) {
                logger.trace("No LocaleResolver '" + LOCALE_RESOLVER_BEAN_NAME +
                        "': using default [" + this.localeResolver.getClass().getSimpleName() + "]");
            }
        }
    }
private void initThemeResolver(ApplicationContext context) {
        try {
            // 从容器中直接获取该类,THEME_RESOLVER_BEAN_NAME = "themeResolver"
            // 在容器中没有获取到,进入catch中获取默认的组件
            // themeResolver 为 org.springframework.web.servlet.theme.FixedThemeResolver
            this.themeResolver = context.getBean(THEME_RESOLVER_BEAN_NAME, ThemeResolver.class);
            if (logger.isTraceEnabled()) {
                logger.trace("Detected " + this.themeResolver);
            }
            else if (logger.isDebugEnabled()) {
                logger.debug("Detected " + this.themeResolver.getClass().getSimpleName());
            }
        }
        catch (NoSuchBeanDefinitionException ex) {
            // We need to use the default.
            this.themeResolver = getDefaultStrategy(context, ThemeResolver.class);
            if (logger.isTraceEnabled()) {
                logger.trace("No ThemeResolver '" + THEME_RESOLVER_BEAN_NAME +
                        "': using default [" + this.themeResolver.getClass().getSimpleName() + "]");
            }
        }
    }
private void initHandlerMappings(ApplicationContext context) {
        this.handlerMappings = null;

        //从容器中获取所有实现HandlerMapping接口的实现类
        //容器中没有的话就设置为默认处理器
        if (this.detectAllHandlerMappings) {
            // Find all HandlerMappings in the ApplicationContext, including ancestor contexts.
            Map<String, HandlerMapping> matchingBeans =
                    BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
            if (!matchingBeans.isEmpty()) {
                this.handlerMappings = new ArrayList<>(matchingBeans.values());
                // We keep HandlerMappings in sorted order.
                AnnotationAwareOrderComparator.sort(this.handlerMappings);
            }
        }
        else {
            try {
                HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class);
                this.handlerMappings = Collections.singletonList(hm);
            }
            catch (NoSuchBeanDefinitionException ex) {
                // Ignore, we'll add a default HandlerMapping later.
            }
        }

        // Ensure we have at least one HandlerMapping, by registering
        // a default HandlerMapping if no other mappings are found.
        if (this.handlerMappings == null) {
            this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
            if (logger.isTraceEnabled()) {
                logger.trace("No HandlerMappings declared for servlet '" + getServletName() +
                        "': using default strategies from DispatcherServlet.properties");
            }
        }
    }
private void initHandlerAdapters(ApplicationContext context) {
        this.handlerAdapters = null;

        if (this.detectAllHandlerAdapters) {
            // Find all HandlerAdapters in the ApplicationContext, including ancestor contexts.
            Map<String, HandlerAdapter> matchingBeans =
                    BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerAdapter.class, true, false);
            if (!matchingBeans.isEmpty()) {
                this.handlerAdapters = new ArrayList<>(matchingBeans.values());
                // We keep HandlerAdapters in sorted order.
                AnnotationAwareOrderComparator.sort(this.handlerAdapters);
            }
        }
        else {
            try {
                HandlerAdapter ha = context.getBean(HANDLER_ADAPTER_BEAN_NAME, HandlerAdapter.class);
                this.handlerAdapters = Collections.singletonList(ha);
            }
            catch (NoSuchBeanDefinitionException ex) {
                // Ignore, we'll add a default HandlerAdapter later.
            }
        }

        // Ensure we have at least some HandlerAdapters, by registering
        // default HandlerAdapters if no other adapters are found.
        if (this.handlerAdapters == null) {
            this.handlerAdapters = getDefaultStrategies(context, HandlerAdapter.class);
            if (logger.isTraceEnabled()) {
                logger.trace("No HandlerAdapters declared for servlet '" + getServletName() +
                        "': using default strategies from DispatcherServlet.properties");
            }
        }
    }
private void initHandlerExceptionResolvers(ApplicationContext context) {
        //从容器中获取所有实现HandlerExceptionResolver接口的实现类
        //容器中没有的话就设置为默认的异常处理器
        this.handlerExceptionResolvers = null;

        if (this.detectAllHandlerExceptionResolvers) {
            // Find all HandlerExceptionResolvers in the ApplicationContext, including ancestor contexts.
            Map<String, HandlerExceptionResolver> matchingBeans = BeanFactoryUtils
                    .beansOfTypeIncludingAncestors(context, HandlerExceptionResolver.class, true, false);
            if (!matchingBeans.isEmpty()) {
                this.handlerExceptionResolvers = new ArrayList<>(matchingBeans.values());
                // We keep HandlerExceptionResolvers in sorted order.
                AnnotationAwareOrderComparator.sort(this.handlerExceptionResolvers);
            }
        }
        else {
            try {
                HandlerExceptionResolver her =
                        context.getBean(HANDLER_EXCEPTION_RESOLVER_BEAN_NAME, HandlerExceptionResolver.class);
                this.handlerExceptionResolvers = Collections.singletonList(her);
            }
            catch (NoSuchBeanDefinitionException ex) {
                // Ignore, no HandlerExceptionResolver is fine too.
            }
        }

        // Ensure we have at least some HandlerExceptionResolvers, by registering
        // default HandlerExceptionResolvers if no other resolvers are found.
        if (this.handlerExceptionResolvers == null) {
            this.handlerExceptionResolvers = getDefaultStrategies(context, HandlerExceptionResolver.class);
            if (logger.isTraceEnabled()) {
                logger.trace("No HandlerExceptionResolvers declared in servlet '" + getServletName() +
                        "': using default strategies from DispatcherServlet.properties");
            }
        }
    }
private void initRequestToViewNameTranslator(ApplicationContext context) {
        try {
            this.viewNameTranslator =
                    context.getBean(REQUEST_TO_VIEW_NAME_TRANSLATOR_BEAN_NAME, RequestToViewNameTranslator.class);
            if (logger.isTraceEnabled()) {
                logger.trace("Detected " + this.viewNameTranslator.getClass().getSimpleName());
            }
            else if (logger.isDebugEnabled()) {
                logger.debug("Detected " + this.viewNameTranslator);
            }
        }
        catch (NoSuchBeanDefinitionException ex) {
            // We need to use the default.
            this.viewNameTranslator = getDefaultStrategy(context, RequestToViewNameTranslator.class);
            if (logger.isTraceEnabled()) {
                logger.trace("No RequestToViewNameTranslator '" + REQUEST_TO_VIEW_NAME_TRANSLATOR_BEAN_NAME +
                        "': using default [" + this.viewNameTranslator.getClass().getSimpleName() + "]");
            }
        }
    }
private void initViewResolvers(ApplicationContext context) {
        this.viewResolvers = null;

        if (this.detectAllViewResolvers) {
            // Find all ViewResolvers in the ApplicationContext, including ancestor contexts.
            Map<String, ViewResolver> matchingBeans =
                    BeanFactoryUtils.beansOfTypeIncludingAncestors(context, ViewResolver.class, true, false);
            if (!matchingBeans.isEmpty()) {
                this.viewResolvers = new ArrayList<>(matchingBeans.values());
                // We keep ViewResolvers in sorted order.
                AnnotationAwareOrderComparator.sort(this.viewResolvers);
            }
        }
        else {
            try {
                ViewResolver vr = context.getBean(VIEW_RESOLVER_BEAN_NAME, ViewResolver.class);
                this.viewResolvers = Collections.singletonList(vr);
            }
            catch (NoSuchBeanDefinitionException ex) {
                // Ignore, we'll add a default ViewResolver later.
            }
        }

        // Ensure we have at least one ViewResolver, by registering
        // a default ViewResolver if no other resolvers are found.
        if (this.viewResolvers == null) {
            this.viewResolvers = getDefaultStrategies(context, ViewResolver.class);
            if (logger.isTraceEnabled()) {
                logger.trace("No ViewResolvers declared for servlet '" + getServletName() +
                        "': using default strategies from DispatcherServlet.properties");
            }
        }
    }
private void initFlashMapManager(ApplicationContext context) {
        try {
            this.flashMapManager = context.getBean(FLASH_MAP_MANAGER_BEAN_NAME, FlashMapManager.class);
            if (logger.isTraceEnabled()) {
                logger.trace("Detected " + this.flashMapManager.getClass().getSimpleName());
            }
            else if (logger.isDebugEnabled()) {
                logger.debug("Detected " + this.flashMapManager);
            }
        }
        catch (NoSuchBeanDefinitionException ex) {
            // We need to use the default.
            this.flashMapManager = getDefaultStrategy(context, FlashMapManager.class);
            if (logger.isTraceEnabled()) {
                logger.trace("No FlashMapManager '" + FLASH_MAP_MANAGER_BEAN_NAME +
                        "': using default [" + this.flashMapManager.getClass().getSimpleName() + "]");
            }
        }
    }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值