1. 概述
handlerAdpater的实现类总共有5个(其中一个已经废弃),而且层级都很少。
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个方法。
- support——判断handler是否适用于当前HandlerAdapter
- handler——根据handler返回ModelAndView
- getLastModified——看名字就知道就是返回最后修改时间
2. HttpRequestHandlerAdapter、SimpleServletHandlerAdapter、SimpleControllerHandlerAdapter
这3个adapter很简单,都是分别针对特定的handler的类型,直接调用就可以了
@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); }
3. RequestMappingHandlerAdapter
RequestMappingHandlerAdapter是AbstractHandlerMethodAdapter的唯一实现类
这个处理就比较复杂(但正是因为他为我们带来了快捷的使用方式)。但总的来说做了3件事
- 准备好Handler所需要的参数
- 使用Handler处理request请求
- 把Handler处理后的结果统一转换为ModelAndView
3.1 准备好Handler所需要的参数
这个步骤应该是3步中最复杂的,抛开直接把Request中的参数(url中的或者body中的)以外、cookie中的参数、session中的参数,还要处理Spring MVC中的一些东西,例如FlashMap中的参数、SessionAttribute中的参数、ModelAttitude中的参数
可以看出,正式因为SpringMVC为我们提供了各种扩展以及便捷的使用,才会处理各种各样的情况。代码虽然很多,如果你知道了用法,反过来看代码逻辑就会轻松得多(用结果推原因,也就是事后诸葛亮)。
@InitBinder,@ModelAttribute,@ControllerAdvice,@SessionAttribute你应该知道。
3.2 初始化
首先看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); } }
3.2.1 initControllerAdviceCache
这个方法可以看出,就是初始化@ControllerAdvice注解标注的类,里面的逻辑就是
- 找出@ModelAttribute注解(并且没有@RequestMapping)注解的方法和@InitBinder注解的方法,分别放入modelAttributeAdviceCache和initBinderAdviceCache中
- 找出RequestBodyAdvice和ResponseBodyAdvice实现类,放入requestResponseBodyAdvice
核心代码如下:
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; } };
3.2.2 初始化ArgumentResolvers
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类
- 针对注解的参数解析器,根据名字就可以知道是针对那些哪些注解
- 基于参数类型的解析器(例如,参数里面的HttpServletRequest,HttpSession,Model等)
- 自定义参数解析器,用户可以自己写一个resolver,然后注入到customArgumentResolvers这个参数中。不过由于自定义的解析器顺序是在上面2种解析器后面,如果1、2已经解析成功的,就不会再使用自定义的解析器
- 针对所有类型的解析器(例如@RequestParamter注解)
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); }
和上面类似,就不在赘述
3.3 调用
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等类进行分析
4. ModelAndViewContainer
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;
- 默认视图使用的是BindingAwareModelMap这个类,同时继承了Model和ModelMap这2个类(因此在参数里设置 Model 或者ModelMap 都是同一个对象)
- 如果是redirect视图,那么defaultModel中的参数就没有任何用处,同理非redirect视图的Redirect Model也是没用的
这个类的最主要的方法是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的情况有:1、返回非redirect视图。2、返回的虽然是redirect视图,但redirectMap不为空并且ignoreDefaultModelOnRedirect为false的情况
5. ModelFactory
5.1 SessionAttributesHandler
在说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中的
5.2 ModelFactory 初始化
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); } } }
- 第一步比较简单,直接从上面介绍过的SessionAttributesHandler中获取所有SessionAttribute参数。然后merge到ModelAndViewContainer(不覆盖原有的)
- 第二步就是调用invokeModelAttributeMethods处理@ModelAttritude注解的方法. 重要说明见注释
-
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); } } }
- 第三步:处理使用@ModelAttribute注解的参数,前提是SessionAttribute中有,并且Model中并不存在才会加入。
因此,分析到这里,Model中设置参数的优先级就知道了
FlashMap>SessionAttribute>ModelAttribute方法(全局优先于局部)>ModelAttribute参数(全局优先于局部)
未完待续