下面是HandlerAdapter的接口定义:
public interface HandlerAdapter {
/**
* Given a handler instance, return whether or not this {@code HandlerAdapter}
* can support it. Typical HandlerAdapters will base the decision on the handler
* type. HandlerAdapters will usually only support one handler type each.
* <p>A typical implementation:
* <p>{@code
* return (handler instanceof MyHandler);
* }
* @param handler handler object to check
* @return whether or not this object can use the given handler
*/
boolean supports(Object handler);
/**
* Use the given handler to handle this request.
* The workflow that is required may vary widely.
* @param request current HTTP request
* @param response current HTTP response
* @param handler handler to use. This object must have previously been passed
* to the {@code supports} method of this interface, which must have
* returned {@code true}.
* @throws Exception in case of errors
* @return ModelAndView object with the name of the view and the required
* model data, or {@code null} if the request has been handled directly
*/
ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;
/**
* Same contract as for HttpServlet's {@code getLastModified} method.
* Can simply return -1 if there's no support in the handler class.
* @param request current HTTP request
* @param handler handler to use
* @return the lastModified value for the given handler
* @see javax.servlet.http.HttpServlet#getLastModified
* @see org.springframework.web.servlet.mvc.LastModified#getLastModified
*/
long getLastModified(HttpServletRequest request, Object handler);
}
下main我们来看一下整个SpringMVC最复杂的组件RequestMappingHandlerAdapter。它的handleInternal方法就是用Handler处理请求,具体处理过程大致可以分为三步:
1、备好处理器所需要的参数
2、使用处理器处理请求
3、处理返回值,也就是将不同类型的返回值统一处理成ModelAndView类型
这三步中最麻烦的就是第一步参数准备,需要根据处理器的需要设置参数,而参数类型、个数都是不确定的,并且还使用了大量的组件。
参数来源:
1、request中相关的参数,主要包括url中的参数、post过来的参数以及请求头所包含的值
2、cookie中的参数
3、session中的参数
4、设置到FlashMap中的参数
5、SessionAttributes传递的参数
6、通过相应的注释了@ModelAttribute的方法进行设置的参数
public void afterPropertiesSet() {
// 初始化注释了@ControllerAdvice的类的相关属性
initControllerAdviceCache();
if (this.argumentResolvers == null) {
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);
}
}
我们看初始化的步骤:
1、initControllerAdviceCache初始化注释了@ControllerAdvice的类的那三个属性
2、初始化argumentResolvers
3、初始化initBinderArgumentResolvers
4、初始化returnValueHandlers
private void initControllerAdviceCache() {
if (getApplicationContext() == null) {
return;
}
if (logger.isInfoEnabled()) {
logger.info("Looking for @ControllerAdvice: " + getApplicationContext());
}
//获取所有注释了@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);
logger.info("Detected @ModelAttribute methods in " + bean);
}
//查找注释了@InitBinder的方法
Set<Method> binderMethods = HandlerMethodSelector.selectMethods(bean.getBeanType(), INIT_BINDER_METHODS);
if (!binderMethods.isEmpty()) {
this.initBinderAdviceCache.put(bean, binderMethods);
logger.info("Detected @InitBinder methods in " + bean);
}
//查找实现了ResponseBodyAdvice接口的类
if (ResponseBodyAdvice.class.isAssignableFrom(bean.getBeanType())) {
responseBodyAdviceBeans.add(bean);
logger.info("Detected ResponseBodyAdvice bean in " + bean);
}
}
//将所有实现了ResponseBodyAdvice接口的类保存起来
if (!responseBodyAdviceBeans.isEmpty()) {
this.responseBodyAdvice.addAll(0, responseBodyAdviceBeans);
}
}
initControllerAdviceCache方法执行完,下面我们看一下那三个getXXX方法:
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()));
// T添加按类型解析参数的解析器
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;
}
这里的解析器可以分为四类,通过注释解析的解析器,通过类型解析的解析器,自定义的解析器和解析所有类型的解析器
下面我们看一下他是如何工作的,他的入口方法是HandleInternal:
protected ModelAndView handleInternal(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
//判断handler是否有@SessionAttribute注释的参数
if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
// Always prevent caching in case of session attribute management.
checkAndPrepare(request, response, this.cacheSecondsForSessionAttributeHandlers, true);
}
else {
// Uses configured default cacheSeconds setting.
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和invokeHandleMethod,下面我们就对他们来进行分析
protected final void checkAndPrepare(
HttpServletRequest request, HttpServletResponse response, int cacheSeconds, boolean lastModified)
throws ServletException {
// 获取请求的方法
String method = request.getMethod();
//检查请求的方法类型是否支持
if (this.supportedMethods != null && !this.supportedMethods.contains(method)) {
throw new HttpRequestMethodNotSupportedException(
method, StringUtils.toStringArray(this.supportedMethods));
}
// 如果session必须存在,判断session是否存在
if (this.requireSession) {
if (request.getSession(false) == null) {
throw new HttpSessionRequiredException("Pre-existing session required but none found");
}
}
//给response设置缓存过期时间
applyCacheSeconds(response, cacheSeconds, lastModified);
}
protected final void applyCacheSeconds(HttpServletResponse response, int seconds, boolean mustRevalidate) {
if (seconds > 0) {
cacheForSeconds(response, seconds, mustRevalidate);
}
else if (seconds == 0) {
preventCaching(response);
}
// Leave caching to the client otherwise.
}
checkAndPrepare方法首先检查了请求的类型是否支持,然后根据是否需要session判断session是否真的存在,最后给response设置过期时间
private ModelAndView invokeHandleMethod(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
//创建ServletWebRequest
ServletWebRequest webRequest = new ServletWebRequest(request, response);
//初始化几个Factory
WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);
ServletInvocableHandlerMethod requestMappingMethod = createRequestMappingMethod(handlerMethod, binderFactory);
ModelAndViewContainer mavContainer = new ModelAndViewContainer();
mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
modelFactory.initModel(webRequest, mavContainer, requestMappingMethod);
mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);
AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response);
asyncWebRequest.setTimeout(this.asyncRequestTimeout);
final WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
asyncManager.setTaskExecutor(this.taskExecutor);
asyncManager.setAsyncWebRequest(asyncWebRequest);
asyncManager.registerCallableInterceptors(this.callableInterceptors);
asyncManager.registerDeferredResultInterceptors(this.deferredResultInterceptors);
if (asyncManager.hasConcurrentResult()) {
Object result = asyncManager.getConcurrentResult();
mavContainer = (ModelAndViewContainer) asyncManager.getConcurrentResultContext()[0];
asyncManager.clearConcurrentResult();
if (logger.isDebugEnabled()) {
logger.debug("Found concurrent result value [" + result + "]");
}
requestMappingMethod = requestMappingMethod.wrapConcurrentResult(result);
}
requestMappingMethod.invokeAndHandle(webRequest, mavContainer);
if (asyncManager.isConcurrentHandlingStarted()) {
return null;
}
return getModelAndView(mavContainer, modelFactory, webRequest);
}
在invokeHandleMethod方法中首先使用request和response创建了ServletWebRequest类型的webRequest,接着对WebDataBinderFactory、ModelFactory、ServletInvocableHandlerMethod这三个类型的变量进行了定义和初始化。
private WebDataBinderFactory getDataBinderFactory(HandlerMethod handlerMethod) throws Exception {
Class<?> handlerType = handlerMethod.getBeanType();
//检查当前Handler中的InitBinder方法是否已经存在缓存中
Set<Method> methods = this.initBinderCache.get(handlerType);
//如果没有则查找并放到缓存中
if (methods == null) {
methods = HandlerMethodSelector.selectMethods(handlerType, INIT_BINDER_METHODS);
this.initBinderCache.put(handlerType, methods);
}
List<InvocableHandlerMethod> initBinderMethods = new ArrayList<InvocableHandlerMethod>();
// 将所有符合条件的initBinder添加到集合中
for (Entry<ControllerAdviceBean, Set<Method>> entry : this.initBinderAdviceCache .entrySet()) {
if (entry.getKey().isApplicableToBeanType(handlerType)) {
Object bean = entry.getKey().resolveBean();
for (Method method : entry.getValue()) {
initBinderMethods.add(createInitBinderMethod(bean, method));
}
}
}
//将当前Handler中的InitBinder方法添加到initBinderMethods
for (Method method : methods) {
Object bean = handlerMethod.getBean();
initBinderMethods.add(createInitBinderMethod(bean, method));
}
return createDataBinderFactory(initBinderMethods);
}
ModelFactory是用来处理Model的,主要包含两个功能:
1、在处理器具体处理之前对Model进行初始化
2、在处理完请求后对Model参数进行更新
给Model初始化具体包括三部分内容:
1、将原来的SessionAttributes中的值设置到Model
2、执行相应注释了@ModelAttribute的方法并将其值设置到Mode
3、处理器中注释了@ModelAttribute的参数如果同时在SessionAttributes中也配置了,而且在mavContainer中还没有值从全部SessionAttributes中查找出并设置出去
private ModelFactory getModelFactory(HandlerMethod handlerMethod, WebDataBinderFactory binderFactory) {
//获取SessionAttributesHandler
SessionAttributesHandler sessionAttrHandler = getSessionAttributesHandler(handlerMethod);
//获取处理器的类型
Class<?> handlerType = handlerMethod.getBeanType();
//获取处理器类中注释了@ModelAttribute而且没有注释@RequestMapping的类型,第一次获取后添加到缓存中,以后直接从缓存中获取
Set<Method> methods = this.modelAttributeCache.get(handlerType);
if (methods == null) {
methods = HandlerMethodSelector.selectMethods(handlerType, MODEL_ATTRIBUTE_METHODS);
this.modelAttributeCache.put(handlerType, methods);
}
List<InvocableHandlerMethod> attrMethods = new ArrayList<InvocableHandlerMethod>();
// 先添加全局@ModelAttribute方法
for (Entry<ControllerAdviceBean, Set<Method>> entry : this.modelAttributeAdviceCache.entrySet()) {
if (entry.getKey().isApplicableToBeanType(handlerType)) {
Object bean = entry.getKey().resolveBean();
for (Method method : entry.getValue()) {
attrMethods.add(createModelAttributeMethod(binderFactory, bean, method));
}
}
}
for (Method method : methods) {
Object bean = handlerMethod.getBean();
attrMethods.add(createModelAttributeMethod(binderFactory, bean, method));
}
return new ModelFactory(attrMethods, binderFactory, sessionAttrHandler);
}
新建ModelFactory主要使用了三个参数,第一个是注释了@ModelAttribute的方法,第二个是WebDataBinderFactory,第三个是SessionAttributeHandler
SessionAttributesHandler的创建方法getSessionAttributeshandler主要用来添加:
1、注释了@ControllerAdvice的类定义的全局的@ModelAttribute方法
2、处理器自身的@ModelAttribute方法
ServletInvocableHandlerMethod类型继承自HandlerMethod,并且可以直接执行,实际请求的处理就是通过它来执行的,参数绑定、处理请求以及返回值处理都在它里边完成:
private ServletInvocableHandlerMethod createRequestMappingMethod(
HandlerMethod handlerMethod, WebDataBinderFactory binderFactory) {
ServletInvocableHandlerMethod requestMethod;
//新建类ServletInvocableHandlerMethod
requestMethod = new ServletInvocableHandlerMethod(handlerMethod);
//设置参数
requestMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
requestMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
requestMethod.setDataBinderFactory(binderFactory);
requestMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
return requestMethod;
}
这三个参数创建完成之后的工作如下:
1、新建传递参数的ModelAndViewContainer容器,并将相应的参数设置到其Model中
2、执行请求
3、请求处理完后进行一些后置处理
新建ModelAndViewContainer类型的mavContainer参数,用于保存Model和View,它贯穿于整个处理过程,然后对mavContainer进行了设置,主要包括三部分内容
1、将FlashMap中的数据设置到Model中
2、使用modelFactory将SessionAttributes和注释了@ModelAttribute的方法的参数设置到Model
3、根据配置对ignoreDefaultModelOnRedirect进行了设置
ModelAndViewContainer mavContainer = new ModelAndViewContainer();
mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
modelFactory.initModel(webRequest, mavContainer, requestMappingMethod);
mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);
执行请求,直接调用ServletInvocableHandlerMethod里的invokeAndHandle方法:
requestMappingMethod.invokeAndHandle(webRequest, mavContainer);
处理完请求后的后置处理,是在getModelAndView里面做的:
private ModelAndView getModelAndView(ModelAndViewContainer mavContainer,
ModelFactory modelFactory, NativeWebRequest webRequest) throws Exception {
//更新Model
modelFactory.updateModel(webRequest, mavContainer);
if (mavContainer.isRequestHandled()) {
return null;
}
ModelMap model = mavContainer.getModel();
//创建modelAndView
ModelAndView mav = new ModelAndView(mavContainer.getViewName(), model);
if (!mavContainer.isViewReference()) {
mav.setView((View) mavContainer.getView());
}
//如果mavContainer里model的是RedirectAttributes类型,则将其值设置到FlashMap中
if (model instanceof RedirectAttributes) {
Map<String, ?> flashAttributes = ((RedirectAttributes) model).getFlashAttributes();
HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
RequestContextUtils.getOutputFlashMap(request).putAll(flashAttributes);
}
return mav;
}
在这里面一共做了三件事:
1、更新Model
2、创建ModelAndView
3、如果mavContainer里model的是RedirectAttributes类型,则将其值设置到FlashMap中
我们总结一下整个处理请求的过程
1、绑定参数,参数来源主要用request、cookie、session、flashMap、SessionAttribute传递的参数、通过相应的注释了@ModelAttribute的方法进行设置的参数
2、执行请求,使用ArgumentResolver解析参数、执行请求、使用ReturnValueHandler处理返回值等内容
3、处理返回值,model中参数的缓存和ModelAndView的创建