SpringMVC中的DispatcherServlet初始化流程详解

 更新时间:2023年12月02日 08:58:14   作者:nuomizhende45  
这篇文章主要介绍了SpringMVC中的DispatcherServlet初始化流程详解,DispatcherServlet这个前端控制器是一个Servlet,所以生命周期和普通的Servlet是差不多的,在一个Servlet初始化的时候都会调用该Servlet的init()方法,需要的朋友可以参考下

DispatcherServlet初始化流程

分析一下DispatcherServlet这个前端控制器的启动和初始化的整个过程

通过前面分析已经知道了DispatcherServlet这个前端控制器是一个Servlet了,所以生命周期和普通的Servlet是差不多的,在一个Servlet初始化的时候都会调用该Servlet的init()方法。下面这个是DispatcherSerlvet父类HttpServletBean中的init方法。

我们发现这里会调用initServletBean()方法进行具体的初始化,而该类这个方法的具体实现这是其子类FrameworkServlet。主要逻辑就是初始化上下文。

    protected final void initServletBean() throws ServletException {
        this.getServletContext().log("Initializing Spring " + this.getClass().getSimpleName() + " \'" + this.getServletName() + "\'");
        if(this.logger.isInfoEnabled()) {
            this.logger.info("Initializing Servlet \'" + this.getServletName() + "\'");
        }
        long startTime = System.currentTimeMillis();
        try {
            /**
            这里初始化上下文
            **/
            this.webApplicationContext = this.initWebApplicationContext();
            this.initFrameworkServlet();
        } catch (RuntimeException | ServletException var4) {
            this.logger.error("Context initialization failed", var4);
            throw var4;
        }
        if(this.logger.isDebugEnabled()) {
            String value = this.enableLoggingRequestDetails?"shown which may lead to unsafe logging of potentially sensitive data":"masked to prevent unsafe logging of potentially sensitive data";
            this.logger.debug("enableLoggingRequestDetails=\'" + this.enableLoggingRequestDetails + "\': request parameters and headers will be " + value);
        }
        if(this.logger.isInfoEnabled()) {
            this.logger.info("Completed initialization in " + (System.currentTimeMillis() - startTime) + " ms");
        }
    }

继续跟进initWebApplicationContext这个方法

   protected WebApplicationContext initWebApplicationContext() {
        /**
        若webApplicationContext不为空的时候从SerlvetContext去出根上下文作为它的双亲上下文
        **/
        WebApplicationContext rootContext = WebApplicationContextUtils.getWebApplicationContext(this.getServletContext());
        WebApplicationContext wac = null;
        if(this.webApplicationContext != null) {
            wac = this.webApplicationContext;
            if(wac instanceof ConfigurableWebApplicationContext) {
                ConfigurableWebApplicationContext attrName = (ConfigurableWebApplicationContext)wac;
                if(!attrName.isActive()) {
                    if(attrName.getParent() == null) {
                        attrName.setParent(rootContext);
                    }
                    this.configureAndRefreshWebApplicationContext(attrName);
                }
            }
        }
        if(wac == null) {
            wac = this.findWebApplicationContext();
        }
        if(wac == null) {
            wac = this.createWebApplicationContext(rootContext);
        }
        //这里通过调用子类DispatcherServlet实现的onRefresh方法
        if(!this.refreshEventReceived) {
            this.onRefresh(wac);
        }
        //把当前建立好的上下文存到ServletContext里面去
        if(this.publishContext) {
            String attrName1 = this.getServletContextAttributeName();
            this.getServletContext().setAttribute(attrName1, wac);
        }
        return wac;
    }

继续跟进这个onRefresh方法,发现是一个模板方法,其具体实现子类则是DispatcherServlet。

跳转到DispatcherServlet中查看该方法,发现里面又调用了initStrategies这个方法

这时我们就大致了解了,这个DispatcherServlet初始化的过程了,首先DispatcherServlet持有者一个以自己的Servlet名字命名的Ioc容器,也就是我们看到的WebApplicationContext对象,这个Ioc容器建立起来后,与Web容器相关的各种配置加载也都完成了。并且这个初始化的入口就是由最初的HttpServletBean的init方法触发的,因为这个HttpServletBean是HttpServlet的子类,接下来HttpServletBean的子类FrameworkServlet对Ioc容器进行了初始化操作,并且利用onRefresh方法回调了DispatcherServlet中的initStrategies方法,在这个方法里启动了整个SpringMVC框架了,我们继续往下面跟进看看。

    
//该属性默认为true
    private boolean detectAllHandlerMappings = true;
