Spring MVC源码解析

image.png

Spring Mvc结构解析

上图是Dispatcher Servlet的结构图,从图中可以清楚的看到Dispatcher Servlet的继承链,下面我们将基于Spring4.1.6揭开Spring MVC的神秘面纱。

初始化过程

我们都知道,Java中初始化顺序是:

  1. 初始化父类静态变量(静态代码块,静态变量,静态方法,需要注意的是main方法也是静态的)
  2. 初始化子类静态变量(范围同父类)
  3. 初始化父类普通成员变量及方法
  4. 调用父类构造方法
  5. 初始化子类普通成员变量及方法
  6. 调用子类构造方法

那么,在Dispatcher Servlet初始化的时候也是严格按照这个顺序来执行的。我们分别来看看在不同阶段都做了些什么。

HttpServletBean初始化过程关键代码

   
    @Override
    public final void init() throws ServletException {
        
        //  从spring的配置文件中读取servlet的Init-Param。即spring配置文件路径等关键配置
        try {
            PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties);
            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) {
            logger.error("Failed to set bean properties on servlet '" + getServletName() + "'", ex);
            throw ex;
        }

        // 调用frameworkServlet的方法初始化
        initServletBean();

        
    }

FrameworkServlet初始化过程关键代码

    @Override
    protected final void initServletBean() throws ServletException { 
            this.webApplicationContext = initWebApplicationContext(); 
        }
    
    protected WebApplicationContext initWebApplicationContext() {
        WebApplicationContext rootContext =
                WebApplicationContextUtils.getWebApplicationContext(getServletContext());
        WebApplicationContext wac = null;

        if (wac == null) {
            // 在这里初始化Spring MVC的context,并将Spring MVC的context和Servlet Context绑定
            wac = createWebApplicationContext(rootContext);
        }
        return wac;
    }

    protected WebApplicationContext createWebApplicationContext(ApplicationContext parent) {
        Class contextClass = getContextClass();
         // 通过反射new一个空的context对象返回
        ConfigurableWebApplicationContext wac =
                (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);
        wac.setEnvironment(getEnvironment());
        wac.setParent(parent);
        wac.setConfigLocation(getContextConfigLocation());
        //  在这里会调用onRefreah方法,初始化Dispatcher Servlet的9大策略
        configureAndRefreshWebApplicationContext(wac);

        return wac;
    }

    protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac) {
        if (ObjectUtils.identityToString(wac).equals(wac.getId())) {
            // The application context id is still set to its original default value
            // -> assign a more useful id based on available information
            if (this.contextId != null) {
                wac.setId(this.contextId);
            }
            else {
                wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX +
                        ObjectUtils.getDisplayString(getServletContext().getContextPath()) + "/" + getServletName());
            }
        }
        // 为web application context设置基本属性
        wac.setServletContext(getServletContext());
        wac.setServletConfig(getServletConfig());
        wac.setNamespace(getNamespace());
        wac.addApplicationListener(new SourceFilteringListener(wac, new ContextRefreshListener()));

        ConfigurableEnvironment env = wac.getEnvironment();
        if (env instanceof ConfigurableWebEnvironment) {
            ((ConfigurableWebEnvironment) env).initPropertySources(getServletContext(), getServletConfig());
        }

        postProcessWebApplicationContext(wac);
        applyInitializers(wac);
        // 关键,这里会刷新整个context,调用Dispatcher Servlet的onRefreah方法。初始化一系列Resolvers
        wac.refresh();
    }

DispatcherServlet初始化过程关键代码

    /**
     * This implementation calls {@link #initStrategies}.
     */
    @Override
    protected void onRefresh(ApplicationContext context) {
        initStrategies(context);
    }

    /**
     * Initialize the strategy objects that this servlet uses.
     * 

May be overridden in subclasses in order to initialize further strategy objects. */ protected void initStrategies(ApplicationContext context) { initMultipartResolver(context); initLocaleResolver(context); initThemeResolver(context); // 寻找配置的HandlerMapping,下篇文章我们会继续分析这里的详细过程。是url映射controller的关键, // 默认是RequestMappgingHandlerMapping和BeanNameUrlHandlerMapping,这些HandlerMapping会在spring context初始化的时候初始化。 initHandlerMappings(context); // 寻找配置的适配器,默认是 // RequestMappingHandlerAdapter,HttpRequestHandlerAdapter,SimpleControllerHandlerAdapter这三种 initHandlerAdapters(context); initHandlerExceptionResolvers(context); initRequestToViewNameTranslator(context); initViewResolvers(context); initFlashMapManager(context); }

从上面的关键部分代码可以看出Spring MVC在启动时的的大概流程,大致了解Spring MVC都做了什么。后续会继续分析请求到达Dispatcher Servlet后是如何找到对应的controller以及参数封装,最后再到数据返回等流程的详细过程。

你可能感兴趣的:(Spring MVC源码解析)