一,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 的实现
@Override
protected boolean supportsInternal(HandlerMethod handlerMethod) {
return true;
}
复制代码
supportsInternal:直接返回 true,也就是没有添加任何判断逻辑;
所以,只需要满足父类是 HandlerMethod 类型的要求就可以了;
2,getLastModifiedInternal 的实现
@Override
protected 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 源码
@Override
public 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,注解注册到RequestMappingHandlerAdapter
2,通过@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,后面就要针对这个具体处理请求的方法进行分析了;
评论