一,RequestMappingHandlerAdapter 的继承结构
RequestMappingHandlerAdapter 继承自 AbstractHandlerMethodAdapter:
二,AbstractHandlerMethodAdapter 简介
源码:
package org.springframework.web.servlet.mvc.method;
public abstract class AbstractHandlerMethodAdapter extends WebContentGenerator implements HandlerAdapter, Ordered {
private int order = Ordered.LOWEST_PRECEDENCE;
public AbstractHandlerMethodAdapter() { super(false); }
public void setOrder(int order) { this.order = order; }
@Override public int getOrder() { return this.order; }
@Override public final boolean supports(Object handler) { return (handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler)); }
// 模板方法,由子类实现 protected abstract boolean supportsInternal(HandlerMethod handlerMethod);
@Override public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
return handleInternal(request, response, (HandlerMethod) handler); }
// 模板方法,由子类实现 protected abstract ModelAndView handleInternal(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception;
@Override public final long getLastModified(HttpServletRequest request, Object handler) { return getLastModifiedInternal(request, (HandlerMethod) handler); } // 模板方法,由子类实现 protected abstract long getLastModifiedInternal(HttpServletRequest request, HandlerMethod handlerMethod);
}
复制代码
AbstractHandlerMethodAdapter 实现了 HandlerAdapter 接口,
HandlerAdapter 的三个接口方法分别调用了三个模板方法:
supportsInternal;
handleInternal;
getLastModifiedInternal;
具体逻辑由其子类 RequestMappingHandlerAdapter 实现;
AbstractHandlerMethodAdapter#support 中有一个条件:Handler 必须是 HandlerMethod 类型;
另外,还实现了 Order 接口,可以在配置时设置顺序,默认优先级最低;
三,RequestMappingHandlerAdapter 组件
RequestMappingHandlerAdapter 可以说是整个 SpringMVC 框架中最复杂的一个组件:
RequestMappingHandlerAdapter 继承自 AbstractHandlerMethodAdapter,实现了三个模板方法:
supportsInternal;
handlerInternal;
getLastModifiedInternal;
1,supportsInternal 的实现
@Overrideprotected boolean supportsInternal(HandlerMethod handlerMethod) { return true;}
复制代码
supportsInternal:直接返回 true,也就是没有添加任何判断逻辑;
所以,只需要满足父类是 HandlerMethod 类型的要求就可以了;
2,getLastModifiedInternal 的实现
@Overrideprotected long getLastModifiedInternal(HttpServletRequest request, HandlerMethod handlerMethod) { return -1; // 直接返回了-1}
复制代码
最重要的就是 handlerInternal 这个方法,正是这个方法实际使用了 Handler 进行请求处理;
3,handlerInternal 的实现
handlerInternal 使用 Handler 处理请求,整个处理过程分为 3 步:
准备处理器需要的数据;
使用处理器处理请求;
处理返回值,将不同类型的返回值统一处理成 ModelAndView 类型;
第一步,根据处理器的需要设置参数,而参数的类型、数量都不确定;
这个过程中使用了大量组件,使代码不容器理解,所以这一步是最为复杂的;
关于绑定参数的一些问题:
都有哪些参数需要绑定;
参数值的来源有哪些;
具体进行绑定的方法;
需要绑定的参数是根据方法确定的,
除了实际处理请求的处理器,还有注释了 @ModelAttribute 和注释了 @InitBinder 的方法;
参数的来源有 6 个:
request 中的相关参数,包含 url 参数,post 参数,请求头参数;
cookie 中的参数;
session 中的参数;
设置到 FlashMap 中的参数,这类参数用于 redirect 的参数传递;
SessionAttributes 传递的参数,这类参数通过 @SessionAttributes 注解传递;
注释了 @ModelAttribute 的方法进行设置的参数;
参数的解析:
参数具体解析是使用 HandlerMethodArgumentResolve 类型的组件完成不同类型的参数使用不同的 ArgumentResolve 来解析
有的Resolve内部使用了WebDataBinder,可以通过注释了@InitBinder的方法来初始化注释了@InitBinder的方法需要绑定参数,也是不确定的,它使用的和Handler使用的不是一套ArgumentResolve
注释了@ModelAttribute的方法也需要绑定参数,它使用的和Handler使用的是同一套ArgumentResolve
复制代码
四,RequestMappingHandlerAdapter 的初始化
RequestMappingHandlerAdapter 的创建是在 afterPropertiesSet 方法中实现的
1,afterPropertiesSet
afterPropertiesSet 源码
@Overridepublic void afterPropertiesSet() { //@ControllerAdvice注释的类相关的 // modelAttributeAdviceCache, // initBinderAdviceCache, // requestResponseBodyAdvice // Do this first, it may add ResponseBody advice beans initControllerAdviceCache();
// 初始化 argumentResolvers if (this.argumentResolvers == null) { List<HandlerMethodArgumentResolver> resolvers = getDefaultArgumentResolvers(); this.argumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers); } // 初始化 initBinderArgumentResolvers if (this.initBinderArgumentResolvers == null) { List<HandlerMethodArgumentResolver> resolvers = getDefaultInitBinderArgumentResolvers(); this.initBinderArgumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers); } // 初始化 returnValueHandlers if (this.returnValueHandlers == null) { List<HandlerMethodReturnValueHandler> handlers = getDefaultReturnValueHandlers(); this.returnValueHandlers = new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers); }}
复制代码
afterPropertiesSet 方法主要初始化了 argumentResolvers、initBinderArgumentResolvers、returnValueHandlers:
除去 initControllerAdviceCache 方法(下面说)
1)HandlerMethodArgumentResolverComposite argumentResolvers; 从返回类型可以看出这是一个给处理器方法解析参数的解析器集合 用于给处理器方法和注释了@ModelAttribute的方法设置参数
2)HandlerMethodArgumentResolverComposite initBinderArgumentResolvers; 从返回类型可以看出这是一个给处理器方法解析参数的解析器集合 用于给注释了@InitBinder的方法设置参数 3)HandlerMethodReturnValueHandlerComposite returnValueHandlers; 用于将处理器的返回值处理成ModelAndView的类型
另外,从返回类型XXXComposite可以看出,这里用到了一个组合模式,其中封装了多种组件
复制代码
2,initControllerAdviceCache
initControllerAdviceCache 方法:初始化了 @ControllerAdvice 注释类相关的集合
1)Map<ControllerAdviceBean, Set<Method>> modelAttributeAdviceCache 用于缓存@ControllerAdvice注解的类中注解了@ModelAttribute的方法
2)Map<ControllerAdviceBean, Set<Method>> initBinderAdviceCache 用于缓存@ControllerAdvice注解的类中注解了@InitBinder的方法 3)List<Object> requestResponseBodyAdvice 用于保存实现了RequestBodyAdvice和ResponseBodyAdvice接口的类
复制代码
initControllerAdviceCache 源码:
private void initControllerAdviceCache() { if (getApplicationContext() == null) { return; } if (logger.isInfoEnabled()) { logger.info("Looking for @ControllerAdvice: " + getApplicationContext()); }
// 获取所有注释了@ControllerAdvice注解的Bean,并根据Order排序 List<ControllerAdviceBean> beans = ControllerAdviceBean.findAnnotatedBeans(getApplicationContext()); AnnotationAwareOrderComparator.sort(beans);
List<Object> requestResponseBodyAdviceBeans = new ArrayList<Object>();
// 遍历所有@ControllerAdvice注解的Bean for (ControllerAdviceBean bean : beans) { // 获取添加了@ModelAttribute注解且没有@RequestMapping注解的方法 Set<Method> attrMethods = MethodIntrospector.selectMethods(bean.getBeanType(), MODEL_ATTRIBUTE_METHODS); if (!attrMethods.isEmpty()) { this.modelAttributeAdviceCache.put(bean, attrMethods); if (logger.isInfoEnabled()) { logger.info("Detected @ModelAttribute methods in " + bean); } } // 获取添加了@InitBinder注解的方法 Set<Method> binderMethods = MethodIntrospector.selectMethods(bean.getBeanType(), INIT_BINDER_METHODS); if (!binderMethods.isEmpty()) { this.initBinderAdviceCache.put(bean, binderMethods); if (logger.isInfoEnabled()) { logger.info("Detected @InitBinder methods in " + bean); } } // 获取实现了RequestBodyAdvice接口的bean if (RequestBodyAdvice.class.isAssignableFrom(bean.getBeanType())) { requestResponseBodyAdviceBeans.add(bean); if (logger.isInfoEnabled()) { logger.info("Detected RequestBodyAdvice bean in " + bean); } } // 获取实现了ResponseBodyAdvice接口的bean if (ResponseBodyAdvice.class.isAssignableFrom(bean.getBeanType())) { requestResponseBodyAdviceBeans.add(bean); if (logger.isInfoEnabled()) { logger.info("Detected ResponseBodyAdvice bean in " + bean); } } }
// 将实现了RequestBodyAdvice和ResponseBodyAdvice接口的类放入requestResponseBodyAdviceBeans // 这里是放入顶部,说明通过@@ControllerAdvice注解实现接口的处理优先级最高 if (!requestResponseBodyAdviceBeans.isEmpty()) { this.requestResponseBodyAdvice.addAll(0, requestResponseBodyAdviceBeans); }}
复制代码
这里需要注意:
requestResponseBodyAdvice.addAll(0, requestResponseBodyAdviceBeans)RequestBodyAdvice和ResponseBodyAdvice的实现有两种注册方法1,注解注册到RequestMappingHandlerAdapter2,通过@Controller注解SpringMVC自己发现并注册所以使用@Controller注解注册的方式优先级要更高一些
复制代码
MODEL_ATTRIBUTE_METHODS 和 INIT_BINDER_METHODS 是两个静态过滤器,
用于传入 MethodIntrospector.selectMethods 过滤包含某注解的方法:
// 判断方法是否有@InitBinder注解public static final MethodFilter INIT_BINDER_METHODS = new MethodFilter() { @Override public boolean matches(Method method) { return AnnotationUtils.findAnnotation(method, InitBinder.class) != null; }};
// 判断方法是否有@ModelAttribute注解且不具有@RequestMapping注解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)); }};
复制代码
问题:为什么要找有 @ModelAttribute 注解且不具有 @RequestMapping 注解的方法?
@ModelAttribute 和 @RequestMapping 同时存在的方法,
只是将返回值设置到 Model,而不是作为 View 使用了,但不会提前执行;
argumentResolvers、initBinderArgumentResolvers、returnValueHandlers 属性的初始化:
这三个属性的初始化都是调用了 getDefaultXXX 得到相应的值,然后设置对应的属性;
以 getDefaultArgumentResolvers 为例:
private List<HandlerMethodArgumentResolver> getDefaultArgumentResolvers() { List<HandlerMethodArgumentResolver> resolvers = new ArrayList<HandlerMethodArgumentResolver>();
// 1,基于注解的参数解析器 // Annotation-based argument resolution 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());
// 2,基于类型的参数解析器 // Type-based argument resolution 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());
// 3,自定义参数解析器 // Custom arguments if (getCustomArgumentResolvers() != null) { resolvers.addAll(getCustomArgumentResolvers()); }
// 4,可解析所有类型的解析器 // Catch-all resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), true)); resolvers.add(new ServletModelAttributeMethodProcessor(true));
return resolvers;}
复制代码
getDefaultArgumentResolvers 中有四类解析器:
基于注解的参数解析器;
基于类型的参数解析器;
自定义参数解析器;
可解析所有类型的解析器;
从源码中可以看出,自定义的解析器是在前面两种都无法解析是才会使用到,这个顺序是无法改变的;
例如:如果想自己写一个解析器来解析 @PathVariable 注释的 PathVariable 参数,是无法实现的,
即使写出来并注册到 RequestMappingHanderAdapter 中也不会被调用;
关于 RequestMappingHanderAdapter 的初始化,主要就是初始化了这 6 个属性;
RequestMappingHanderAdapter 处理请求的入口方法是 handleInternal,后面就要针对这个具体处理请求的方法进行分析了;
评论