详解springMVC容器加载源码分析
springmvc是一个基于servlet容器的轻量灵活的mvc框架,在它整个请求过程中,为了能够灵活定制各种需求,所以提供了一系列的组件完成整个请求的映射,响应等等处理。这里我们来分析下springMVC的源码。
首先,spring提供了一个处理所有请求的servlet,这个servlet实现了servlet的接口,就是DispatcherServlet。把它配置在web.xml中,并且处理我们在整个mvc中需要处理的请求,一般如下配置:
spring-servlet org.springframework.web.servlet.DispatcherServlet contextConfigLocation classpath:springmvc-servlet.xml 1 spring-servlet /
DispatcherServlet也继承了FrameworkServlet抽象类,这个抽象类为整个servlet的处理提供了spring容器的支持,让原本servlet容器的DispatcherServlet拥有能够利用spring容器组件的能力。上面servlet的初始化参数contextConfigLocation就是DispatcherServlet获取spring容器的配置环境。FrameworkServlet继承自org.springframework.web.servlet.HttpServletBean。HttpServletBean实现了servlet容器初始化会调用的init函数。这个init函数会调用FrameworkServlet的初始化加载spring容器方法。方法源码:
@Override protectedfinalvoidinitServletBean()throwsServletException{ getServletContext().log("InitializingSpringFrameworkServlet'"+getServletName()+"'"); if(this.logger.isInfoEnabled()){ this.logger.info("FrameworkServlet'"+getServletName()+"':initializationstarted"); } longstartTime=System.currentTimeMillis(); try{ //初始化spring-servlet容器 this.webApplicationContext=initWebApplicationContext(); initFrameworkServlet(); } catch(ServletExceptionex){ this.logger.error("Contextinitializationfailed",ex); throwex; } catch(RuntimeExceptionex){ this.logger.error("Contextinitializationfailed",ex); throwex; } if(this.logger.isInfoEnabled()){ longelapsedTime=System.currentTimeMillis()-startTime; this.logger.info("FrameworkServlet'"+getServletName()+"':initializationcompletedin"+ elapsedTime+"ms"); } }
可以看到这里就触发了spring的对web支持的容器初始化,这里使用的容器为WebApplicationContext.接下来我们就来分析一下整个容器的初始化过程:
protectedWebApplicationContextinitWebApplicationContext(){ //查看是否在servlet上下文有所有容器需要继承的根Web容器 WebApplicationContextrootContext= WebApplicationContextUtils.getWebApplicationContext(getServletContext()); WebApplicationContextwac=null; //如果容器已经加载 if(this.webApplicationContext!=null){ //Acontextinstancewasinjectedatconstructiontime->useit wac=this.webApplicationContext; if(wacinstanceofConfigurableWebApplicationContext){ ConfigurableWebApplicationContextcwac=(ConfigurableWebApplicationContext)wac; if(!cwac.isActive()){ //Thecontexthasnotyetbeenrefreshed->provideservicessuchas //settingtheparentcontext,settingtheapplicationcontextid,etc if(cwac.getParent()==null){ //Thecontextinstancewasinjectedwithoutanexplicitparent->set //therootapplicationcontext(ifany;maybenull)astheparent cwac.setParent(rootContext); } configureAndRefreshWebApplicationContext(cwac); } } } if(wac==null){ //Nocontextinstancewasinjectedatconstructiontime->seeifone //hasbeenregisteredintheservletcontext.Ifoneexists,itisassumed //thattheparentcontext(ifany)hasalreadybeensetandthatthe //userhasperformedanyinitializationsuchassettingthecontextid wac=findWebApplicationContext(); } if(wac==null){ //创建容器 wac=createWebApplicationContext(rootContext); } if(!this.refreshEventReceived){ //EitherthecontextisnotaConfigurableApplicationContextwithrefresh //supportorthecontextinjectedatconstructiontimehadalreadybeen //refreshed->triggerinitialonRefreshmanuallyhere. onRefresh(wac); } if(this.publishContext){ //Publishthecontextasaservletcontextattribute. StringattrName=getServletContextAttributeName(); getServletContext().setAttribute(attrName,wac); if(this.logger.isDebugEnabled()){ this.logger.debug("PublishedWebApplicationContextofservlet'"+getServletName()+ "'asServletContextattributewithname["+attrName+"]"); } } returnwac; }
如果已经有容器被创建那就初始化。否则创建容器,创建逻辑:
protectedWebApplicationContextcreateWebApplicationContext(ApplicationContextparent){ Class>contextClass=getContextClass(); if(this.logger.isDebugEnabled()){ this.logger.debug("Servletwithname'"+getServletName()+ "'willtrytocreatecustomWebApplicationContextcontextofclass'"+ contextClass.getName()+"'"+",usingparentcontext["+parent+"]"); } //判断是否是可配置的容器 if(!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)){ thrownewApplicationContextException( "Fatalinitializationerrorinservletwithname'"+getServletName()+ "':customWebApplicationContextclass["+contextClass.getName()+ "]isnotoftypeConfigurableWebApplicationContext"); } //如果找到目标容器,并且可配置,然后就开始获取配置文件并开始初始化 ConfigurableWebApplicationContextwac= (ConfigurableWebApplicationContext)BeanUtils.instantiateClass(contextClass); wac.setEnvironment(getEnvironment()); wac.setParent(parent); wac.setConfigLocation(getContextConfigLocation()); //这里是获取配置文件和完成初始化web容器的入口 configureAndRefreshWebApplicationContext(wac); returnwac; }
这里完成了web容器的相关准备工作,开始正式读取配置文件加载和初始化容器。
protectedvoidconfigureAndRefreshWebApplicationContext(ConfigurableWebApplicationContextwac){ //给容器设置一个id if(ObjectUtils.identityToString(wac).equals(wac.getId())){ //Theapplicationcontextidisstillsettoitsoriginaldefaultvalue //->assignamoreusefulidbasedonavailableinformation if(this.contextId!=null){ wac.setId(this.contextId); } else{ //Generatedefaultid... wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX+ ObjectUtils.getDisplayString(getServletContext().getContextPath())+'/'+getServletName()); } } wac.setServletContext(getServletContext()); wac.setServletConfig(getServletConfig()); wac.setNamespace(getNamespace()); wac.addApplicationListener(newSourceFilteringListener(wac,newContextRefreshListener())); //Thewacenvironment's#initPropertySourceswillbecalledinanycasewhenthecontext //isrefreshed;doiteagerlyheretoensureservletpropertysourcesareinplacefor //useinanypost-processingorinitializationthatoccursbelowpriorto#refresh ConfigurableEnvironmentenv=wac.getEnvironment(); if(envinstanceofConfigurableWebEnvironment){ ((ConfigurableWebEnvironment)env).initPropertySources(getServletContext(),getServletConfig()); } /*这里在容器被激活后, 并且容器还没完成初始化之前可以对容器的相关配置做一些修改, 默认给了空实现, 这里子类可以去重写,能够获得在容器初始化之前做一些处理*/ postProcessWebApplicationContext(wac); //这里讲容器的初始化信息放到一个列表 applyInitializers(wac); //这里就开始web容器的初始化 wac.refresh(); }
容器的初始化在AbstractApplicationContext,无论是其他的容器,最终都会调用到refresh()函数,这个函数基本定义了整个容器初始化的整个脉络,这里不展开讲,本博客之后应该会详细分析这块的逻辑,这里大概的注释一下每一个函数完成的操作:
publicvoidrefresh()throwsBeansException,IllegalStateException{ synchronized(this.startupShutdownMonitor){ //这里主要加载了容器当中一些从其他配置文件读取的变量 prepareRefresh(); //获取容器本身 ConfigurableListableBeanFactorybeanFactory=obtainFreshBeanFactory(); //这里完成一些基础组件的依赖 prepareBeanFactory(beanFactory); try{ //添加容器初始化之前的前置处理 postProcessBeanFactory(beanFactory); //调用前置处理器,其中包含invokeBeanDefinitionRegistryPostProcessors与invokeBeanFactoryPostProcessors两类前置处理器的调用 invokeBeanFactoryPostProcessors(beanFactory); //注册bean被创建之前的前置处理器 registerBeanPostProcessors(beanFactory); //初始化容器的编码源 initMessageSource(); //初始化一些事件监听器 initApplicationEventMulticaster(); //Initializeotherspecialbeansinspecificcontextsubclasses. onRefresh(); //注册容器监听器 registerListeners(); //初始化所有非懒加载的beans finishBeanFactoryInitialization(beanFactory); //Laststep:事件通知关心容器加载的相关组件 finishRefresh(); } //部分代码省略 } } }
自此加载完毕核心容器,然后回到FramewordServlet的initWebApplicationContext函数,在调用createWebApplicationContext完成一系列上面的操作之后,需要mvcservlet组件,入口就是onRefresh(ApplocationContextcontext)方法。它会调用另一个方法initStrategies(ApplicationContextcontext)。该方法如下:
protectedvoidinitStrategies(ApplicationContextcontext){ initMultipartResolver(context); initLocaleResolver(context); initThemeResolver(context); //获取所有的RequestMappings initHandlerMappings(context); //不同handler的适配器 initHandlerAdapters(context); //异常解析器 initHandlerExceptionResolvers(context); initRequestToViewNameTranslator(context); initViewResolvers(context); initFlashMapManager(context); }
这里我们重点讲解initHandlerMappings与initHandlerAdapters函数,因为这两个是处理servlet请求的入口。
在springmvc中任何类都可以处理request请求,因为DispacherServlet也是实现了HttpServlet的接口,所以处理请求也是doService里。doService会将请求交给doDispatcher函数处理。然后doDispacher的源码:
protectedvoiddoDispatch(HttpServletRequestrequest,HttpServletResponseresponse)throwsException{ HttpServletRequestprocessedRequest=request; HandlerExecutionChainmappedHandler=null; booleanmultipartRequestParsed=false; WebAsyncManagerasyncManager=WebAsyncUtils.getAsyncManager(request); try{ ModelAndViewmv=null; ExceptiondispatchException=null; try{ processedRequest=checkMultipart(request); multipartRequestParsed=(processedRequest!=request); //这里获取当前请求的处理handler mappedHandler=getHandler(processedRequest,false); if(mappedHandler==null||mappedHandler.getHandler()==null){ noHandlerFound(processedRequest,response); return; } /*因为handler可以是任何类, 但是我们的DispacherServlet需要一个统一的处理接口,这个接口就是HandlerAdapter, 不同的HandlerMapping可以获取到各种各样的Handler, 这个handler最后都必须得到HandlerAdapter的支持才能被DispacherServlet所调用。 扩充一个新的HandlerMapping只需要添加一个新的HandlerAdatper即可,有点抽象工厂模式的味道*/ HandlerAdapterha=getHandlerAdapter(mappedHandler.getHandler()); //Processlast-modifiedheader,ifsupportedbythehandler. Stringmethod=request.getMethod(); booleanisGet="GET".equals(method); if(isGet||"HEAD".equals(method)){ longlastModified=ha.getLastModified(request,mappedHandler.getHandler()); if(logger.isDebugEnabled()){ logger.debug("Last-Modifiedvaluefor["+getRequestUri(request)+"]is:"+lastModified); } if(newServletWebRequest(request,response).checkNotModified(lastModified)&&isGet){ return; } } if(!mappedHandler.applyPreHandle(processedRequest,response)){ return; } //Actuallyinvokethehandler. mv=ha.handle(processedRequest,response,mappedHandler.getHandler()); if(asyncManager.isConcurrentHandlingStarted()){ return; } applyDefaultViewName(request,mv); mappedHandler.applyPostHandle(processedRequest,response,mv); } catch(Exceptionex){ dispatchException=ex; } processDispatchResult(processedRequest,response,mappedHandler,mv,dispatchException); } catch(Exceptionex){ triggerAfterCompletion(processedRequest,response,mappedHandler,ex); } catch(Errorerr){ triggerAfterCompletionWithError(processedRequest,response,mappedHandler,err); } finally{ if(asyncManager.isConcurrentHandlingStarted()){ //InsteadofpostHandleandafterCompletion if(mappedHandler!=null){ mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest,response); } } else{ //Cleanupanyresourcesusedbyamultipartrequest. if(multipartRequestParsed){ cleanupMultipart(processedRequest); } } } }
但是我们发现获取到的handler并不是Object而是一个HandlerExecutionChain,这个类可以进去查看发现是一堆拦截器和一个handler,主要就是给每一个请求一个前置处理的机会,这里值得一提的是一般来说拦截器和过滤器的区别就是拦截器可以终止后续执行流程,而过滤器一般不终止。过滤器一般是容器级别的,这个handler前置拦截器可以做到更细级别的控制,例如过滤器只定义了init和doFilter,但是这个handler拦截器定义了preHandle和postHandle还有afterCompletion函数,不难理解分别对应不同请求阶段的拦截粒度,更加灵活。
获取处理handler的getHandler代码:
protectedHandlerExecutionChaingetHandler(HttpServletRequestrequest)throwsException{ //这里获取多个映射方式,一旦找到合适的处理请求的handler即返回 for(HandlerMappinghm:this.handlerMappings){ if(logger.isTraceEnabled()){ logger.trace( "Testinghandlermap["+hm+"]inDispatcherServletwithname'"+getServletName()+"'"); } //HandlerExecutionChain包含了 HandlerExecutionChainhandler=hm.getHandler(request); if(handler!=null){ returnhandler; } } returnnull; }
HandlerAdapter处理后返回统一被封装成ModelAndView对象,这个就是包含试图和数据的对象,在经过适当的处理:
processDispatchResult(HttpServletRequestrequest,HttpServletResponseresponse, HandlerExecutionChainmappedHandler,ModelAndViewmv,Exceptionexception)
将页面与返回的数据返回给浏览器完成整个请求过程。以上就是springMVC大概的启动过程和请求的处理过程,之后本博客还会陆续分析核心的spring源码,博主一直认为精读著名框架源码是在短时间提升代码能力的捷径,因为这些轮子包含太多设计思想和细小的代码规范,这些读多了都会潜移默化的形成一种本能的东西。设计模式也不断贯穿其中。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。