赞
踩
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
本文出自马彬彬的博客
HandlerMapping通过request找到Handler,HandlerAdapter通过Handler来干活。HandlerAdapter的继承关系如下:
图1:
HandlerAdapter的继承结构很简单,且右边4个类都很简单,只需关注AbstractHandlerMethodAdapter和RequestMappingHandlerAdapter即可。
左边的AbstractHandlerMethodAdapter抽象了supportsInternal、handleInternal、getLastModifiedInternal三个方法,实现了Ordered,其他都交给了子类RequestMappingHandlerAdapter来实现。
HandlerAdapter通过Handler来干活,但是Handler的类型是多种多样的,并且会处理参数、处理异常等工作,所以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的执行就是实现父类的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承担处理过程中数据的传递工作,它保存了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类型的对象就是他们。
在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中的参数。
代码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起到传递参数的作用。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。