SpringMVC源码分析(二)—————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的初始化的大体流程了。

你可能感兴趣的:(源码分析)