SpringMVC 源码解析

2022-10-17,,

前言

        年初面试时接触到一道面试题,在聊到springmvc时提到了springmvc的开发者为何要设计父子容器呢,又或者说是父子容器的设计有什么更实际的作用呢?
         首先要理解对于一个web应用,当其部署在web容器上时,容器会为其提供一个全局上下文环境servletcontext,这个上下文环境将为后续的spring提供宿主环境。

springmvc工作流程

dispatcherservlet上下文继承关系

springmvc设计的父子容器

父子容器配置文件

--在web.xml中配置,两个重要的xml:applicationcontext.xml和springmvc-conf.xml
<context-param>
    <param-name>contextconfiglocation</param-name>
    <param-value>classpath*:applictioncontext.xml</param-value>
</context-param>
<listener>
   <listener-class>org.springframework.web.context.contextloaderlistener</listener-class>
</listener>
  
<servlet>
    <servlet-name>dispatcher-servlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.dispatcherservlet</servlet-class>
    <init-param>
      <param-name>contextconfiglocation</param-name>
      <param-value>classpath*:springmvc-conf.xml</param-value>
    </init-param>
</servlet>
  
<servlet-mapping>
  <servlet-name>dispatcher-servlet</servlet-name>
  <url-pattern>/*</url-pattern>
</servlet-mapping>

父子容器的设计目的

     根据springmvc的官方解释,父(根)容器主要包括一些基础脚手架的bean,比如pool、datasource、dao、service。目的是在不同的servlet实例之间共享。这些不同的bean可以在子容器中重写。
     而子容器主要包括一些controller、view等一些web相关的bean。 

dispatcherservlet源码分析

     既然springmvc中同时包含spring容器和springmvc容器,那么这两个容器都是在什么时候初始化呢?

根容器初始化

      首先,根容器是通过servletcontext监听器进行创建,默认的监听器为contextloaderlistener,当web应用启动时,会调用监听器的contextinitialized方法。
      那么根容器的初始化就从contextloaderlistener类说起吧,,spring官方对该类的描述是启动监听器去启动和关闭spring的root webapplicationcontext(翻译的实在有点蹩脚)。
     

public class contextloaderlistener extends contextloader implements servletcontextlistener {
    public contextloaderlistener() {
    }

    public contextloaderlistener(webapplicationcontext context) {
        super(context);
    }

    //===初始化root webapplicationcontext===
    @override
    public void contextinitialized(servletcontextevent event) {
        initwebapplicationcontext(event.getservletcontext());
    }

    @override
    public void contextdestroyed(servletcontextevent event) {
        closewebapplicationcontext(event.getservletcontext());
        contextcleanuplistener.cleanupattributes(event.getservletcontext());
    }
}

   

//contextloader.java
public webapplicationcontext initwebapplicationcontext(servletcontext servletcontext) {
    //初始化spring容器时如果发现servlet 容器中已存在根spring容根器则抛出异常,证明rootwebapplicationcontext只能有一个。
    if (servletcontext.getattribute(webapplicationcontext.root_web_application_context_attribute) != null) {
        throw new illegalstateexception(
                "cannot initialize context because there is already a root application context present - " +
                "check whether you have multiple contextloader* definitions in your web.xml!");
    }

    try {
        //创建webapplicationcontext实例
        if (this.context == null) {
            this.context = createwebapplicationcontext(servletcontext);
        }
        if (this.context instanceof configurablewebapplicationcontext) {
            configurablewebapplicationcontext cwac = (configurablewebapplicationcontext) this.context;
            if (!cwac.isactive()) {
                if (cwac.getparent() == null) {
                    applicationcontext parent = loadparentcontext(servletcontext);
                    cwac.setparent(parent);
                }
                //配置webapplicationcontext
                configureandrefreshwebapplicationcontext(cwac, servletcontext);
            }
        }
        
        /**
           把生成的webapplicationcontext设置成root webapplicationcontext。保存在servletcontext上下文中。
           下一步初始化mvc applicationcontext时需要从servletcontext取出根上下文作为其父上下文。
        **/ 
        servletcontext.setattribute(webapplicationcontext.root_web_application_context_attribute, this.context);

        classloader ccl = thread.currentthread().getcontextclassloader();
        if (ccl == contextloader.class.getclassloader()) {
            currentcontext = this.context;
        }
        else if (ccl != null) {
            currentcontextperthread.put(ccl, this.context);
        }
        
        return this.context;
    }
    catch (runtimeexception | error ex) {
        servletcontext.setattribute(webapplicationcontext.root_web_application_context_attribute, ex);
        throw ex;
    }
}

      以上代码主要完成两个功能:创建实例webapplicationcontext实例、把所创建的webapplicationcontext设置为根上下文,也就是设置成为root_web_application_context_attribute的值。

