SpringMVC 源码解析
前言
年初面试时接触到一道面试题,在聊到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