spring源码解析-web系列(一):启动
spring源码解析-web系列(二):处理请求的过程
spring源码解析-web系列(三):九大组件之HandlerMapping
spring源码解析-web系列(四):九大组件之HandlerAdapter
spring源码解析-web系列(五):解析请求参数
spring源码解析-web系列(六):九大组件之ViewResolver
spring源码解析-web系列(七):九大组件之HandlerExceptionResolver
转载请标明出处:
https://blog.csdn.net/bingospunky/article/details/98463628
本文出自马彬彬的博客
HandlerAdapter
HandlerMapping通过request找到Handler,HandlerAdapter通过Handler来干活。HandlerAdapter的继承关系如下:
图1:
HandlerAdapter的继承结构很简单,且右边4个类都很简单,只需关注AbstractHandlerMethodAdapter和RequestMappingHandlerAdapter即可。
左边的AbstractHandlerMethodAdapter抽象了supportsInternal、handleInternal、getLastModifiedInternal三个方法,实现了Ordered,其他都交给了子类RequestMappingHandlerAdapter来实现。
HandlerAdapter通过Handler来干活,但是Handler的类型是多种多样的,并且会处理参数、处理异常等工作,所以RequestMappingHandlerAdapter的实现很复杂,是这九大组件中最复杂的一个。
RequestMappingHandlerAdapter初始化过程
初始化在afterPropertiesSet方法中:
代码1 (org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.afterPropertiesSet):
public void afterPropertiesSet() {
this.initControllerAdviceCache();
List handlers;
if (this.argumentResolvers == null) {
handlers = this.getDefaultArgumentResolvers();
this.argumentResolvers = (new HandlerMethodArgumentResolverComposite()).addResolvers(handlers);
}
if (this.initBinderArgumentResolvers == null) {
handlers = this.getDefaultInitBinderArgumentResolvers();
this.initBinderArgumentResolvers = (new HandlerMethodArgumentResolverComposite()).addResolver1s(handlers);
}
if (this.returnValueHandlers == null) {
handlers = this.getDefaultReturnValueHandlers();
this.returnValueHandlers = (new HandlerMethodReturnValueHandlerComposite()).addHandlers(handlers);
}
}
代码1第2行处理被@ControllerAdvice注解的bean。
代码2 (org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.initControllerAdviceCache):
private void initControllerAdviceCache() {
if (this.getApplicationContext() != null) {
if (this.logger.isInfoEnabled()) {
this.logger.info("Looking for @ControllerAdvice: " + this.getApplicationContext());
}
List<ControllerAdviceBean> beans = ControllerAdviceBean.findAnnotatedBeans(this.getApplicationContext());
OrderComparator.sort(beans);
List<Object> responseBodyAdviceBeans = new ArrayList();
Iterator var3 = beans.iterator();
while(var3.hasNext()) {
ControllerAdviceBean bean = (ControllerAdviceBean)var3.next();
Set<Method> attrMethods = HandlerMethodSelector.selectMethods(bean.getBeanType(), MODEL_ATTRIBUTE_METHODS);
if (!attrMethods.isEmpty()) {
this.modelAttributeAdviceCache.put(bean, attrMethods);
this.logger.info("Detected @ModelAttribute methods in " + bean);
}
Set<Method> binderMethods = HandlerMethodSelector.selectMethods(bean.getBeanType(), INIT_BINDER_METHODS);
if (!binderMethods.isEmpty()) {
this.initBinderAdviceCache.put(bean, binderMethods);
this.logger.info("Detected @InitBinder methods in " + bean);
}
if (ResponseBodyAdvice.class.isAssignableFrom(bean.getBeanType())) {
responseBodyAdviceBeans.add(bean);
this.logger.info("Detected ResponseBodyAdvice bean in " + bean);
}
}
if (!responseBodyAdviceBeans.isEmpty()) {
this.responseBodyAdvice.addAll(0, responseBodyAdviceBeans);
}
}
}
代码2第7行获取到BeanFactory里所有被@ControllerAdvice注解的bean,后面遍历处理每一个bean。代码2第14行获取一个@ControllerAdvice注解的bean的所有被@ModelAttribute注解且没有被@RequestMapping注解的方法,放到modelAttributeAdviceCache中。代码2第20行代码获取一个@ControllerAdvice注解的bean的所有被@InitBinder注解的方法,放到initBinderAdviceCache中。代码2第26~29行,如果该bean是ResponseBodyAdvice类,则把该bean添加到responseBodyAdviceBeans中。由于@ControllerAdvice是全局的,这些方法被添加在适当的Map中,当请求到来时,可以方便的取出来使用。
代码1第4~第17行,分别处理argumentResolvers、initBinderArgumentResolvers、returnValueHandlers,他们过程相似,我们只看returnValueHandlers。
代码3 (org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.getDefaultArgumentResolvers):
private List<HandlerMethodArgumentResolver> getDefaultArgumentResolvers() {
List<HandlerMethodArgumentResolver> resolvers = new ArrayList();
resolvers.add(new RequestParamMethodArgumentResolver(this.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(this.getMessageConverters()));
resolvers.add(new RequestPartMethodArgumentResolver(this.getMessageConverters()));
resolvers.add(new RequestHeaderMethodArgumentResolver(this.getBeanFactory()));
resolvers.add(new RequestHeaderMapMethodArgumentResolver());
resolvers.add(new ServletCookieValueMethodArgumentResolver(this.getBeanFactory()));
resolvers.add(new ExpressionValueMethodArgumentResolver(this.getBeanFactory()));
resolvers.add(new ServletRequestMethodArgumentResolver());
resolvers.add(new ServletResponseMethodArgumentResolver());
resolvers.add(new HttpEntityMethodProcessor(this.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 (this.getCustomArgumentResolvers() != null) {
resolvers.addAll(this.getCustomArgumentResolvers());
}
resolvers.add(new RequestParamMethodArgumentResolver(this.getBeanFactory(), true));
resolvers.add(new ServletModelAttributeMethodProcessor(true));
return resolvers;
}
代码3添加了很多个HandlerMethodArgumentResolver用来解析参数。
RequestMappingHandlerAdapter执行过程
RequestMappingHandlerAdapter的执行就是实现父类的handleInternal方法:
代码4 (org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal):
protected ModelAndView handleInternal(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
if (this.getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
this.checkAndPrepare(request, response, this.cacheSecondsForSessionAttributeHandlers, true);
} else {
this.checkAndPrepare(request, response, true);
}
if (this.synchronizeOnSession) {
HttpSession session = request.getSession(false);
if (session != null) {
Object mutex = WebUtils.getSessionMutex(session);
synchronized(mutex) {
return this.invokeHandleMethod(request, response, handlerMethod);
}
}
}
return this.invokeHandleMethod(request, response, handlerMethod);
}
代码4第2~第6行根据方式上是否被@SessionAttribute注解,来设置HttpServletResponse相关的header,与是否缓存相关的header(Expires、Cache-Control、max-age=xxx)。这部分是@SessionAttribute相关的,由于无状态的趋势,在实际开发中不使用@SessionAttribute,这部分可以先不关注。
代码5 (org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandleMethod):
private ModelAndView invokeHandleMethod(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
ServletWebRequest webRequest = new ServletWebRequest(request, response);
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);
}
代码5第6行创建binderFactory对象,代码5第7行创建modelFactory对象,这俩对象是参数相关的,比如@ModelAttribute、@InitBinder等,注意这几个对象与@RequestParam、@PathVariabl等在http请求获取的参数无关。代码5第8行创建了ServletInvocableHandlerMethod对象,这个对象继承HandlerMethod,请求的处理就是通过这个对象执行的,包括参数绑定、请求处理、返回值解析等。代码5第10行创建了ModelAndViewContainer对象,这个对象贯穿处理的过程。代码5第11~第13行对ModelAndViewContainer进行了一些处理。代码5第35行执行处理过程。代码5第41行进行一些后置的处理,比如@SessionAttribute、RedirectAttribures,创建了ModelAndView对象。
ModelAndViewContainer
ModelAndViewContainer承担处理过程中数据的传递工作,它保存了View以及Model。
它有如下两个属性:
代码6 (org.springframework.web.method.support.ModelAndViewContainer):
private final ModelMap defaultModel = new BindingAwareModelMap();
private ModelMap redirectModel;
defaultModel是默认使用的Model,后者是redirect时使用的Model。我们在@RequestMapping方法里使用的Model或者ModelMap类型的对象就是他们。
ModelFactory
在RequestMappingHandlerAdapter.invokeHandleMethod方法的执行过程中使用了ModelFactory。
ModelFactory是用来维护Model的,具体包含两个功能:1.初始化Model。2.处理器执行后把Model中相应的参数更新到SessionAttributes中。
初始化Model的过程如下:
代码7 (org.springframework.web.method.annotation.ModelFactory.initModel):
public void initModel(NativeWebRequest request, ModelAndViewContainer mavContainer, HandlerMethod handlerMethod)
throws Exception {
Map<String, ?> sessionAttributes = this.sessionAttributesHandler.retrieveAttributes(request);
mavContainer.mergeAttributes(sessionAttributes);
invokeModelAttributeMethods(request, mavContainer);
for (String name : findSessionAttributeArguments(handlerMethod)) {
if (!mavContainer.containsAttribute(name)) {
Object value = this.sessionAttributesHandler.retrieveAttribute(request, name);
if (value == null) {
throw new HttpSessionRequiredException("Expected session attribute '" + name + "'");
}
mavContainer.addAttribute(name, value);
}
}
}
初始化Model的过程分为3步:1.从SessionAttributes取出参数,存放到mavContainer中。2.执行注释了@ModelAttribute注释的方法,并将返回值设置到Model。3.处理既注释了@ModelAttribute又在@SessionAttribute中的参数。
ServletInvocableHandlerMethod
代码5第8行创建了ServletInvocableHandlerMethod对象,请求的处理就是通过这个对象触发的。
ServletInvocableHandlerMethod的继承关系比较简单,只有三层:ServletInvocableHandlerMethod -> InvocableHandlerMethod -> HandlerMethod 。
ServletInvocableHandlerMethod的执行过程如下:
代码8 (org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle):
public void invokeAndHandle(ServletWebRequest webRequest,
ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
setResponseStatus(webRequest);
if (returnValue == null) {
if (isRequestNotModified(webRequest) || hasResponseStatus() || mavContainer.isRequestHandled()) {
mavContainer.setRequestHandled(true);
return;
}
}
else if (StringUtils.hasText(this.responseReason)) {
mavContainer.setRequestHandled(true);
return;
}
mavContainer.setRequestHandled(false);
try {
this.returnValueHandlers.handleReturnValue(
returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
}
catch (Exception ex) {
if (logger.isTraceEnabled()) {
logger.trace(getReturnValueHandlingErrorMessage("Error handling return value", returnValue), ex);
}
throw ex;
}
}
代码8第4行调用父类的invokeForRequest方法处理请求,获取的对象returnValue。代码8第20行处理返回的对象,并根据情况来渲染,根据returnValueHandler是否支持来决定是否渲染,这里有17个returnValueHandler,如果是不支持的类型,则不渲染。比如:ResponseEntity类型的返回值可以渲染;@ResponseBody注解的方法可以渲染;字符串类型不可以渲染;void类型不可以渲染。如果渲染完的话,会在mavContainer对象做如下标记***mavContainer.setRequestHandled(true);***,那么后面就不会再次渲染了。如果这里没有渲染,后面会在DispatcherServlet.processDispatchResult方法渲染。
代码8第4行调用父类的invokeForRequest方法如下:
代码9 (org.springframework.web.method.support.InvocableHandlerMethod):
public Object invokeForRequest(NativeWebRequest request, ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
Object[] args = this.getMethodArgumentValues(request, mavContainer, providedArgs);
Object returnValue = this.doInvoke(args);
return returnValue;
}
protected Object doInvoke(Object... args) throws Exception {
ReflectionUtils.makeAccessible(this.getBridgedMethod());
return this.getBridgedMethod().invoke(this.getBean(), args);
}
代码9第2行获取参数。代码9第4行调用doInvoke方法,通过反射执行我们配置的Controller方法。
参数的解析是在ServletInvocableHandlerMethod类里执行的,我们在下一篇博客里专门阐述Spring是如何解析参数的。
总结
HandlerAdapter的作用就是通过前面获取到的Handler,执行处理逻辑。整个处理过程可以分为三步:解析参数、执行请求、处理返回值。
参数的来源有很多,大体可以分为两类,一类从Model中来,通过FlashMapManager和ModelFactory管理。另一类从request中来,使用HandlerMethodArgumentResolver解析,下一篇博客会详细介绍。
执行请求的是HandlerMethod的子类ServletInvocableHandlerMethod。
返回值是通过HandlerMethodReturnValueHandler进行解析的,不同返回值类型对应不同的HandlerMethodReturnValueHandler,在ServletInvocableHandlerMethod里进行解析。
另外,整个处理过程中ModelAndViewContainer起到传递参数的作用。