在前一篇對DispatcherServlet的分析中,初略的過了下請求是如何處理的,本文將重點分析,HandlerMapping與HandlerAdapter是如何工作的
在web容器啟動的過程中,會初初始化一系列SpringMVC所需的類,這裡我們看看AbstractHandlerMethodMapping類的initHandlerMethods方法
如果bean中有相應註解 檢測HandlerMethod
具體看看 selectMethods方法的實現
而其中的inspect方法 調用了 getMappingForMethod方法 具體實現 由其子類 RequestMappingHandlerMapping實現
protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {RequestMappingInfo info = createRequestMappingInfo(method);if (info != null) {RequestMappingInfo typeInfo = createRequestMappingInfo(handlerType);if (typeInfo != null) {info = typeInfo.combine(info);}}return info;}
此方法返回的是一個RequestMappingInfo類執行個體,可見我們之前methods Map中的T 類型就為RequestMappingInfo
此類是一個封裝了各種請求映射條件並實現了RequestCondition介面的類。有各種RequestCondition實作類別屬性,patternsCondition,methodsCondition,paramsCondition,headersCondition,consumesCondition以及producesCondition,這個請
求條件看屬性名稱也瞭解,分別代表http請求的路徑模式、方法、參數、頭部等資訊。
繼續看getMappingForMethod方法,createRequestMappingInfo的具體實現如下:
private RequestMappingInfo createRequestMappingInfo(AnnotatedElement element) {RequestMapping requestMapping = AnnotatedElementUtils.findMergedAnnotation(element, RequestMapping.class);RequestCondition<?> condition = (element instanceof Class<?> ?getCustomTypeCondition((Class<?>) element) : getCustomMethodCondition((Method) element));return (requestMapping != null ? createRequestMappingInfo(requestMapping, condition) : null);}首先找到方法的@RequestMapping註解,然後擷取RequestCondition ,如果有註解,則調用具體建立方法,否則返回null
protected RequestMappingInfo createRequestMappingInfo(RequestMapping requestMapping, RequestCondition<?> customCondition) {return RequestMappingInfo.paths(resolveEmbeddedValuesInPatterns(requestMapping.path())).methods(requestMapping.method()).params(requestMapping.params()).headers(requestMapping.headers()).consumes(requestMapping.consumes()).produces(requestMapping.produces()).mappingName(requestMapping.name()).customCondition(customCondition).options(this.config).build();}除了pathCondithion 其他都是直接使用 requestMapping註解中的condition
回頭再看registerHandlerMethod方法
到此 就註冊完URL相關操作
回頭再看 doDispatch方法中 getHandler的調用 最終會調用getHandlerInternal方法,具體實現:
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);if (logger.isDebugEnabled()) {logger.debug("Looking up handler method for path " + lookupPath);}this.mappingRegistry.acquireReadLock();try {HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);if (logger.isDebugEnabled()) {if (handlerMethod != null) {logger.debug("Returning handler method [" + handlerMethod + "]");}else {logger.debug("Did not find handler method for [" + lookupPath + "]");}}return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);}finally {this.mappingRegistry.releaseReadLock();}}關鍵代碼是通過調用 lookupHandlerMethod擷取 handlerMethod
以上都是基於Controller方法的映射 RequestMappingHandlerMapping,關於靜態資源的映射 這裡就不作詳細說明了,對應的handlerMpping 為SimpleUrlHandlerMapping
HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
通過handler 和 request構建 HandlerExecutionChain
protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?(HandlerExecutionChain) handler : new HandlerExecutionChain(handler));String lookupPath = this.urlPathHelper.getLookupPathForRequest(request);for (HandlerInterceptor interceptor : this.adaptedInterceptors) {if (interceptor instanceof MappedInterceptor) {MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {chain.addInterceptor(mappedInterceptor.getInterceptor());}}else {chain.addInterceptor(interceptor);}}return chain;}
HandlerAdapter的擷取以及是如何工作的
同樣在doDispatch中 我們通過handler來擷取handlerAdapter
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException { for (HandlerAdapter ha : this.handlerAdapters) { if (logger.isTraceEnabled()) { logger.trace("Testing handler adapter [" + ha + "]"); } if (ha.supports(handler)) { return ha; } } throw new ServletException("No adapter for handler [" + handler + "]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");}
這裡使用的handlerAdapters是在private void initHandlerAdapters(ApplicationContext context)方法中得到初始化的,大致思想就是將所有實現了HandlerAdapter介面的類的執行個體都找出來放到這個list中
我們以RequestMappingHandlerAdapter 執行個體來分析 對應的supports方法為 父類 AbstractHandlerMethodAdapter 方法:
public final boolean supports(Object handler) {return (handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler));} 在RequestMappingHandlerAdapter實現 supportsInternal:
protected boolean supportsInternal(HandlerMethod handlerMethod) {return true;}
可以發現RequestMappingHandlerAdapter 是對所有handlerMethod 進行適配調用
回到doDispatch
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
handler的調用 核心方法handleInternal的實現為:
protected ModelAndView handleInternal(HttpServletRequest request,HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {checkRequest(request);if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);}else {prepareResponse(response);}// Execute invokeHandlerMethod in synchronized block if required.if (this.synchronizeOnSession) {HttpSession session = request.getSession(false);if (session != null) {Object mutex = WebUtils.getSessionMutex(session);synchronized (mutex) {return invokeHandlerMethod(request, response, handlerMethod);}}}return invokeHandlerMethod(request, response, handlerMethod);}
內容很多,我們只需要重點關心invokeHandlerMethod
protected ModelAndView invokeHandlerMethod(HttpServletRequest request,HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {ServletWebRequest webRequest = new ServletWebRequest(request, response);WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);invocableMethod.setDataBinderFactory(binderFactory);invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);ModelAndViewContainer mavContainer = new ModelAndViewContainer();mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));modelFactory.initModel(webRequest, mavContainer, invocableMethod);mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response);asyncWebRequest.setTimeout(this.asyncRequestTimeout);WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);asyncManager.setTaskExecutor(this.taskExecutor);asyncManager.setAsyncWebRequest(asyncWebRequest);asyncManager.registerCallableInterceptors(this.callableInterceptors);asyncManager.registerDeferredResultInterceptors(this.deferredResultInterceptors);if (asyncManager.hasConcurrentResult()) {Object result = asyncManager.getConcurrentResult();mavContainer = (ModelAndViewContainer) asyncManager.getConcurrentResultContext()[0];asyncManager.clearConcurrentResult();if (logger.isDebugEnabled()) {logger.debug("Found concurrent result value [" + result + "]");}invocableMethod = invocableMethod.wrapConcurrentResult(result);}invocableMethod.invokeAndHandle(webRequest, mavContainer);if (asyncManager.isConcurrentHandlingStarted()) {return null;}return getModelAndView(mavContainer, modelFactory, webRequest);}
在此方法中,會根據 handlerMethod 建立ServletInvocableHandlerMethod 對象,設定方法執行過程中相應的 resovler
然後調用 invokeAndHandle:
public void invokeAndHandle(ServletWebRequest webRequest,ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception { //執行請求 並返回結果Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);setResponseStatus(webRequest);if (returnValue == null) {if (isRequestNotModified(webRequest) || hasResponseStatus() || mavContainer.isRequestHandled()) {mavContainer.setRequestHandled(true);return;}}else if (StringUtils.hasText(this.responseReason)) {mavContainer.setRequestHandled(true);return;}mavContainer.setRequestHandled(false);try {this.returnValueHandlers.handleReturnValue(returnValue, getReturnValueType(returnValue), mavContainer, webRequest);}catch (Exception ex) {if (logger.isTraceEnabled()) {logger.trace(getReturnValueHandlingErrorMessage("Error handling return value", returnValue), ex);}throw ex;}}可以看到 第一行調用 invokeForRequest執行請求
public Object invokeForRequest(NativeWebRequest request, ModelAndViewContainer mavContainer,Object... providedArgs) throws Exception {Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);if (logger.isTraceEnabled()) {logger.trace("Invoking '" + ClassUtils.getQualifiedMethodName(getMethod(), getBeanType()) +"' with arguments " + Arrays.toString(args));}Object returnValue = doInvoke(args);if (logger.isTraceEnabled()) {logger.trace("Method [" + ClassUtils.getQualifiedMethodName(getMethod(), getBeanType()) +"] returned [" + returnValue + "]");}return returnValue;}
繼續跟doInvoke方法,對於上面的請求參數解析下一篇部落格會分析,本文只分析方法的調用
其中的getBridgedMethod為:
protected Method getBridgedMethod() {return this.bridgedMethod;}而我們的bridgedMethod是什麼呢,不知道大家有沒有留意到,在前面我提到過的 ServletInvocableHandlerMethod 執行個體的建立
ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
而createInvocableHandlerMethod 就是好調用ServletInvocableHandlerMethod HandlerMethod參數 建構函式,最終會調用HandlerMethod建構函式:
protected HandlerMethod(HandlerMethod handlerMethod) {Assert.notNull(handlerMethod, "HandlerMethod is required");this.bean = handlerMethod.bean;this.beanFactory = handlerMethod.beanFactory;this.beanType = handlerMethod.beanType;this.method = handlerMethod.method;this.bridgedMethod = handlerMethod.bridgedMethod;this.parameters = handlerMethod.parameters;this.responseStatus = handlerMethod.responseStatus;this.responseStatusReason = handlerMethod.responseStatusReason;this.resolvedFromHandlerMethod = handlerMethod.resolvedFromHandlerMethod;}
其中就有對 bridgedMethod 的賦值,這下就應該清楚了 adapter是如何來調用我們Controller的方法啦
本節重點分析了 RequestMappingHandlerMapping 與 RequestMappingHandlerAdapter的工作原理以及過程