mvc容器初始化 

      大家知道servlet生命周期都是从init方法开始,desctory方法结束,由jvm负责垃圾回收。而dispatcherservlet也是一个普通的servlet,先看一下dispatcherservlet的继承关系图,对整个继承关系有个了解。

   既然说起servlet,那就从servlet的初始化(init)方法入手

//httpservletbean.java
@override
public final void init() throws servletexception {

    propertyvalues pvs = new servletconfigpropertyvalues(getservletconfig(), this.requiredproperties);
    if (!pvs.isempty()) {
        try {
            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) {
            throw ex;
        }
    }

    //交给子类重写
    initservletbean();
}

//frameworkservlet.java
@override
protected final void initservletbean() throws servletexception {
    try {
        this.webapplicationcontext = initwebapplicationcontext();
        initframeworkservlet();
    }
    catch (servletexception | runtimeexception ex) {
        throw ex;
    }
}

//frameworkservlet.java
//初始化mvc容器
protected webapplicationcontext initwebapplicationcontext() {
    //从servletcontext取出根上下文
    webapplicationcontext rootcontext =
            webapplicationcontextutils.getwebapplicationcontext(getservletcontext());
    webapplicationcontext wac = null;

    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) {
        wac = findwebapplicationcontext();
    }
    
    //如果还没有webapplicatioincontext,创建webapplicationcontext
    if (wac == null) {
        wac = createwebapplicationcontext(rootcontext);
    }

    //子类自定义对servlet子上下文后续操作,在dispatcherservlet中实现
    if (!this.refresheventreceived) {
        synchronized (this.onrefreshmonitor) {
            //执行子类扩展方法onrefresh,在dispatcherservlet内初始化所有web相关组件
            onrefresh(wac);
        }
    }

    //发布servlet子上下文到servletcontext
    if (this.publishcontext) {
        string attrname = getservletcontextattributename();
        //将servlet子上下文以org.springframework.web.servlet.frameworkservlet.context. + servletname的属性名称注册到servletcontext中
        getservletcontext().setattribute(attrname, wac);
    }

    return wac;
}

protected webapplicationcontext createwebapplicationcontext(@nullable webapplicationcontext parent) {
    return createwebapplicationcontext((applicationcontext) parent);
}

protected webapplicationcontext createwebapplicationcontext(@nullable applicationcontext parent) {
    //获取webapplicationcontext实现类,此处其实就是xmlwebapplicationcontext
    class<?> contextclass = getcontextclass();
    if (!configurablewebapplicationcontext.class.isassignablefrom(contextclass)) {
        throw new applicationcontextexception("fatal initialization error in servlet with name '" + getservletname() +
                "': custom webapplicationcontext class [" + contextclass.getname() +
                "] is not of type configurablewebapplicationcontext");
    }
    
    //生成xmlwebapplicationcontext实例
    configurablewebapplicationcontext wac =
            (configurablewebapplicationcontext) beanutils.instantiateclass(contextclass);

    wac.setenvironment(getenvironment());
    //设置根容器为父容器 
    wac.setparent(parent);
    string configlocation = getcontextconfiglocation();
    if (configlocation != null) {
        //设置配置文件
        wac.setconfiglocation(configlocation);
    }
    
    //配置webapplicationcontext
    configureandrefreshwebapplicationcontext(wac);

    return wac;
}

