handlerAdpater的實現類總共有5個(其中一個已經廢棄),並且層級都不多。web
public interface HandlerAdapter { boolean supports(Object handler); ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception; long getLastModified(HttpServletRequest request, Object handler); }
handlerAdapter的接口很簡單,只有3個方法。緩存
這3個adapter很簡單,都是分別針對特定的handler的類型,直接調用就能夠了cookie
@Override public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { ((HttpRequestHandler) handler).handleRequest(request, response); return null; }
@Override public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { ((Servlet) handler).service(request, response); return null; }
@Override public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { return ((Controller) handler).handleRequest(request, response); }
RequestMappingHandlerAdapter是AbstractHandlerMethodAdapter的惟一實現類session
這個處理就比較複雜(但正是由於他爲咱們帶來了快捷的使用方式)。但總的來講作了3件事app
這個步驟應該是3步中最複雜的,拋開直接把Request中的參數(url中的或者body中的)之外、cookie中的參數、session中的參數,還要處理Spring MVC中的一些東西,例如FlashMap中的參數、SessionAttribute中的參數、ModelAttitude中的參數異步
能夠看出,正式由於SpringMVC爲咱們提供了各類擴展以及便捷的使用,纔會處理各類各樣的狀況。代碼雖然不少,若是你知道了用法,反過來看代碼邏輯就會輕鬆得多(用結果推緣由,也就是過後諸葛亮)。async
@InitBinder,@ModelAttribute,@ControllerAdvice,@SessionAttribute你應該知道。ide
首先看afterPropertiesSet(實現了InitializingBean接口,回在bean初始化的時候調用)函數
@Override public void afterPropertiesSet() { // Do this first, it may add ResponseBody advice beans initControllerAdviceCache(); if (this.argumentResolvers == null) { List<HandlerMethodArgumentResolver> resolvers = getDefaultArgumentResolvers(); this.argumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers); } if (this.initBinderArgumentResolvers == null) { List<HandlerMethodArgumentResolver> resolvers = getDefaultInitBinderArgumentResolvers(); this.initBinderArgumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers); } if (this.returnValueHandlers == null) { List<HandlerMethodReturnValueHandler> handlers = getDefaultReturnValueHandlers(); this.returnValueHandlers = new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers); } }
這個方法能夠看出,就是初始化@ControllerAdvice註解標註的類,裏面的邏輯就是ui
核心代碼以下:
private void initControllerAdviceCache() { List<ControllerAdviceBean> beans = ControllerAdviceBean.findAnnotatedBeans(getApplicationContext()); AnnotationAwareOrderComparator.sort(beans); List<Object> requestResponseBodyAdviceBeans = new ArrayList<Object>(); for (ControllerAdviceBean bean : beans) { Set<Method> attrMethods = MethodIntrospector.selectMethods(bean.getBeanType(), MODEL_ATTRIBUTE_METHODS); if (!attrMethods.isEmpty()) { this.modelAttributeAdviceCache.put(bean, attrMethods); } Set<Method> binderMethods = MethodIntrospector.selectMethods(bean.getBeanType(), INIT_BINDER_METHODS); if (!binderMethods.isEmpty()) { this.initBinderAdviceCache.put(bean, binderMethods); } if (RequestBodyAdvice.class.isAssignableFrom(bean.getBeanType())) { requestResponseBodyAdviceBeans.add(bean); } if (ResponseBodyAdvice.class.isAssignableFrom(bean.getBeanType())) { requestResponseBodyAdviceBeans.add(bean); } } if (!requestResponseBodyAdviceBeans.isEmpty()) { this.requestResponseBodyAdvice.addAll(0, requestResponseBodyAdviceBeans); } }
其中 MODEL_ATTRIBUTE_METHODS和INIT_BINDER_METHODS是靜態類
public static final MethodFilter MODEL_ATTRIBUTE_METHODS = new MethodFilter() { @Override public boolean matches(Method method) { return ((AnnotationUtils.findAnnotation(method, RequestMapping.class) == null) && (AnnotationUtils.findAnnotation(method, ModelAttribute.class) != null)); } };
public static final MethodFilter INIT_BINDER_METHODS = new MethodFilter() { @Override public boolean matches(Method method) { return AnnotationUtils.findAnnotation(method, InitBinder.class) != null; } };
if (this.argumentResolvers == null) { List<HandlerMethodArgumentResolver> resolvers = getDefaultArgumentResolvers(); this.argumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers); }
首先是使用getDefaultArgumentResolvers 獲取默認的ArgumentResolver類,而後封裝成一個Composite放入到argumentResolvers中。默認的ArgumentResolver有以下:
private List<HandlerMethodArgumentResolver> getDefaultArgumentResolvers() { List<HandlerMethodArgumentResolver> resolvers = new ArrayList<HandlerMethodArgumentResolver>(); // 基於註釋相關參數解析器,從名字就能夠看出來分別對應哪些註解 resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), false)); resolvers.add(new RequestParamMapMethodArgumentResolver()); resolvers.add(new PathVariableMethodArgumentResolver()); resolvers.add(new PathVariableMapMethodArgumentResolver()); resolvers.add(new MatrixVariableMethodArgumentResolver()); resolvers.add(new MatrixVariableMapMethodArgumentResolver()); resolvers.add(new ServletModelAttributeMethodProcessor(false)); resolvers.add(new RequestResponseBodyMethodProcessor(getMessageConverters(), this.requestResponseBodyAdvice)); resolvers.add(new RequestPartMethodArgumentResolver(getMessageConverters(), this.requestResponseBodyAdvice)); resolvers.add(new RequestHeaderMethodArgumentResolver(getBeanFactory())); resolvers.add(new RequestHeaderMapMethodArgumentResolver()); resolvers.add(new ServletCookieValueMethodArgumentResolver(getBeanFactory())); resolvers.add(new ExpressionValueMethodArgumentResolver(getBeanFactory())); resolvers.add(new SessionAttributeMethodArgumentResolver()); resolvers.add(new RequestAttributeMethodArgumentResolver()); // 基於類型的參數解析器 resolvers.add(new ServletRequestMethodArgumentResolver()); resolvers.add(new ServletResponseMethodArgumentResolver()); resolvers.add(new HttpEntityMethodProcessor(getMessageConverters(), this.requestResponseBodyAdvice)); resolvers.add(new RedirectAttributesMethodArgumentResolver()); resolvers.add(new ModelMethodProcessor()); resolvers.add(new MapMethodProcessor()); resolvers.add(new ErrorsMethodArgumentResolver()); resolvers.add(new SessionStatusMethodArgumentResolver()); resolvers.add(new UriComponentsBuilderMethodArgumentResolver()); // 自定義的參數解析器 if (getCustomArgumentResolvers() != null) { resolvers.addAll(getCustomArgumentResolvers()); } // 針對全部類型的參數解析器 resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), true)); resolvers.add(new ServletModelAttributeMethodProcessor(true)); return resolvers; }
加載的默認解析器不少,主要分爲4類
if (this.initBinderArgumentResolvers == null) { List<HandlerMethodArgumentResolver> resolvers = getDefaultInitBinderArgumentResolvers(); this.initBinderArgumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers); } if (this.returnValueHandlers == null) { List<HandlerMethodReturnValueHandler> handlers = getDefaultReturnValueHandlers(); this.returnValueHandlers = new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers); }
和上面相似,就不在贅述
RequestMappingHandlerAdapter實現了HandlerAdapter,其中supports和getLastModified的方法很簡單,重點是看
ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;
這個接口。
這個接口的實現是在handleInternal函數中
@Override protected ModelAndView handleInternal(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception { ModelAndView mav; //判斷request參數,1. 判斷method是否一致(GET,POST),若是須要session判斷是否有session checkRequest(request); // 是不是同步的,默認是false if (this.synchronizeOnSession) { HttpSession session = request.getSession(false); if (session != null) { Object mutex = WebUtils.getSessionMutex(session); synchronized (mutex) { //調用handler mav = invokeHandlerMethod(request, response, handlerMethod); } } else { // No HttpSession available -> no mutex necessary mav = invokeHandlerMethod(request, response, handlerMethod); } } else { // No synchronization on session demanded at all... mav = invokeHandlerMethod(request, response, handlerMethod); } // 若是response頭裏面沒有Cache-Control,而且該handler對應的類有@SessionAttributes,則 // 設置Cache-Control爲non—cache if (!response.containsHeader(HEADER_CACHE_CONTROL)) { //使用HandlerMethod.getBeanType()做爲key,在緩存sessionAttributesHandlerCache。 if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) { applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers); } else { prepareResponse(response); } } return mav; }
這個最主要的方法就是invokeHandlerMethod,這個方法就包含了參數綁定、執行Handler、處理返回值的整個流程,主要步驟註釋上都有標明。
protected ModelAndView invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception { //首先是利用HttpServletRequest和HttpServletResponse封裝成ServletWebRequest,在參數解析器中入參就是這個類。 ServletWebRequest webRequest = new ServletWebRequest(request, response); try { //@InitBinder註解的方法獲取(先從緩存獲取,不然從類定義中獲取放入緩存), //最後利用獲取的數據建立WebDataBinderFactory WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod); //處理@SessiohAttributes和@ModeAttribute //看名字就是是爲Model服務的,例如@SessiohAttributes和 //@ModeAttribute(包括全局和局部,具體看初始化流程)註解參數加入的model中等 ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory); //ServletInvocableHandlerMethod繼承InvocableHandlerMethod(實現了HandlerMethod接口)。 //實際處理請求就是經過這個類執行,包括參數綁定、請求處理調用和返回值。 ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod); // 設置參數解析器 invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers); // 設置返回值處理器,封裝成ModelAndView invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers); // InitBinder相關函數 invocableMethod.setDataBinderFactory(binderFactory); // 參數查詢 invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer); // 新建ModelAndViewContainer ModelAndViewContainer mavContainer = new ModelAndViewContainer(); // 設置falshMap mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request)); // 將@SessionAttributes和@ModelAttribute的相關屬性設置到Model中 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; } //更新model信息, // 這裏面須要注意,若是@SessionStatus若是Complate爲true,則會清除,這裏須要注意的是清除實在Handler處理完後才調用。 // 根據mavContainer建立ModelAndView(若是有RedirectAttributes,設置FlashMap) return getModelAndView(mavContainer, modelFactory, webRequest); } finally { webRequest.requestCompleted(); } }
要理解整個處理流程,還須要對方法中涉及的一些對象進行分析,下面就會對ModelAndViewContainer、ModelFactory等類進行分析
ModelAndViewContainer就是負責保存Model、View等等功能
private boolean ignoreDefaultModelOnRedirect = false; // view對象,也能夠是String類型的邏輯視圖 private Object view; // 默認Model private final ModelMap defaultModel = new BindingAwareModelMap(); //redirect Model private ModelMap redirectModel; //返回Redirect 視圖表示 private boolean redirectModelScenario = false; //SessionAttribute使用完成標誌 private final SessionStatus sessionStatus = new SimpleSessionStatus(); //請求是否完成標誌 private boolean requestHandled = false;
這個類的最主要的方法是getModel()
public ModelMap getModel() { if (useDefaultModel()) { return this.defaultModel; } else { if (this.redirectModel == null) { this.redirectModel = new ModelMap(); } return this.redirectModel; } }
private boolean useDefaultModel() { return (!this.redirectModelScenario || (this.redirectModel == null && !this.ignoreDefaultModelOnRedirect)); }
從代碼裏面看出,使用defaultModel的狀況有:一、返回非redirect視圖。二、返回的雖然是redirect視圖,但redirectMap不爲空而且ignoreDefaultModelOnRedirect爲false的狀況
在說ModelFactory以前必須先了解SessionAttributesHandler。SessionAttributesHandler就是用於處理@SessionAttitudes註解的。
@SessionAttitudes的功能簡單來講,就是把一些數據在放入Model的時候保存起來,而後在其餘Handler中的Model方法中能夠獲取。至關於用session來傳遞參數。只不過咱們能夠方便的一鍵刪除這些。
SessionAttributesHandler中的屬性有:
// 保存@SessionAttributes註解裏的value private final Set<String> attributeNames = new HashSet<String>(); // 保存@SessionAttributes註解裏的types private final Set<Class<?>> attributeTypes = new HashSet<Class<?>>(); // 保存@SessionAttributes中當前已知的Session Name private final Set<String> knownAttributeNames = Collections.newSetFromMap(new ConcurrentHashMap<String, Boolean>(4)); // 實際保存數據的處理類,可是數據並非在這個類裏,默認是保存在Session中 private final SessionAttributeStore sessionAttributeStore;
除此以外,還提供了而且提供增刪查的功能。查詢全部SessionAttribute和刪除全部SessionAttribute都是刪除的是knownAttributeNames中的
public void initModel(NativeWebRequest request, ModelAndViewContainer container, HandlerMethod handlerMethod) throws Exception { // 第一步:獲取全部SessionAttribute中的參數,merge到ModelAndViewContainer中 Map<String, ?> sessionAttributes = this.sessionAttributesHandler.retrieveAttributes(request); container.mergeAttributes(sessionAttributes); // 第二步:調用@ModelAttritude註解的方法(結果加入到ModelAndViewContainer中) invokeModelAttributeMethods(request, container); // 第三步:處理使用@ModelAttribute註解的參數(須要在@SessionAttribute中存在),最後加入到ModelAndViewContainer for (String name : findSessionAttributeArguments(handlerMethod)) { if (!container.containsAttribute(name)) { Object value = this.sessionAttributesHandler.retrieveAttribute(request, name); if (value == null) { throw new HttpSessionRequiredException("Expected session attribute '" + name + "'", name); } container.addAttribute(name, value); } } }
private void invokeModelAttributeMethods(NativeWebRequest request, ModelAndViewContainer container) throws Exception { while (!this.modelMethods.isEmpty()) { InvocableHandlerMethod modelMethod = getNextModelMethod(container).getHandlerMethod(); ModelAttribute ann = modelMethod.getMethodAnnotation(ModelAttribute.class); if (container.containsAttribute(ann.name())) { if (!ann.binding()) { container.setBindingDisabled(ann.name()); } continue; } // 根據request調用HandlerMethod,須要說明的是其中的參數使用了ArgumentResolver,所以注入的Model // 就是container中的model(session,httpRequest相似也有對用的ArgumentResolver) Object returnValue = modelMethod.invokeForRequest(request, container); // 如何返回的參數不爲空,則把參數設置到model中 if (!modelMethod.isVoid()){ // 優先使用註解中的名字,沒有則根據返回的class類型設置名字 String returnValueName = getNameForReturnValue(returnValue, modelMethod.getReturnType()); if (!ann.binding()) { container.setBindingDisabled(returnValueName); } if (!container.containsAttribute(returnValueName)) { container.addAttribute(returnValueName, returnValue); } } }
所以,分析到這裏,Model中設置參數的優先級就知道了
FlashMap>SessionAttribute>ModelAttribute方法(全局優先於局部)>ModelAttribute參數(全局優先於局部)
未完待續