回顾
上期说道,HandlerAdapter
存在的意义,就是充当request,reponse
与我们定义的各种形式handler
之间的参数适配,返回值适配。
当我们在享受着SpringMVC带来的多样化参数接收形式,以及简便的返回值操作时,殊不知,HandlerAdapter
在背后默默的为我们奉献着。
RequestMappingHandlerAdapter
适用于@RequestMapping
注解标注的Handler
,是处理我们定义的controller
接口最重要的HandlerAdapter
。基于他的重要地位,本文讲讲他是如何工作的。
1.初始化
先从其初始化开始下手
为了应对handler的各种样式的参数接收,在handlerApater
里,就需要大量的转换工具来类处理这些东西。
所以:初始化的过程中,就是要设置各种参数工具,返回值处理工具等等,这些工具可以是Spring
提供的或者开发人员自己定义的。
(1) public RequestMappingHandlerAdapter() { StringHttpMessageConverter stringHttpMessageConverter = new StringHttpMessageConverter(); stringHttpMessageConverter.setWriteAcceptCharset(false); // see SPR-7316 this.messageConverters = new ArrayList<HttpMessageConverter<?>>(4); this.messageConverters.add(new ByteArrayHttpMessageConverter()); this.messageConverters.add(stringHttpMessageConverter); this.messageConverters.add(new SourceHttpMessageConverter<Source>()); this.messageConverters.add(new AllEncompassingFormHttpMessageConverter()); } public void afterPropertiesSet() { (2) initControllerAdviceCache(); (3) 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.1 设置HttpMessageConverter
HttpMessageConverter
负责将请求信息转换为一个对象(类型为 T),将对象(类型为 T)输出为响应信息
1.2 initControllerAdviceCache
这一步目的是对 @ControllerAdvice
标注的Bean的处理
这里简单介绍下@ControllerAdvice
注解意义,通过@ControllerAdvice
标注的类一般作为全局异常处理,全局数据绑定,全局数据预处理等。
例如:我们在一个Controller里抛出一个自定义异常时,通常都会有一个@ControllerAdvice
定义的类中处理此异常。
也就是说:@ControllerAdvice
标注类 后,他已经成为一种处理工具。自然的SpringMVC在初始化时会把这些 开发人员定义的处理工具找到 缓存起来。
源码中initControllerAdviceCache()
的逻辑是
- 找到该Advice Bean内所有的标注有
@ModelAttribute
但没标注@RequestMapping
的缓存到一起 - 找到该Advice Bean内所有的标注有
@InitBinder
的方法缓存在一起 - 实现了接口
RequestBodyAdvice/ResponseBodyAdvice
们,缓存到requestResponseBodyAdvice
集合的前面
1.3 设置默认参数解析工具
在getDefaultArgumentResolvers()
方法中设置了大量的SpringMVC已经准备好的参数解析工具。为handlerApater
处理做准备。
列如:我们常用@PathVariable注解。其实就是在此处设置的PathVariableMethodArgumentResolver
解析工具帮我们解析的。
@PostMapping("/post/{id}/{name}") public void Post(@PathVariable(value = "id") String id,@PathVariable(value = "name") String name, HttpServletRequest request, HttpServletResponse response){ }
工具设置逻辑为:
- 先设置针对注解的参数解析工具
- 基于type类型的解析工具设置
- 设置用户定义的参数解析工具
- 最终解析工具,如果上边都没解析,此处设置解析工具最终处理
这些参数解析工具统一交给HandlerMethodArgumentResolverComposite
。从他的名字也可以看出解析工具混合器
,说白了就是解析工具集合
这里提一下自己的一点小理解: 我在很多框架中都见过类型
xxxComposite
混合器,本质上就是同一个东西的集合。既然有了集合为啥还要多一层出来呢?
个人觉得混合器就好比工头,当我们跟工人打交道时,直接与工头交涉,比跟多个工人交涉方便的多。
总结为:分工明确,高内聚低耦合
1.4 设置返回值处理工具
提供对HandlerMethod返回值的支持,比如@ResponseBody
等同参数解析器逻辑差不多,
最终初始化HandlerMethodReturnValueHandlerComposite
混合器,承载返回值处理器集合
1.5 其他
除了上述初始化外,当然还有其他细节,感兴趣可以去阅读源码
2.handle处理
一切准备就绪后,下面就是调用了
再回头看下DispatcherServlet
中,HandlerAdapter
的调用起点
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception { ... 获取当前hangdler的HandlerAdapter HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler()); 走过拦截器的前置处理 if (!mappedHandler.applyPreHandle(processedRequest, response)) { return; } 通过适配器执行调用 mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); 过拦截器后置处理 mappedHandler.applyPostHandle(processedRequest, response, mv); }
RequestMappingHandlerAdapter
handle方法在父类中AbstractHandlerMethodAdapter
回调RequestMappingHandlerAdapter.handleInternal
方法
2.1 handleInternal
protected ModelAndView handleInternal(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception { ModelAndView mav; checkRequest(request); // Execute invokeHandlerMethod in synchronized block if required. if (this.synchronizeOnSession) { ... } else { // No synchronization on session demanded at all... mav = invokeHandlerMethod(request, response, handlerMethod); } if (!response.containsHeader(HEADER_CACHE_CONTROL)) { if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) { applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers); } else { prepareResponse(response); } } return mav; }
这里只要是
- request请求方法的检查,
- 同一个Session下是否要串行(同步)
- 调用
invokeHandlerMethod
- 处理Cache-Control这个请求头
2.1 invokeHandlerMethod
执行handler方法,好戏正式登场
protected ModelAndView invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception { ServletWebRequest webRequest = new ServletWebRequest(request, response); try { WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod); ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory); //对handlerMethod进行封装。 ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod); //设置参数处理器 invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers); //设置返回值处理器 invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers); invocableMethod.setDataBinderFactory(binderFactory); invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer); ModelAndViewContainer mavContainer = new ModelAndViewContainer(); mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request)); modelFactory.initModel(webRequest, mavContainer, invocableMethod); mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect); AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response); asyncWebRequest.setTimeout(this.asyncRequestTimeout); 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 + "]"); } invocableMethod = invocableMethod.wrapConcurrentResult(result); } //调用 invocableMethod.invokeAndHandle(webRequest, mavContainer); if (asyncManager.isConcurrentHandlingStarted()) { return null; } return getModelAndView(mavContainer, modelFactory, webRequest); } finally { webRequest.requestCompleted(); } }