protected void configureandrefreshwebapplicationcontext(configurablewebapplicationcontext wac) {
    if (objectutils.identitytostring(wac).equals(wac.getid())) {
        if (this.contextid != null) {
            wac.setid(this.contextid);
        }
        else {
            wac.setid(configurablewebapplicationcontext.application_context_id_prefix + objectutils.getdisplaystring(getservletcontext().getcontextpath()) + '/' + getservletname());
        }
    }

    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);
    
    //开始处理bean
    wac.refresh();
}

      上面的关键代码都在frameworkservlet类中,有几个关键点:取除根上下文,创建子上下文并设置父上下文,完成刷新,把子上下文发布到servletcontext中。 到这里可以说子容器(子上下文)已经创建完成。 并把其他初始化web组件的相关工作交给onrefresh方法完成,由dispatcherservlet来重写onrefresh方法,这就又回到了我们熟悉的initstrategies方法。

web组件初始化

 

@override
protected void onrefresh(applicationcontext context) {
    initstrategies(context);
}

protected void initstrategies(applicationcontext context) {
    //文件上传解析器
    initmultipartresolver(context);
    
    //本地化解析器
    initlocaleresolver(context);
    
    //主题解析器
    initthemeresolver(context);
    
    //处理器映射器(url和controller方法的映射)
    inithandlermappings(context);
    
    //处理器适配器(实际执行controller方法)
    inithandleradapters(context);
    
    //处理器异常解析器
    inithandlerexceptionresolvers(context);
    
    //requesttoviewname解析器
    initrequesttoviewnametranslator(context);
    
    //视图解析器(视图的匹配和渲染)
    initviewresolvers(context);
    
    //flashmap管理者
    initflashmapmanager(context);
}

             这里我们主要关注一下三个重要组件:handlermapping、handleradapter、viewresolver。分析这3个组件之前,我们先看一下我们的springmvc-conf.xml配置文件,mvc的配置文件中,我们配置了两行代码:

<context:component-scan base-package="com.zhangfei"/>
<mvc:annotation-driven>

      第二行代码主要是添加了默认的handlemapping,viewresolver,handleadapter。我们看看annotation-driven的源码定义,根据spring自定义schema定义,我们找到如下代码,如图所示:

该文件就一行代码:

http\://www.springframework.org/schema/mvc=org.springframework.web.servlet.config.mvcnamespacehandler
//mvc所有的标签解析器都定义在此
public class mvcnamespacehandler extends namespacehandlersupport {
    @override
    public void init() {
        registerbeandefinitionparser("annotation-driven", new annotationdrivenbeandefinitionparser());
        registerbeandefinitionparser("default-servlet-handler", new defaultservlethandlerbeandefinitionparser());
        registerbeandefinitionparser("interceptors", new interceptorsbeandefinitionparser());
        registerbeandefinitionparser("resources", new resourcesbeandefinitionparser());
        registerbeandefinitionparser("view-controller", new viewcontrollerbeandefinitionparser());
        registerbeandefinitionparser("redirect-view-controller", new viewcontrollerbeandefinitionparser());
        registerbeandefinitionparser("status-controller", new viewcontrollerbeandefinitionparser());
        registerbeandefinitionparser("view-resolvers", new viewresolversbeandefinitionparser());
        registerbeandefinitionparser("tiles-configurer", new tilesconfigurerbeandefinitionparser());
        registerbeandefinitionparser("freemarker-configurer", new freemarkerconfigurerbeandefinitionparser());
        registerbeandefinitionparser("groovy-configurer", new groovymarkupconfigurerbeandefinitionparser());
        registerbeandefinitionparser("script-template-configurer", new scripttemplateconfigurerbeandefinitionparser());
        registerbeandefinitionparser("cors", new corsbeandefinitionparser());
    }
}

那么通过分析annotationdrivenbeandefinitionparser类,主要完成以下三大组件的装配工作:

初始化处理器映射器

