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
supportsInternal实现:
@Override
protected boolean supportsInternal(HandlerMethod handlerMethod) {
return true;
}
supportsInternal:直接返回true,也就是没有添加任何判断逻辑
所以只需要满足父类的HandlerMethod类型的要求就可以了
getLastModifiedInternal实现:
@Override
protected long getLastModifiedInternal(HttpServletRequest request, HandlerMethod handlerMethod) {
return -1;
}
直接返回了-1
最重要的是handlerInternal方法,正是这个方法实际使用了Handler来处理请求
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方法中实现的
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方法主要初始化了:
除去initControllerAdviceCache方法(下面说)
1)HandlerMethodArgumentResolverComposite argumentResolvers;
从返回类型可以看出这是一个给处理器方法解析参数的解析器集合
用于给处理器方法和注释了@ModelAttribute的方法设置参数
2)HandlerMethodArgumentResolverComposite initBinderArgumentResolvers;
从返回类型可以看出这是一个给处理器方法解析参数的解析器集合
用于给注释了@InitBinder的方法设置参数
3)HandlerMethodReturnValueHandlerComposite returnValueHandlers;
用于将处理器的返回值处理成ModelAndView的类型
另外,从返回类型XXXComposite可以看出,这里用到了一个组合模式,其中封装了多种组件
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,initBinderArgumentResolversreturnValueHandlers属性的初始化
这三个属性的初始化都是调用了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,
后面就要针对这个具体处理请求的方法进行分析了