《看透springMvc源代码分析与实践》学习笔记
SpringMVC 版本 4.1.5.RELEASE
HandlerAdapter的作用是具体使用HandlerMapping来干活的。
它在 DispatcherServlet.initHandlerAdapters(context)中被初始化,在DispatcherServlet.properties中配置,默认使用:HttpRequestHandlerAdapter, SimpleControllerHandlerAdapter, AnnotationMethodHandlerAdapter
.
HandlerAdapter接口定义了三个方法:
supports
: 判断是否支持掺入的Handlerhandle
: 使用Handle处理请求getLastModified
: 获取资源LastModified的值
HandlerAdapter 类图
HandlerAdapter的结构比较简单,一共有5类Adapter,其中只有RequestMappingHandlerAdapter
有两层结构,其他的只有一层,都是直接实现的HandlerAdapter接口。
HttpRequestHandlerAdapter , SimpleServletHandlerAdapter, SimpleControllerHandlerAdapter
HttpRequestHandlerAdapter , SimpleServletHandlerAdapter, SimpleControllerHandlerAdapter
分别适配 HttpRequestHandler,Servlet,Controller
类型的Handler,
方法非常简单,都是调用 handle
里固定的代码,代码如下:
//org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter
public class HttpRequestHandlerAdapter implements HandlerAdapter {
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
((HttpRequestHandler) handler).handleRequest(request, response);
return null;
}
}
//org.springframework.web.servlet.handler.SimpleServletHandlerAdapter
public class SimpleServletHandlerAdapter implements HandlerAdapter {
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
((Servlet) handler).service(request, response);
return null;
}
}
//org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter
public class SimpleControllerHandlerAdapter implements HandlerAdapter {
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
return ((Controller) handler).handleRequest(request, response);
}
}
只有SimpleControllerHandlerAdapter
返回结果不是null
.
AnnotationMethodHandlerAdapter
AnnotationMethodHandlerAdapter已经废弃。
@deprecated in Spring 3.2 in favor of
@link org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter RequestMappingHandlerAdapter}
这里不再详细分析。
RequestMappingHandlerAdapter 概述
分析 AbstractHandlerMethodAdapter
RequestMappingHandlerAdapter
继承自 AbstractHandlerMethodAdapter
,AbstractHandlerMethodAdapter比较简单,代码如下:
public abstract class AbstractHandlerMethodAdapter extends WebContentGenerator implements HandlerAdapter, Ordered {
//提供setter,配置时可设置顺序。
private int order = Ordered.LOWEST_PRECEDENCE;
public AbstractHandlerMethodAdapter() {
//是否限制仅支持: GET, HEAD and POST
super(false);
}
@Override
public final boolean supports(Object handler) {
/**
* a. 必须为 HandlerMethod类型
* b. 还需满足supportsInternal的条件,supportsInternal为模板方法,由子类实现。 子类直接返回true.
* ==== 综上 handler只需为HandlerMethod 即返回true.
*/
return (handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler));
}
@Override
public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
//调用handleInternal模板方法,由子类实现
return handleInternal(request, response, (HandlerMethod) handler);
}
@Override
public final long getLastModified(HttpServletRequest request, Object handler) {
//getLastModifiedInternal 模板方法 由子类实现 , 子类实现 直接返回 -1
return getLastModifiedInternal(request, (HandlerMethod) handler);
}
}
handleInternal
通过分析AbstractHandlerMethodAdapter
可以发现,最终的处理逻辑全部交给了handleInternal
方法,就是这个方法使用handler来处理请求.
handleInternal处理过程大概分为三个步骤:
- 准备好处理器所需的参数
- 使用处理器处理请求 ---- 直接利用反射调用处理器执行即可。
- 处理返回值,
即将不同类型的返回值统一处理成ModelAndView类型。
参数绑定
这3步中,最复杂的是第1步即参数绑定,这一步需要根据hanlder的需要设置参数,参数类型、个数都不确定且此过程运用了大量的组件,给这部分代码带来了很大的复杂度。
想要理解参数绑定需要明白如下三个问题:
- 都有哪些参数需要
- 根据处理请求Handler确定
- 当前处理器对应注释了
@ModelAttribute、@InitBinder
- 参数的值的来源
request请求中参数
: url、post以及请求头header中cookie中参数
session中参数
设置到FlashMap中的参数
: 这种弄参数主要用于redirect传递参数@SessionAttributes传递的参数
注释@ModelAttribute方法设置的参数
- 具体进行绑定的方法: 具体的参数解析使用
HandlerMethodArgumentResolver
类型的组件来完成。@ModelAttribute、@InitBinder、@ControllerAdvice用法
RequestMappingHandlerAdapter 结构
RequestMappingHandlerAdapter自身结构并不复杂,只不过是使用了很多组件,增加了对代码分析的难度。
RequestMappingHandlerAdapter 初始化
RequestMappingHandlerAdapter 实现了 InitializingBean
接口,它的初始化工作是在afterPropertiesSet()
方法中完成的,它的主要工作内容是初始化如下一些属性:
//org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter
public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter implements BeanFactoryAware, InitializingBean {
//用于给处理器方法和带有@ModelAttribute的方法设置参数
private HandlerMethodArgumentResolverComposite argumentResolvers;
//用于给注释了@InitBinder的方法设置参数
private HandlerMethodArgumentResolverComposite initBinderArgumentResolvers;
//@ControllerAdvice类中, 带有@InitBinder 注解的方法
private final Map<ControllerAdviceBean, Set<Method>> initBinderAdviceCache = new LinkedHashMap<ControllerAdviceBean, Set<Method>>();
//@ControllerAdvice类中, 带有@ModelAttribute且不带有@RequestMapping 注解的方法
private final Map<ControllerAdviceBean, Set<Method>> modelAttributeAdviceCache = new LinkedHashMap<ControllerAdviceBean, Set<Method>>();
//带有@ControllerAdvice且实现了ResponseBodyAdvice接口的 类
private List<Object> responseBodyAdvice = new ArrayList<Object>();
//用于将处理器返回值 处理成 ModelAndView
private HandlerMethodReturnValueHandlerComposite returnValueHandlers;
@Override
public void afterPropertiesSet() {
//初始化 带有@ControllerAdvice类的相关属性
initControllerAdviceCache();
if (this.argumentResolvers == null) {
// 注①, 获取默认的ArgumentResolvers ,然后设置到argumentResolvers中
List<HandlerMethodArgumentResolver> resolvers = getDefaultArgumentResolvers();
this.argumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
}
if (this.initBinderArgumentResolvers == null) {
List<HandlerMethodArgumentResolver> resolvers = getDefaultInitBinderArgumentResolvers();
this.initBinderArgumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
}
if (this.returnValueHandlers == null) {
List<HandlerMethodReturnValueHandler> handlers = getDefaultReturnValueHandlers();
this.returnValueHandlers = new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers);
}
}
private void initControllerAdviceCache() {
//寻找带有@ControllerAdvice 的bean
List<ControllerAdviceBean> beans = ControllerAdviceBean.findAnnotatedBeans(getApplicationContext());
Collections.sort(beans, new OrderComparator()); //排序
List<Object> responseBodyAdviceBeans = new ArrayList<Object>();
for (ControllerAdviceBean bean : beans) {
//寻找带有@ModelAttribute && 不带有 @RequestMapping 的方法
Set<Method> attrMethods = HandlerMethodSelector.selectMethods(bean.getBeanType(), MODEL_ATTRIBUTE_METHODS);
if (!attrMethods.isEmpty()) {
this.modelAttributeAdviceCache.put(bean, attrMethods);
}
//寻找带有@InitBinder 的方法
Set<Method> binderMethods = HandlerMethodSelector.selectMethods(bean.getBeanType(), INIT_BINDER_METHODS);
if (!binderMethods.isEmpty()) {
this.initBinderAdviceCache.put(bean, binderMethods);
}
//寻找implements ResponseBodyAdvice接口的类
if (ResponseBodyAdvice.class.isAssignableFrom(bean.getBeanType())) {
responseBodyAdviceBeans.add(bean);
}
}
if (!responseBodyAdviceBeans.isEmpty()) {
/*
* 将匹配到的responseBodyAdviceBeans添加到List最前面。
* ResponseBodyAdvice可以通过@ControllerAdvice注解注册 ,也可以直接注册到 RequestMappingHandlerAdapter中,
* list.addAll(0, list2); 目的是让@ControllerAdvice注解注册的优先级更高
*/
this.responseBodyAdvice.addAll(0, responseBodyAdviceBeans);
}
}
}
上述过程中,argumentResolvers 、 initBinderArgumentResolvers 和 returnValueHandlers
初始化过程中都调用了相应的getDefaultXXX
方法,下以getDefaultArgumentResolvers()
为例:
//org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter
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;
}
可以看到上述有四类解析器:其中第三类为自定义解析器,通过自定义HandlerMethodArgumentResolver
实现,然后通过customArgumentResolvers
属性注册到RequestMappingHandlerAdapter
中。
注意: 自定义解析器的优先级必须在前两种解析器无法解析
时才会使用到,这个顺序无法改变!
例:如果自定义一个解析器用来解析@PathVariable注释的参数,是无法实现的,因为它会前两种解析器解析。
RequestMappingHandlerAdapter 调用
RequestMappingHandlerAdapter处理请求的入口方法是handleInternal
,代码如下:
//org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter
protected ModelAndView handleInternal(HttpServletRequest request,HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
/**
* getSessionAttributesHandler: 判断handlerMethod是否有@SessionAttributes注解,
* SessionAttributesHandler.hasSessionAttributes(): 判断@SessionAttributes注解,是否有value,types 属性配置
**/
if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
checkAndPrepare(request, response, this.cacheSecondsForSessionAttributeHandlers, true);
} else {
checkAndPrepare(request, response, true);
}
if (this.synchronizeOnSession) {
HttpSession session = request.getSession(false);
if (session != null) {
Object mutex = WebUtils.getSessionMutex(session);
synchronized (mutex) {
return invokeHandleMethod(request, response, handlerMethod);
}
}
}
return invokeHandleMethod(request, response, handlerMethod);
}
checkAndPrepare
checkAndPrepare
方法在父类 WebContentGenerator
中定义;
//AbstractHandlerMethodAdapter 继承 WebContentGenerator ,
public abstract class AbstractHandlerMethodAdapter extends WebContentGenerator implements HandlerAdapter, Ordered {
public AbstractHandlerMethodAdapter() {
super(false);
}
}
public abstract class WebContentGenerator extends WebApplicationObjectSupport {
//restrictDefaultSupportedMethods: 是否限制Http方法类型,默认为false;
public WebContentGenerator(boolean restrictDefaultSupportedMethods) {
if (restrictDefaultSupportedMethods) {
this.supportedMethods = new HashSet<String>(4);
this.supportedMethods.add(METHOD_GET);
this.supportedMethods.add(METHOD_HEAD);
this.supportedMethods.add(METHOD_POST);
}
}
protected final void checkAndPrepare(HttpServletRequest request, HttpServletResponse response, boolean lastModified) {
checkAndPrepare(request, response, -1 , lastModified);
}
protected final void checkAndPrepare(HttpServletRequest request, HttpServletResponse response, int cacheSeconds, boolean lastModified) {
String method = request.getMethod();
// 判断是否支持method :: 默认不限制http方法类型 restrictDefaultSupportedMethods = false
if (this.supportedMethods != null && !this.supportedMethods.contains(method)) {
throw new HttpRequestMethodNotSupportedException(method, StringUtils.toStringArray(this.supportedMethods));
}
// 判断是否必须session, 默认为false;
if (this.requireSession) {
if (request.getSession(false) == null) {
throw new HttpSessionRequiredException("Pre-existing session required but none found");
}
}
/**
* 给response设置缓存过期时间
* cacheSeconds > 0 : 设置缓存具体时间。 单位s
* cacheSeconds = 0 : 禁止使用缓存,对response的setHeader进行`"no-cache"`设置;
* cacheSeconds = -1 : do nothing
*/
applyCacheSeconds(response, cacheSeconds, lastModified);
}
}
checkAndPrepare方法的作用:用来设置response缓存相关的Header参数。
invokeHandleMethod
invokeHandleMethod
,它执行请求的处理。
//org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter
private ModelAndView invokeHandleMethod(HttpServletRequest request,HttpServletResponse response, HandlerMethod handlerMethod) {
ServletWebRequest webRequest = new ServletWebRequest(request, response);
/**
* 寻找handlerMethod对应的InitBinderMethod ,
* 先@ControllerAdvice中配置的全局@InitBinder的Method,
* 后自身@InitBinder的Method 后createDataBinderFactory
*/
WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
/**
* 寻找@SessionAttributes,@ControllerAdvice中配置的全局@ModelAttribute方法 和自身的@ModelAttribute方法,
* 加上上一步的binderFactory,创建ModelFactory
*/
ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);
//创建ServletInvocableHandlerMethod,实际请求的执行包括:参数绑定,处理请求以及返回值处理都在此类中完成。
ServletInvocableHandlerMethod requestMappingMethod = createRequestMappingMethod(handlerMethod, binderFactory);
ModelAndViewContainer mavContainer = new ModelAndViewContainer();
//将FlashMap中数据设置到model中
mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
//使用mdoelFactory将 @ModelAttribute 和 @SessionAttributes参数设置到Model.
modelFactory.initModel(webRequest, mavContainer, requestMappingMethod);
mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);
//.....省略 async部分代码......
//执行请求, 后续ServletInvocableHandlerMethod详解
requestMappingMethod.invokeAndHandle(webRequest, mavContainer);
/*
* modelFactory更新model(包括SessionAttributes 和 给Model设置BindingResult)
* mavContainer 创建 ModelAndView
* mavContainer中的model如果是RedirectAttributes类型,则将值设置到FlashMap中。
*/
return getModelAndView(mavContainer, modelFactory, webRequest);
}
自此整个RequestMappingHandlerAdapter
处理请求的过程(不包含各个组件的内部处理逻辑)就分析完成了,接下来分析各个组件的处理过程。