private void inithandlermappings(applicationcontext context) {
    this.handlermappings = null;

    //这里detectallhandlermappings默认值为true,可以通过配置文件设置为false
    if (this.detectallhandlermappings) {
        //从上下文(包含父上下文)中查找所有handlermapping实现类
        map<string, handlermapping> matchingbeans =
                beanfactoryutils.beansoftypeincludingancestors(context, handlermapping.class, true, false);
        if (!matchingbeans.isempty()) {
            this.handlermappings = new arraylist<>(matchingbeans.values());
            annotationawareordercomparator.sort(this.handlermappings);
        }
    }
    else {
        try {
            //这里只取固定的bean
            handlermapping hm = context.getbean(handler_mapping_bean_name, handlermapping.class);
            this.handlermappings = collections.singletonlist(hm);
        }
        catch (nosuchbeandefinitionexception ex) {
            
        }
    }
    
    /***
      确保至少有一个handlermapping,如果没能找到,注册一个默认的
      默认规则在dispatcherservlet.properties中,这里也就是取beannameurlhandlermapping、requestmappinghandlermapping
    ***/
    if (this.handlermappings == null) {
        this.handlermappings = getdefaultstrategies(context, handlermapping.class);     
    }
}

初始化处理器适配器

private void inithandleradapters(applicationcontext context) {
    this.handleradapters = null;

    if (this.detectallhandleradapters) {
        //从上下文(包括父上下文)中查找所有handleradapter实现类
        map<string, handleradapter> matchingbeans =beanfactoryutils.beansoftypeincludingancestors(context, handleradapter.class, true, false);
        if (!matchingbeans.isempty()) {
            this.handleradapters = new arraylist<>(matchingbeans.values());
            annotationawareordercomparator.sort(this.handleradapters);
        }
    }
    else {
        try {
            //这里取bean名字为handleradapter,类型为handleradapter的处理器适配器
            handleradapter ha = context.getbean(handler_adapter_bean_name, handleradapter.class);
            this.handleradapters = collections.singletonlist(ha);
        }
        catch (nosuchbeandefinitionexception ex) {
            
        }
    }
    
    /**
    如果没找到,则从默认规则里取出指定的三个实现类:httprequesthandleradapter、simplecontrollerhandleradapter、requestmappinghandleradapter
    **/
    if (this.handleradapters == null) {
        this.handleradapters = getdefaultstrategies(context, handleradapter.class);     
    }
}

初始化试图解析器

private void initviewresolvers(applicationcontext context) {
    this.viewresolvers = null;

    if (this.detectallviewresolvers) {
        //从上下文(包括父上下文)中查找所有viewresolver实现类
        map<string, viewresolver> matchingbeans =beanfactoryutils.beansoftypeincludingancestors(context, viewresolver.class, true, false);
        if (!matchingbeans.isempty()) {
            this.viewresolvers = new arraylist<>(matchingbeans.values());
            annotationawareordercomparator.sort(this.viewresolvers);
        }
    }
    else {
        try {
            viewresolver vr = context.getbean(view_resolver_bean_name, viewresolver.class);
            this.viewresolvers = collections.singletonlist(vr);
        }
        catch (nosuchbeandefinitionexception ex) {
            
        }
    }
    
    /**
    如果没找到,则从默认规则里取出指定的实现类:internalresourceviewresolver
    **/
    if (this.viewresolvers == null) {
        this.viewresolvers = getdefaultstrategies(context, viewresolver.class); 
    }
}

         三大组件的初始化最后判断为null时都会调用getdefaultstrategies方法,也就是从dispatcherservlet.properties中取出指定默认值。

