写点什么

SpringMVC 源码分析 -HandlerAdapter(2)-RequestMappingHandlerAdapter 的初始化

用户头像
Brave
关注
发布于: 3 小时前

一,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 的三个接口方法分别调用了三个模板方法:

  1. supportsInternal;

  2. handleInternal;

  3. getLastModifiedInternal;

具体逻辑由其子类 RequestMappingHandlerAdapter 实现;


AbstractHandlerMethodAdapter#support 中有一个条件:Handler 必须是 HandlerMethod 类型;

另外,还实现了 Order 接口,可以在配置时设置顺序,默认优先级最低;


三,RequestMappingHandlerAdapter 组件


RequestMappingHandlerAdapter 可以说是整个 SpringMVC 框架中最复杂的一个组件:

RequestMappingHandlerAdapter 继承自 AbstractHandlerMethodAdapter,实现了三个模板方法:

  1. supportsInternal;

  2. handlerInternal;

  3. 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 步:

  1. 准备处理器需要的数据;

  2. 使用处理器处理请求;

  3. 处理返回值,将不同类型的返回值统一处理成 ModelAndView 类型;


第一步,根据处理器的需要设置参数,而参数的类型、数量都不确定;

这个过程中使用了大量组件,使代码不容器理解,所以这一步是最为复杂的;


关于绑定参数的一些问题:

  1. 都有哪些参数需要绑定;

  2. 参数值的来源有哪些;

  3. 具体进行绑定的方法;


需要绑定的参数是根据方法确定的,

除了实际处理请求的处理器,还有注释了 @ModelAttribute 和注释了 @InitBinder 的方法;


参数的来源有 6 个:

  1. request 中的相关参数,包含 url 参数,post 参数,请求头参数;

  2. cookie 中的参数;

  3. session 中的参数;

  4. 设置到 FlashMap 中的参数,这类参数用于 redirect 的参数传递;

  5. SessionAttributes 传递的参数,这类参数通过 @SessionAttributes 注解传递;

  6. 注释了 @ModelAttribute 的方法进行设置的参数;


  • 前三种参数通过 request 进行管理;

  • 后三种参数通过 Model 进行管理;

  • 第四种参数,在请求处理前将之前保存的设置到 Model,处理完如果需要将 model 中的值设置到 FlashMap;

  • 第五种、第六种参数使用 ModelFactory 管理;


参数的解析:

参数具体解析是使用 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 中有四类解析器:

  1. 基于注解的参数解析器;

  2. 基于类型的参数解析器;

  3. 自定义参数解析器;

  4. 可解析所有类型的解析器;

从源码中可以看出,自定义的解析器是在前面两种都无法解析是才会使用到,这个顺序是无法改变的;

例如:如果想自己写一个解析器来解析 @PathVariable 注释的 PathVariable 参数,是无法实现的,

即使写出来并注册到 RequestMappingHanderAdapter 中也不会被调用;


关于 RequestMappingHanderAdapter 的初始化,主要就是初始化了这 6 个属性;



RequestMappingHanderAdapter 处理请求的入口方法是 handleInternal,后面就要针对这个具体处理请求的方法进行分析了;

用户头像

Brave

关注

还未添加个人签名 2018.12.13 加入

还未添加个人简介

评论

发布
暂无评论
SpringMVC源码分析-HandlerAdapter(2)-RequestMappingHandlerAdapter的初始化