private void initHandlerMappings(ApplicationContext context) {
        this.handlerMappings = null;
        //这里面的逻辑是从导入所有的HandlerMappingBean,这些Bean有可能存在与双亲容器中,也可能在DispathcerServlet持有的容器的,这里detectAllHandlerMappings默认为true,默认从所有容器中导入
        if(this.detectAllHandlerMappings) {
            Map hm = BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
            if(!hm.isEmpty()) {
                this.handlerMappings = new ArrayList(hm.values());
                AnnotationAwareOrderComparator.sort(this.handlerMappings);
            }
        } else {
            //否则通过直接通过名字从当前的IOC容器中通过getBean方法获取handlerMapping
            try {
                HandlerMapping hm1 = (HandlerMapping)context.getBean("handlerMapping", HandlerMapping.class);
                this.handlerMappings = Collections.singletonList(hm1);
            } catch (NoSuchBeanDefinitionException var3) {
                ;
            }
        }
        //如果还是没有找到hadlerMapping就需要设定默认的handlerMappings了
        if(this.handlerMappings == null) {
            this.handlerMappings = this.getDefaultStrategies(context, HandlerMapping.class);
            if(this.logger.isTraceEnabled()) {
                this.logger.trace("No HandlerMappings declared for servlet \'" + this.getServletName() + "\': using default strategies from DispatcherServlet.properties");
            }
        }
    }

下面是用debugger看看它究竟获取了那些handlerMapping,如下:7个handlerMapping

除了这个初始化handlerMapping的initHandlerMapping方法,当然还初始化了很多东西,如支持国际化的LocalResolver以及视图生成的ViewResolver等的初始化过程,其余的有兴趣自己跟着看一下,这里就不细跟了。到这里我们就知道了整个DispatcherServlet的初始化的大体流程了。

到此这篇关于SpringMVC中的DispatcherServlet初始化流程详解的文章就介绍到这了,更多相关DispatcherServlet初始化流程内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Java 8 对 ArrayList 元素进行排序的操作方法

    Java 8 对 ArrayList 元素进行排序的操作方法

    Java8提供了多种方式对ArrayList元素进行排序,包括使用Collections.sort()方法、Collections.reverseOrder()实现降序排序、使用Lambda表达式进行自定义排序、使用StreamAPI对ArrayList进行排序及按对象属性排序,本文通过示例代码介绍的非常详细,感兴趣的朋友一起看看吧
    2024-11-11
  • Java 时间日期详细介绍及实例

    Java 时间日期详细介绍及实例

    这篇文章主要介绍了Java 时间日期详细介绍及实例的相关资料,需要的朋友可以参考下
    2017-01-01
  • SpringBoot实现热部署详解

    SpringBoot实现热部署详解

    SpringBoot热部署是一种开发时极为有用的功能,它能够让开发人员在代码修改后无需手动重启应用程序就能立即看到变化的效果,所以我本文就给打击介绍一下为什么要使用热部署以及实现热部署的方式,需要的朋友可以参考下
    2023-07-07
  • Java函数式编程(三):列表的转化

    Java函数式编程(三):列表的转化

    这篇文章主要介绍了Java函数式编程(二):列表的转化,lambda表达式不仅能帮助我们遍历集合,并且可以进行集合的转化,需要的朋友可以参考下
    2014-09-09
  • 详解maven配置多仓库的方法示例

    详解maven配置多仓库的方法示例

    这篇文章主要介绍了详解maven配置多仓库的方法示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-08-08
  • Java面向对象之包装类的用途与实际使用

    Java面向对象之包装类的用途与实际使用

    所谓包装类,就是能够直接将简单类型的变量表示为一个类,在执行变量类型的相互转换时,我们会大量使用这些包装类,本文我们来深入探索一下Java包装类的相关内容,需要的朋友可以参考下
    2022-03-03
  • SpringCloud实战之Feign声明式服务调用

    SpringCloud实战之Feign声明式服务调用

    这篇文章主要介绍了SpringCloud实战之Feign声明式服务调用,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-05-05
  • Java中Object类的常用方法小结

    Java中Object类的常用方法小结

    Java Object 类是所有类的父类,位于 java.lang 包中,本文为大家整理了一些Object类的常用方法,感兴趣的小伙伴可以跟随小编一起学习一下
    2025-01-01
  • 详解Java使用双异步后如何保证数据一致性

    详解Java使用双异步后如何保证数据一致性

    这篇文章主要为大家详细介绍了Java使用双异步后如何保证数据一致性,文中的示例代码讲解详细,具有一定的借鉴价值,有需要的小伙伴可以了解下
    2024-01-01
  • Java批量操作如何提升ORM框架的批处理性能

    Java批量操作如何提升ORM框架的批处理性能

    本文介绍的批量插入、更新、删除和读取优化技术,以及性能监控与调优方法,为开发者提供了全面的批处理性能优化思路,感兴趣的朋友一起看看吧
    2025-05-05

最新评论