protected <t> list<t> getdefaultstrategies(applicationcontext context, class<t> strategyinterface) {
    string key = strategyinterface.getname();
    string value = defaultstrategies.getproperty(key);
    if (value != null) {
        string[] classnames = stringutils.commadelimitedlisttostringarray(value);
        list<t> strategies = new arraylist<>(classnames.length);
        for (string classname : classnames) {
            try {
                class<?> clazz = classutils.forname(classname, dispatcherservlet.class.getclassloader());
                object strategy = createdefaultstrategy(context, clazz);
                strategies.add((t) strategy);
            }
            catch (classnotfoundexception ex) {
                throw new beaninitializationexception("could not find dispatcherservlet's default strategy class [" + classname +"] for interface [" + key + "]", ex);
            }
            catch (linkageerror err) {
                throw new beaninitializationexception("unresolvable class definition for dispatcherservlet's default strategy class [" +classname + "] for interface [" + key + "]", err);
            }
        }
        return strategies;
    }
    else {
        return new linkedlist<>();
    }
}

dispatcherservlet请求处理过程

     提到请求处理过程,我们再来回顾一下servlet生命周期,处理请求都放在service方法中处理,那么也从dispatcherservlet的service方法入手。dispatcherservlet继承frameworkservlet,在frameworkservlet中重写了service、doget、dopost、doput、dodelete方法。

//frameworkservlet.java
@override
protected void service(httpservletrequest request, httpservletresponse response)
        throws servletexception, ioexception {
    httpmethod httpmethod = httpmethod.resolve(request.getmethod());
    if (httpmethod == httpmethod.patch || httpmethod == null) {
        processrequest(request, response);
    }
    else {
        super.service(request, response);
    }
}

    
@override
protected final void doget(httpservletrequest request, httpservletresponse response)
        throws servletexception, ioexception {
    processrequest(request, response);
}

    
@override
protected final void dopost(httpservletrequest request, httpservletresponse response)
        throws servletexception, ioexception {
    processrequest(request, response);
}

    
@override
protected final void doput(httpservletrequest request, httpservletresponse response)
        throws servletexception, ioexception {
    processrequest(request, response);
}

    
@override
protected final void dodelete(httpservletrequest request, httpservletresponse response)
        throws servletexception, ioexception {
    processrequest(request, response);
}


protected final void processrequest(httpservletrequest request, httpservletresponse response)
            throws servletexception, ioexception {

    long starttime = system.currenttimemillis();
    throwable failurecause = null;

    localecontext previouslocalecontext = localecontextholder.getlocalecontext();
    localecontext localecontext = buildlocalecontext(request);

    requestattributes previousattributes = requestcontextholder.getrequestattributes();
    servletrequestattributes requestattributes = buildrequestattributes(request, response, previousattributes);

    webasyncmanager asyncmanager = webasyncutils.getasyncmanager(request);
    asyncmanager.registercallableinterceptor(frameworkservlet.class.getname(), new requestbindinginterceptor());
    
    //把新构造的localecontext对象和servletrequestattributes对象和当前请求线程绑定(后面要解除绑定)
    initcontextholders(request, localecontext, requestattributes);

    try {
        //抽象方法,交给dispatcherservlet方法实现
        doservice(request, response);
    }
    catch (servletexception | ioexception ex) {
        failurecause = ex;
        throw ex;
    }
    catch (throwable ex) {
        failurecause = ex;
        throw new nestedservletexception("request processing failed", ex);
    }

    finally {
        //重置localecontext和requestattributes对象,也就是解除localecontext对象和servletrequestattributes对象和当前请求线程的绑定
        resetcontextholders(request, previouslocalecontext, previousattributes);
        if (requestattributes != null) {
            requestattributes.requestcompleted();
        }
        //发布servletrequesthandledevent事件
        publishrequesthandledevent(request, response, starttime, failurecause);
    }
}
//dispatcherservlet.java
@override
protected void doservice(httpservletrequest request, httpservletresponse response) throws exception {
    
    map<string, object> attributessnapshot = null;
    if (webutils.isincluderequest(request)) {
        attributessnapshot = new hashmap<>();
        enumeration<?> attrnames = request.getattributenames();
        while (attrnames.hasmoreelements()) {
            string attrname = (string) attrnames.nextelement();
            if (this.cleanupafterinclude || attrname.startswith(default_strategies_prefix)) {
                attributessnapshot.put(attrname, request.getattribute(attrname));
            }
        }
    }
    
    //在当前request对象中填充4个属性
    request.setattribute(web_application_context_attribute, getwebapplicationcontext());
    request.setattribute(locale_resolver_attribute, this.localeresolver);
    request.setattribute(theme_resolver_attribute, this.themeresolver);
    request.setattribute(theme_source_attribute, getthemesource());

    if (this.flashmapmanager != null) {
        flashmap inputflashmap = this.flashmapmanager.retrieveandupdate(request, response);
        if (inputflashmap != null) {
            request.setattribute(input_flash_map_attribute, collections.unmodifiablemap(inputflashmap));
        }
        request.setattribute(output_flash_map_attribute, new flashmap());
        request.setattribute(flash_map_manager_attribute, this.flashmapmanager);
    }

    try {
        //主要处理分发请求
        dodispatch(request, response);
    }
    finally {
        if (!webasyncutils.getasyncmanager(request).isconcurrenthandlingstarted()) {
            if (attributessnapshot != null) {
                restoreattributesafterinclude(request, attributessnapshot);
            }
        }
    }
}


