1.HandlerAdpter
- 前面我们解释了SpringMvc中的一个重要组件HandlerMapping。
- 现在我们来看另一个重要的组件HandlerAdapter,有关HandlerMapping于HandlerAdapter之间的关系我们做一个简单的回顾,HandlerMapping我们理解为干活的工具,而HandlerAdapter为使用工作干活的人。HandlerAdapter这个组件就是执行已经找到的HandlerMapping。
- HandlerAdpter有五个实现类,其中一个已经废弃。剩余4个分别为AbstractHandlerMethodAdapter,HttpRequestHandlerAdapter,SimpleControllerHandlerAdapter,SimpleServletHandlerAdapter。其中AbstractHandlerMethodAdapter的实现最为复杂,其他三个都比较简单。
- HandlerAdpter组件为SpringMvc中最为复杂的一个组件,因为涉及到了参数的绑定,Handler的执行,返回值的处理等等。
- 所以我们主要分析的是AbstractHandlerMethodAdapter相关的类。
2.RequestMappingHandlerAdapter
AbstractHandlerMethodAdapter是一个抽象类,类中的结构比较简单,调用了三个模板方法(抽象方法),最终都由子类去实现。
最终的实现类为RequestMappingHandlerAdapter,该类继承AbstractHandlerMethodAdapter,并且实现了父类的抽象方法。
类中最核心的方法为handleInternal,该方法为使用HanlderMapping找到的Handler来处理请求,也就是执行Handler的方法。
该方法主要可分为三个步骤,1.准备方法所需要的参数(请求参数)。2.执行Handler方法处理请求。3.处理返回值,返回值统一为ModelAndView。
其中第一步最为复杂,因为参数的来源比较多,比如request中的参数,链接中的参数,post参数,请求头参数,cookie参数,session中的参数,FlashMap参数,SessionAttribute传递的参数,ModelAttribute注解的参数等。
该类的初始化方法为afterProperties,因为实现了InitialzingBean接口,Spring在加载该类的时候会自动调用afterPropertiesSet方法。
该方法中初始化了6个全局变量。
分别为
argumentResolvers,initBinderArgumentResolvers,returnValueHandlers,modelAttributeAdviceCache,initBinderAdviceCache,
responseBodyAdvice。
/**
* RequestMappingHandlerAdapter类中的afterPropertiesSet方法
*/
@Override
public void afterPropertiesSet() {
//处理注解了@ControllerAdvice注解的类
//处理类中带有@InitBinder注解和@ModelAttribute注解的方法,相当于全局的,将结果缓存
//处理实现了ResponseBodyAdvice接口的类
//方法中初始化了modelAttributeAdviceCache,initBinderAdviceCache,responseBodyAdvice
initControllerAdviceCache();
//初始化argumentResolvers,给处理器方法和注解了@ModelAttribute方法设置参数解析器
if (this.argumentResolvers == null) {
List<HandlerMethodArgumentResolver> resolvers = getDefaultArgumentResolvers();
this.argumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
}
//初始化initBinderArgumentResolvers,给注解了@InitBinder方法设置参数解析器
if (this.initBinderArgumentResolvers == null) {
List<HandlerMethodArgumentResolver> resolvers = getDefaultInitBinderArgumentResolvers();
this.initBinderArgumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
}
//初始化returnValueHandlers,将所有返回值统一处理成ModelAndView类型
if (this.returnValueHandlers == null) {
List<HandlerMethodReturnValueHandler> handlers = getDefaultReturnValueHandlers();
this.returnValueHandlers = new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers);
}
}
来看一下initControllerAdviceCache方法,上面提到该方法中初始化了三个变量。
/**
* RequestMappingHandlerAdapter类中的initControllerAdviceCache方法
*/
private void initControllerAdviceCache() {
if (getApplicationContext() == null) {
return;
}
//查询所有带有@ControllerAdvice注解的类
List<ControllerAdviceBean> beans = ControllerAdviceBean.findAnnotatedBeans(getApplicationContext());
//根据order属性进行排序
Collections.sort(beans, new OrderComparator());
List<Object> responseBodyAdviceBeans = new ArrayList<Object>();
//遍历获取到的所有的Bean,解析类中带有ModelAttribute注解和InitBinder注解的方法
for (ControllerAdviceBean bean : beans) {
//获取所有带有@ModelAttribute注解并且没有RequestMapping注解的方法
Set<Method> attrMethods = HandlerMethodSelector.selectMethods(bean.getBeanType(), MODEL_ATTRIBUTE_METHODS);
if (!attrMethods.isEmpty()) {
//保存到modelAttributeAdviceCache中
this.modelAttributeAdviceCache.put(bean, attrMethods);
}
//获取所有带有@InitBinder注解的方法
Set<Method> binderMethods = HandlerMethodSelector.selectMethods(bean.getBeanType(), INIT_BINDER_METHODS);
if (!binderMethods.isEmpty()) {
//保存到initBinderAdviceCache中
this.initBinderAdviceCache.put(bean, binderMethods);
}
//判断Bean是否实现了ResponseBodyAdvice接口
if (ResponseBodyAdvice.class.isAssignableFrom(bean.getBeanType())) {
//保存到responseBodyAdviceBeans集合中
responseBodyAdviceBeans.add(bean);
}
}
if (!responseBodyAdviceBeans.isEmpty()) {
//保存到responseBodyAdvice中
this.responseBodyAdvice.addAll(0, responseBodyAdviceBeans);
}
}
来看一下另外三个属性是如何初始化的,代码基本一致,逻辑也比较简单,以argumentResolvers为例,初始化方法为getDefaultArgumentResolvers。
/**
* RequestMappingHandlerAdapter类中的getDefaultArgumentResolvers方法
*/
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()));
resolvers.add(new RequestPartMethodArgumentResolver(getMessageConverters()));
resolvers.add(new RequestHeaderMethodArgumentResolver(getBeanFactory()));
resolvers.add(new RequestHeaderMapMethodArgumentResolver());
resolvers.add(new ServletCookieValueMethodArgumentResolver(getBeanFactory()));
resolvers.add(new ExpressionValueMethodArgumentResolver(getBeanFactory()));
//按参数类型解析的解析器
resolvers.add(new ServletRequestMethodArgumentResolver());
resolvers.add(new ServletResponseMethodArgumentResolver());
resolvers.add(new HttpEntityMethodProcessor(getMessageConverters()));
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;
}
解析参数时,SpringMvc采用了责任链模式,也就是说,通过上面的代码,添加了很多的参数解析器。而自定义解析器,与SpringMvc的内部解析器的使用顺序是无法改变的,只有当前面的解析器解析不了的时候,才会轮到自定义解析器去解析参数。
我们简单的做一个总结,在SpringMvc初始化的时候,会调用RequestMappingHandlerAdapter中的afterPropertiesSet方法,因为该类实现了InitialzingBean接口,所以afterPropertiesSet方法会被自动调用。
在方法中,对一些变量进行了初始化,并且添加了相关的解析器。
下一篇我们将分析处理请求的核心方法handleInternal。