<springmvc源碼分析(2)dispatcherservlet的初始化>初始化DispatcherServlet的多個組件。
本文繼續分析DispatcherServlet解析請求的過程。
概覽

①:DispatcherServlet是springmvc中的前端控制器(front controller),負責接收request並將request轉發給對應的處理組件.
②:HanlerMapping是springmvc中完成url到controller映射的組件.DispatcherServlet接收request,然后從HandlerMapping查找處理request的controller.
③:Cntroller處理request,並返回ModelAndView對象,Controller是springmvc中負責處理request的組件(類似於struts2中的Action),ModelAndView是封裝結果視圖的組件.
④ ⑤ ⑥:視圖解析器解析ModelAndView對象並返回對應的視圖給客戶端.
要點
維護url和controller的映射
這部分工作由DefaultAnnotationHandlerMapping.setApplicationContext的父類
org.springframework.web.servlet.handler.AbstractDetectingUrlHandlerMapping.initApplicationContext實現。具體方法為detectHandlers
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
protectedvoiddetectHandlers()throwsBeansException{
if
(logger.isDebugEnabled()){
logger.debug(
"LookingforURLmappingsinapplicationcontext:"
+getApplicationContext());
}
String[]beanNames=(
this
.detectHandlersInAncestorContexts?
BeanFactoryUtils.beanNamesForTypeIncludingAncestors(getApplicationContext(),Object.
class
):
getApplicationContext().getBeanNamesForType(Object.
class
));
//TakeanybeannamethatwecandetermineURLsfor.
for
(StringbeanName:beanNames){
String[]urls=determineUrlsForHandler(beanName);
if
(!ObjectUtils.isEmpty(urls)){
//URLpathsfound:Let'sconsideritahandler.
registerHandler(urls,beanName);
}
else
{
if
(logger.isDebugEnabled()){
logger.debug(
"Rejectedbeanname'"
+beanName+
"':noURLpathsidentified"
);
}
}
}
}
|
2.准確定位處理請求的具體方法(在AnnotationMethodHandlerAdapter中實現)
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
protectedModelAndViewinvokeHandlerMethod(HttpServletRequestrequest,HttpServletResponseresponse,Objecthandler)
throwsException{
ServletHandlerMethodResolvermethodResolver=getMethodResolver(handler);
MethodhandlerMethod=methodResolver.resolveHandlerMethod(request);
//具體實現方法的匹配
ServletHandlerMethodInvokermethodInvoker=newServletHandlerMethodInvoker(methodResolver);
ServletWebRequestwebRequest=newServletWebRequest(request,response);
ExtendedModelMapimplicitModel=newBindingAwareModelMap();
Objectresult=methodInvoker.invokeHandlerMethod(handlerMethod,handler,webRequest,implicitModel);
ModelAndViewmav=
methodInvoker.getModelAndView(handlerMethod,handler.getClass(),result,implicitModel,webRequest);
methodInvoker.updateModelAttributes(handler,(mav!=
null
?mav.getModel():
null
),implicitModel,webRequest);
returnmav;
}
|
1.請求入口
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
|
@Override
protectedfinalvoiddoGet(HttpServletRequestrequest,HttpServletResponseresponse)
throwsServletException,IOException{
processRequest(request,response);
}
/**
*DelegatePOSTrequeststo{@link#processRequest}.
*@see#doService
*/
@Override
protectedfinalvoiddoPost(HttpServletRequestrequest,HttpServletResponseresponse)
throwsServletException,IOException{
processRequest(request,response);
}
protectedfinalvoidprocessRequest(HttpServletRequestrequest,HttpServletResponseresponse)
throwsServletException,IOException{
longstartTime=System.currentTimeMillis();
ThrowablefailureCause=
null
;
//ExposecurrentLocaleResolverandrequestasLocaleContext.
LocaleContextpreviousLocaleContext=LocaleContextHolder.getLocaleContext();
LocaleContextHolder.setLocaleContext(buildLocaleContext(request),
this
.threadContextInheritable);
//ExposecurrentRequestAttributestocurrentthread.
RequestAttributespreviousRequestAttributes=RequestContextHolder.getRequestAttributes();
ServletRequestAttributesrequestAttributes=
null
;
if
(previousRequestAttributes==
null
||previousRequestAttributes.getClass().equals(ServletRequestAttributes.
class
)){
requestAttributes=newServletRequestAttributes(request);
RequestContextHolder.setRequestAttributes(requestAttributes,
this
.threadContextInheritable);
}
if
(logger.isTraceEnabled()){
logger.trace(
"Boundrequestcontexttothread:"
+request);
}
try
{
doService(request,response);
}
catch
(ServletExceptionex){
failureCause=ex;
throwex;
}
catch
(IOExceptionex){
failureCause=ex;
throwex;
}
catch
(Throwableex){
failureCause=ex;
thrownewNestedServletException(
"Requestprocessingfailed"
,ex);
}
finally
{
//Clearrequestattributesandresetthread-boundcontext.
LocaleContextHolder.setLocaleContext(previousLocaleContext,
this
.threadContextInheritable);
if
(requestAttributes!=
null
){
RequestContextHolder.setRequestAttributes(previousRequestAttributes,
this
.threadContextInheritable);
requestAttributes.requestCompleted();
}
if
(logger.isTraceEnabled()){
logger.trace(
"Clearedthread-boundrequestcontext:"
+request);
}
if
(failureCause!=
null
){
this
.logger.debug(
"Couldnotcompleterequest"
,failureCause);
}
else
{
this
.logger.debug(
"Successfullycompletedrequest"
);
}
if
(
this
.publishEvents){
//Whetherornotwesucceeded,publishanevent.
longprocessingTime=System.currentTimeMillis()-startTime;
this
.webApplicationContext.publishEvent(
newServletRequestHandledEvent(
this
,
request.getRequestURI(),request.getRemoteAddr(),
request.getMethod(),getServletConfig().getServletName(),
WebUtils.getSessionId(request),getUsernameForRequest(request),
processingTime,failureCause));
}
}
}
|
processRequest方法主要做4項工作。
-
得到當前線程的LocaleContext和RequestAttributes,創建新的LocaleContext和RequestAttributes並重新綁定到當前線程。
調用子類實現的doService()
重置當前線程的LocaleContext和RequestAttributes
執行成功后,發布ServletRequestHandledEvent事件。
2.DispatcherServlet自定義的doService方法
1234567891011121314151617181920212223242526272829303132333435363738protectedvoiddoService(HttpServletRequestrequest,HttpServletResponseresponse)throwsException{if(logger.isDebugEnabled()){StringrequestUri=urlPathHelper.getRequestUri(request);logger.debug("DispatcherServletwithname'"+getServletName()+"'processing"+request.getMethod()+"requestfor["+requestUri+"]");}//Keepasnapshotoftherequestattributesincaseofaninclude,//tobeabletorestoretheoriginalattributesaftertheinclude.Map<string,object>attributesSnapshot=null;if(WebUtils.isIncludeRequest(request)){logger.debug("Takingsnapshotofrequestattributesbeforeinclude");attributesSnapshot=newHashMap<string,object>();EnumerationattrNames=request.getAttributeNames();while(attrNames.hasMoreElements()){StringattrName=(String)attrNames.nextElement();if(this.cleanupAfterInclude||attrName.startsWith("org.springframework.web.servlet")){attributesSnapshot.put(attrName,request.getAttribute(attrName));}}}//Makeframeworkobjectsavailabletohandlersandviewobjects.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());try{doDispatch(request,response);}finally{//Restoretheoriginalattributesnapshot,incaseofaninclude.if(attributesSnapshot!=null){restoreAttributesAfterInclude(request,attributesSnapshot);}}}</string,object></string,object>主要做兩部分工作
-
如果是include請求,先保存一份request域數據的快照,doDispatch執行過后,將會用快照數據恢復。
調用doDispatch方法,完成請求轉發。
3.doDispatch方法
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697protectedvoiddoDispatch(HttpServletRequestrequest,HttpServletResponseresponse)throwsException{HttpServletRequestprocessedRequest=request;HandlerExecutionChainmappedHandler=null;intinterceptorIndex=-1;try{ModelAndViewmv;booleanerrorView=false;try{//1.檢查是否是文件上傳的請求processedRequest=checkMultipart(request);//Determinehandlerforthecurrentrequest.//2.取得處理當前請求的controller,這里也稱為hanlder,處理器,第一個步驟的意義就在這里體現了.//這里並不是直接返回controller,而是返回的HandlerExecutionChain請求處理器鏈對象,該對象封裝了handler和interceptors.mappedHandler=getHandler(processedRequest,false);if(mappedHandler==null||mappedHandler.getHandler()==null){noHandlerFound(processedRequest,response);return;}//Determinehandleradapterforthecurrentrequest.//3.獲取處理request的處理器適配器handleradapterHandlerAdapterha=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()){StringrequestUri=urlPathHelper.getRequestUri(request);logger.debug("Last-Modifiedvaluefor["+requestUri+"]is:"+lastModified);}if(newServletWebRequest(request,response).checkNotModified(lastModified)&&isGet){return;}}//ApplypreHandlemethodsofregisteredinterceptors.//4.攔截器的預處理方法HandlerInterceptor[]interceptors=mappedHandler.getInterceptors();if(interceptors!=null){for(inti=0;i<interceptors.length;i++){ actuallyinvokethehandler.=""applyposthandlemethodsofregisteredinterceptors.=""handlerinterceptorinterceptor="interceptors[i];"interceptorindex="i;"inti="interceptors.length-1;i"mv="ha.handle(processedRequest,response,mappedHandler.getHandler());">=0;i--){HandlerInterceptorinterceptor=interceptors[i];interceptor.postHandle(processedRequest,response,mappedHandler.getHandler(),mv);}}}catch(ModelAndViewDefiningExceptionex){logger.debug("ModelAndViewDefiningExceptionencountered",ex);mv=ex.getModelAndView();}catch(Exceptionex){Objecthandler=(mappedHandler!=null?mappedHandler.getHandler():null);mv=processHandlerException(processedRequest,response,handler,ex);errorView=(mv!=null);}//Didthehandlerreturnaviewtorender?if(mv!=null&&!mv.wasCleared()){render(mv,processedRequest,response);if(errorView){WebUtils.clearErrorRequestAttributes(request);}}else{if(logger.isDebugEnabled()){logger.debug("NullModelAndViewreturnedtoDispatcherServletwithname'"+getServletName()+"':assumingHandlerAdaptercompletedrequesthandling");}}//Triggerafter-completionforsuccessfuloutcome.triggerAfterCompletion(mappedHandler,interceptorIndex,processedRequest,response,null);}catch(Exceptionex){//Triggerafter-completionforthrownexception.triggerAfterCompletion(mappedHandler,interceptorIndex,processedRequest,response,ex);throwex;}catch(Errorerr){ServletExceptionex=newNestedServletException("Handlerprocessingfailed",err);//Triggerafter-completionforthrownexception.triggerAfterCompletion(mappedHandler,interceptorIndex,processedRequest,response,ex);throwex;}finally{//Cleanupanyresourcesusedbyamultipartrequest.if(processedRequest!=request){cleanupMultipart(processedRequest);}}}</interceptors.length;i++){>很明顯這兒是SpringMVC核心。
1.根據請求的路徑找到HandlerMethod(帶有Method反射屬性,也就是對應Controller中的方法)(DispatcherServlet.getHandler完成)
2.匹配路徑對應的攔截器(DispatcherServlet.getHandler完成)
3.獲得HandlerExecutionChain對象(DispatcherServlet.getHandler完成)
4.通過HandlerAdapter對象進行處理得到ModelAndView對象(HandlerAdapter.handle)
5.調用HandlerInterceptor.preHandle
6.調用HandlerInterceptor.postHandle
7. 渲染
4.總結

簡單粗暴的總結下
step1-6: 獲取controller
step5-15 :調用controller方法
step17-20:渲染view
其他:aop方式處理攔截統一處理。
-
