繼上一篇spring-webmvc請求處理流程以後,本篇繼續講解3.2.x版本以後使用的RequestMappingHandlerAdapter,該類替換了AnnotationMethodHandlerAdapter。java
自3.2以後的版本,引入了RequestMappingHandlerAdapter來替換了AnnotationMethodHandlerAdapter的處理。這裏也來分析一下這個玩意兒。web
由於也是一個HandlerAdapter,因此,前面的處理流程都是同樣的,servlet的getHandlerAdapter這個時候就返回了RequestMappingHandlerAdapter,而不是AnnotationMethodHandlerAdapter了。spring
拿到HandlerAdapter以後,咱們就直接衝ha.handle()方法開始分析吧。json
// RequestMAppingHandlerAdapter.java protected final ModelAndView handleInternal(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception { //...作一些檢查 return invokeHandleMethod(request, response, handlerMethod); } private ModelAndView invokeHandleMethod(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception { ServletWebRequest webRequest = new ServletWebRequest(request, response); WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod); ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory); //拿取咱們須要執行的controller的方法 ServletInvocableHandlerMethod requestMappingMethod = createRequestMappingMethod(handlerMethod, binderFactory); // 用於後面構造mv的Container ModelAndViewContainer mavContainer = new ModelAndViewContainer(); mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request)); modelFactory.initModel(webRequest, mavContainer, requestMappingMethod); mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect); //...這一段是對異步請求的處理 //調用controller的方法,並處理mavContainer requestMappingMethod.invokeAndHandle(webRequest, mavContainer); if (asyncManager.isConcurrentHandlingStarted()) { return null; } return getModelAndView(mavContainer, modelFactory, webRequest); } private ModelAndView getModelAndView(ModelAndViewContainer mavContainer, ModelFactory modelFactory, NativeWebRequest webRequest) throws Exception { modelFactory.updateModel(webRequest, mavContainer); //判斷,若是當前請求已經處理完成,則不進行後續的處理沒直接返回null if (mavContainer.isRequestHandled()) { return null; } //若是請求還未處理完成,那說明可能有頁面須要返回,開始查找,處理並返回mav ModelMap model = mavContainer.getModel(); ModelAndView mav = new ModelAndView(mavContainer.getViewName(), model); if (!mavContainer.isViewReference()) { mav.setView((View) mavContainer.getView()); } if (model instanceof RedirectAttributes) { Map<String, ?> flashAttributes = ((RedirectAttributes) model).getFlashAttributes(); HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class); RequestContextUtils.getOutputFlashMap(request).putAll(flashAttributes); } return mav; }
直接跟進去。來到RequestMappingHAndlerAdapter的handleInternal()方法,不要驚慌,按照spring的一向風格,這TM固然不是核心方法,他只是作了一些檢查。方法最後調用了invokeHandleMethod()。在該方法中,作了一些所需參數的獲取,好比請求的controller層方法,參數。而後調用ServletInvocableHandlerMethod對象invokeAndHandle方法。mvc
//ServletInvocableHandlerMethod.java public final void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception { // 真正調用controller方法,得到結果 Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs); //設置響應狀態 setResponseStatus(webRequest); //若是返回值爲null,則說明該請求不返回任何結果,直接設置mavContainer.setRequestHandled(true) //設置爲true以後,表示該請求已經處理完,後續再也不處理,後續會提到這個 if (returnValue == null) { if (isRequestNotModified(webRequest) || hasResponseStatus() || mavContainer.isRequestHandled()) { mavContainer.setRequestHandled(true); return; } } else if (StringUtils.hasText(this.responseReason)) { mavContainer.setRequestHandled(true); return; } //設置爲false,表示當前請求還未處理完成 mavContainer.setRequestHandled(false); try { //調用默認的和自定義的全部返回值解析器處理返回結果 this.returnValueHandlers.handleReturnValue(returnValue, getReturnValueType(returnValue), mavContainer, webRequest); } catch (Exception ex) {//...} throw ex; } }
從註釋中可於瞭解到,首先調用業務邏輯得到返回結果,而後對返回值作必定的判斷並簡單處理。經過returnValueHandlers對象來進一步處理返回結果。這是個HandlerMethodReturnValueHandlerComposite類型的對象,繼續跟進。app
public void handleReturnValue( Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception { // 得到能夠處理返回值的handler,固然也是經過遍歷,能夠看方法 HandlerMethodReturnValueHandler handler = getReturnValueHandler(returnType); //若是沒有合適的返回值處理器,就會報錯 Assert.notNull(handler, "Unknown return value type [" + returnType.getParameterType().getName() + "]"); //使用返回值處理器處理返回結果 handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest); } private HandlerMethodReturnValueHandler getReturnValueHandler(MethodParameter returnType) { //遍歷全部handler,包括自定義的 for (HandlerMethodReturnValueHandler returnValueHandler : returnValueHandlers) { //... if (returnValueHandler.supportsReturnType(returnType)) { //若是該handler可以處理當前返回值,就返回該handler return returnValueHandler; } } return null; }
來,看一下全部的默認註冊的處理器。看到了RequestResponseBodyMethodProcessor是否是很親切呢,對咯,他就是處理@ResponseBody註解的。喜歡的朋友能夠去看哈這個類的supportsReturnType()方法就明白了。異步
到這裏就不繼續跟了,咱們熟悉的RequestResponseBodyMethodProcessor處理器處理結果的時候會設置mavContainer.setRequestHandled(true);表示處理已經完畢。async
處理完以後,回到RequestMappingHandlerAdapter的invokeHandleMethod()方法。這個方法最終返回了getModelAndView();ide
從該方法中,咱們能夠看到,若是當前請求已經處理完成(mavContainer.isRequestHandled()值爲true),則不進行後續的處理沒直接返回null,不然spring會繼續處理當前請求,並試圖返回一個ModelAndView。測試
既然上面提到了自定義的返回值處理器,那這個自定義是在哪裏的呢?這個返回值處理器就是在哪裏註冊的呢?精彩立刻回來!
返回值處理器須要實現HandlerMethodReturnValueHandler
public class MyCustomReturnValueHandler implements HandlerMethodReturnValueHandler { @Override public boolean supportsReturnType(MethodParameter returnType) { //判斷方法是否包含自定義註解MyResonse或者返回結果是指定的某種類型 return returnType.getMethodAnnotation(MyResponse.class) != null || ResponseResult.class.isAssignableFrom(returnType.getParameterType()); } @Override public void handleReturnValue(Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception { // 代表該請求已經處理,後面spring不會再處理 mavContainer.setRequestHandled(true); HttpServletResponse response = webRequest.getNativeResponse(HttpServletResponse.class); response.setCharacterEncoding("UTF-8"); response.setContentType("application/json;charset=UTF-8"); response.getWriter().println(JSON.toJSONString(returnValue)); } }
controller,我這裏註解和返回值類型都符合上面處理器的要求,事實上只要一種就行了。
@RequestMapping("/testValueHandler") @MyResponse public ResponseResult testValueHandler() { return new ResponseResult(0,"success"); }
springmvc.xml
<mvc:annotation-driven> <mvc:return-value-handlers> <bean class="com.wt.test.webmvc.config.MyCustomReturnValueHandler"/> </mvc:return-value-handlers> </mvc:annotation-driven>
從xml中能夠看到是自定義標籤mvc:return-value-handlers,跟蹤MvcNamespaceHandler。
// MvcNamespaceHandler.java public void init() { //解析自定義標籤的parser registerBeanDefinitionParser("annotation-driven", new AnnotationDrivenBeanDefinitionParser()); }
進入AnnotationDrivenBeanDefinitionParser的parse方法,自定義的就是在這裏處理的,咱們來看一下。
// AnnotationDrivenBeanDefinitionParser public BeanDefinition parse(Element element, ParserContext parserContext) { //... //獲取自定義的返回值處理器 ManagedList<?> returnValueHandlers = getReturnValueHandlers(element, parserContext); //... // 定義RequestMappingAdapterHandler RootBeanDefinition handlerAdapterDef = new RootBeanDefinition(RequestMappingHandlerAdapter.class); //... if (returnValueHandlers != null) { //設置自定義返回值處理器的屬性customReturnValueHandlers handlerAdapterDef.getPropertyValues().add("customReturnValueHandlers", returnValueHandlers); } //... // 將定義的RequestMappingAdapterHandler註冊爲spring的bean parserContext.registerComponent(new BeanComponentDefinition(handlerAdapterDef, handlerAdapterName)); //... } // 解析自定義標籤return-value-handlers private ManagedList<?> getReturnValueHandlers(Element element, ParserContext parserContext) { Element handlersElement = DomUtils.getChildElementByTagName(element, "return-value-handlers"); if (handlersElement != null) { return extractBeanSubElements(handlersElement, parserContext); } return null; }
直接看註釋了,不解釋了。到這裏自定義的返回值處理器就已經註冊完了,已是spring的一個bean了。如今咱們來看看RequestMappingHandlerAdapter。
這個傢伙實現了InitializingBean,咱們來看afterPropertiesSet方法。
public void afterPropertiesSet() { //... } if (this.returnValueHandlers == null) { //獲取全部的返回值處理器,不要看方法名是getDefaultReturnVanlueHandler,實際上在裏面也包含了自定義的處理器 List<HandlerMethodReturnValueHandler> handlers = getDefaultReturnValueHandlers(); this.returnValueHandlers = new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers); } initControllerAdviceCache(); } private List<HandlerMethodReturnValueHandler> getDefaultReturnValueHandlers() { List<HandlerMethodReturnValueHandler> handlers = new ArrayList<HandlerMethodReturnValueHandler>(); // 默認的返回值處理器 // Single-purpose return value types handlers.add(new ModelAndViewMethodReturnValueHandler()); handlers.add(new ModelMethodProcessor()); handlers.add(new ViewMethodReturnValueHandler()); handlers.add(new HttpEntityMethodProcessor(getMessageConverters(), this.contentNegotiationManager)); handlers.add(new CallableMethodReturnValueHandler()); handlers.add(new DeferredResultMethodReturnValueHandler()); handlers.add(new AsyncTaskMethodReturnValueHandler(this.beanFactory)); // Annotation-based return value types handlers.add(new ModelAttributeMethodProcessor(false)); handlers.add(new RequestResponseBodyMethodProcessor(getMessageConverters(), this.contentNegotiationManager)); // Multi-purpose return value types handlers.add(new ViewNameMethodReturnValueHandler()); handlers.add(new MapMethodProcessor()); // 自定義的返回值處理器,就是在以前parse處理的那些 if (getCustomReturnValueHandlers() != null) { handlers.addAll(getCustomReturnValueHandlers()); } // 添加其餘的默認返回值處理器 // Catch-all if (!CollectionUtils.isEmpty(getModelAndViewResolvers())) { handlers.add(new ModelAndViewResolverMethodReturnValueHandler(getModelAndViewResolvers())); } else { handlers.add(new ModelAttributeMethodProcessor(true)); } return handlers; }
從上能夠看出,咱們雖然咱們的自定義返回值處理器放進去了,可是必定會用到嘛?那不必定哦。能夠看到對全部的返回值處理器,並無進行排序,所以咱們不能控制這個順序。先給一個調試的圖:
從圖中咱們可看到,咱們自定義的handler確實是加載進去了,可是因爲spring在處理這個handlers的時候並無進行排序,因此咱們自定義被放在了後面,咱們不可以控制這個順序(其餘騷方法能夠實現,這裏不考慮這種狀況)。因此存在一種狀況,咱們的返回值可以被前面的11個處理器中的某一個處理,那麼就輪不到咱們自定義的返回值處理器了。舉個簡單的例子,好比你返回值類型是String,那麼就會別ViewNameMethodReturnValueHandler處理;若是返回的類型是Map,那麼就會被MapMethodProcessor處理,能夠自行測試。所以咱們的返回值其實也很重要。因此要使用到咱們自定義的處理器,那麼首先咱們就得讓前面的處理器沒法處理咱們的返回結果。
一般能夠實現一個通用的返回結果實體,或者某個標記接口(空接口),這樣其餘的返回值處理器沒法處理返回的值類型,這樣就輪到咱們本身的返回值處理器了。也能夠返回喜歡的實體類型,像示例中同樣使用註解也能夠。可是由於一般一個項目來說返回值都是有定義的,返回的類型都是有同一種格式的,因此這類比較偏向使用通用相同的返回實體,或者使用某個接口標記。
over ...