protected void dodispatch(httpservletrequest request, httpservletresponse response) throws exception {
    httpservletrequest processedrequest = request;
    handlerexecutionchain mappedhandler = null;
    boolean multipartrequestparsed = false;

    webasyncmanager asyncmanager = webasyncutils.getasyncmanager(request);

    try {
        modelandview mv = null;
        exception dispatchexception = null;

        try {
            processedrequest = checkmultipart(request);
            multipartrequestparsed = (processedrequest != request);
            
            //调用handlermapping获取handlerchain
            mappedhandler = gethandler(processedrequest);
            if (mappedhandler == null) {
                nohandlerfound(processedrequest, response);
                return;
            }

            //获取支持该handler解析的handleradapter
            handleradapter ha = gethandleradapter(mappedhandler.gethandler());

            string method = request.getmethod();
            boolean isget = "get".equals(method);
            if (isget || "head".equals(method)) {
                long lastmodified = ha.getlastmodified(request, mappedhandler.gethandler());
                if (new servletwebrequest(request, response).checknotmodified(lastmodified) && isget) {
                    return;
                }
            }

            if (!mappedhandler.applyprehandle(processedrequest, response)) {
                return;
            }

            //使用handleradapter完成handler处理
            mv = ha.handle(processedrequest, response, mappedhandler.gethandler());

            if (asyncmanager.isconcurrenthandlingstarted()) {
                return;
            }

            //视图处理(页面渲染)
            applydefaultviewname(processedrequest, mv);
            mappedhandler.applyposthandle(processedrequest, response, mv);
        }
        catch (exception ex) {
            dispatchexception = ex;
        }
        catch (throwable err) {
            dispatchexception = new nestedservletexception("handler dispatch failed", err);
        }
        processdispatchresult(processedrequest, response, mappedhandler, mv, dispatchexception);
    }
    catch (exception ex) {
        triggeraftercompletion(processedrequest, response, mappedhandler, ex);
    }
    catch (throwable err) {
        triggeraftercompletion(processedrequest, response, mappedhandler,new nestedservletexception("handler processing failed", err));
    }
    finally {
        if (asyncmanager.isconcurrenthandlingstarted()) {
            if (mappedhandler != null) {
                mappedhandler.applyafterconcurrenthandlingstarted(processedrequest, response);
            }
        }
        else {
            if (multipartrequestparsed) {
                cleanupmultipart(processedrequest);
            }
        }
    }
}

        dispatcherservlet的dodispatch方法概括起来大致就是以下几点:首先根据当前请求路径找到对应的handlermethod,一个handlermethod和若干个拦截器构造一个handlerexecutionchain.通过handlerexecutionchain得到handleradapter对象通过执行handleradapter的handle方法得到modelandview对象,调用modelandview解析视图,渲染视图,response结束。

参考

https://www.cnblogs.com/fangjian0423/p/springmvc-dispatcherservlet.html

《SpringMVC 源码解析.doc》

下载本文的Word格式文档,以方便收藏与打印。