1.整体结构

    SpringMvc中三个主要的类,分别为HttpServletBean,FrameworkServlet,DispatcherServlet。

    HttpServletBean直接继承HttpServlet,   FrameworkServlet继承了HttpServletBean,DispatcherServlet继承了FrameworkServlet。

    过程是这样的,启动tomcat的时候。

    1.首先会调用HttpServletBean的init方法。

    2.调用initServletBean方法,initServletBean在FrameworkServlet中进行了重写。

    3.initServletBean方法中调用本类的initWebApplicationContext方法进行初始化容器的工作。

    4. 初始化中又调用了onRefrsh方法,onRefrsh方法在DispatcherServlet进行重写,对SpringMvc的九大组件进行了初始化。

    接下来看相关方法的核心代码。

/**
     * HttpServletBean,因为继承了HttpServlet,又在web.xml中配置了,所以tomcat在启动的时候会执行该类的init方法。
     * 完全可以把这个类当做一个Servlet来理解,事实也是如此,因为继承了HttpServlet。
     */
    @Override
    public final void init() throws ServletException {
        try {
            //读取Servlet配置的参数并封装到pvs变量中(web.xml配置的参数),requiredProperties为必须参数,没有配置则报异常
            PropertyValues pvs = new HttpServletBean.ServletConfigPropertyValues(getServletConfig(), this.requiredProperties);
            //BeanWrapper为spring中的工具类,将一个对象封装为BeanWrapper,可操作对象的属性
            //在这里,这个this,或者bw对象为DispatcherServlet,可通过断点来看到
            BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);
            ResourceLoader resourceLoader = new ServletContextResourceLoader(getServletContext());
            bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, getEnvironment()));
            initBeanWrapper(bw);
            //将获取到的配置参数设置到DispatcherServlet
            bw.setPropertyValues(pvs, true);
        }
        catch (BeansException ex) {
            logger.error("Failed to set bean properties on servlet '" + getServletName() + "'", ex);
            throw ex;
        }
        //模板方法,在FrameworkServlet中进行了实现,子类初始化入口
        initServletBean();
    }

    接下来看一下FrameworkServlet中的initServletBean。

        

/**
     * FrameworkServlet中的initServletBean方法
     * 这里面主要的代码只有两句,日志代码已经去掉
     */
    @Override
    protected final void initServletBean() throws ServletException {
        try {
            //核心代码,初始化WebApplicationContext,WebApplicationContext为SpringMvc容器
            this.webApplicationContext = initWebApplicationContext();
            //模板方法,空实现
            initFrameworkServlet();
        }
        catch (ServletException ex) {
            this.logger.error("Context initialization failed", ex);
            throw ex;
        }
        catch (RuntimeException ex) {
            this.logger.error("Context initialization failed", ex);
            throw ex;
        }
    }

    FrameworkServlet中的initWebApplicationContext方法

    在该方法中主要做了三件事,获取spring根容器,2.获取webApplicationContext并根据情况调用onRefresh方法,3.将    webApplicationContext设置到ServletContext中。

/**
     * FrameworkServlet中的initWebApplicationContext
     * 省略了日志代码和原有注释
     * @return
     */
    protected WebApplicationContext initWebApplicationContext() {
        //获取spring根容器rootContext
        WebApplicationContext rootContext =
                WebApplicationContextUtils.getWebApplicationContext(getServletContext());
        WebApplicationContext wac = null;
        //如果在构造中初始化了webApplicationContext则会执行该if里面的逻辑
        if (this.webApplicationContext != null) {
            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中获取WebApplicationContext
            wac = findWebApplicationContext();
        }
        if (wac == null) {
            //如果没有获取到则创建一个WebApplicationContext
            wac = createWebApplicationContext(rootContext);
        }
        //boolean类型变量,默认为false,如果为false则执行onRefresh方法
        //如果执行了上面的createWebApplicationContext方法,则会将refreshEventReceived设置为true
        //因为在createWebApplicationContext中调用了onRefresh方法,所以会将标识设置为true
        if (!this.refreshEventReceived) {
            onRefresh(wac);
        }
        if (this.publishContext) {
            //将WebApplicationContext保存到ServletContext中
            String attrName = getServletContextAttributeName();
            getServletContext().setAttribute(attrName, wac);
        }
        return wac;
    }

    DispatcherServlet中的onRefresh方法


/**
     * DispatcherServlet中的onRefresh方法
     * 方法比较简单,调用了initStrategies
     * 在initStrategies中初始化了SpringMvc的九大组件
     */
    @Override
    protected void onRefresh(ApplicationContext context) {
        initStrategies(context);
    }

    /**
     * 简单说明一下九大组件,后续详细分析
     */
    protected void initStrategies(ApplicationContext context) {
        //文件上传解析器
        initMultipartResolver(context);
        //国际化资源解析器
        initLocaleResolver(context);
        //主题解析器(用于更换css,图片等)
        initThemeResolver(context);
        //解析能够处理请求的方法
        initHandlerMappings(context);
        //具体处理请求时使用的适配器(Adapter执行某个Handler)
        initHandlerAdapters(context);
        //异常解析器
        initHandlerExceptionResolvers(context);
        //获取默认视图名字的工具
        initRequestToViewNameTranslator(context);
        //视图解析器
        initViewResolvers(context);
        //Redirect中传递参数的工具
        initFlashMapManager(context);
    }

到这就结束了,简单的介绍了一下SpringMvc的基本构成以及初始化的过程,当然具体过程并不是这么简单,这里只是说一下大致流程,可以根据上述步骤打断点跟一下SpringMvc的初始化过程,在几个重要方法打断点即可,后续会对九大组件进行一个简单的解析,希望对大家有所帮助。