方法:
RequestMappingHandlerAdapter: ... // 省略所有属性的get/set方法 @Override protected long getLastModifiedInternal(HttpServletRequest request, HandlerMethod handlerMethod) { return -1; } // 因为它只需要处理HandlerMethod这样的Handler,所以这里恒返回true 请参照父类的supportsInternal()钩子方法 @Override protected boolean supportsInternal(HandlerMethod handlerMethod) { return true; } // 可以认为这个就是`HandlerAdapter`的接口方法,是处理请求的入口 最终返回一个ModelAndView @Override protected ModelAndView handleInternal(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception { ModelAndView mav; checkRequest(request); // 检查方法 // Execute invokeHandlerMethod in synchronized block if required. // 同一个Session下是否要串行,显然一般都是不需要的。直接看invokeHandlerMethod()方法吧 if (this.synchronizeOnSession) { HttpSession session = request.getSession(false); if (session != null) { Object mutex = WebUtils.getSessionMutex(session); synchronized (mutex) { mav = invokeHandlerMethod(request, response, handlerMethod); } } else { // No HttpSession available -> no mutex necessary mav = invokeHandlerMethod(request, response, handlerMethod); } } else { // No synchronization on session demanded at all... mav = invokeHandlerMethod(request, response, handlerMethod); } // 处理Cache-Control这个请求头~~~~~~~~~(若你自己木有set的话) if (!response.containsHeader(HEADER_CACHE_CONTROL)) { if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) { applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers); } else { prepareResponse(response); } } return mav; }
剩下的便是本适配器最为重要的一个方法:invokeHandlerMethod()
:
invokeHandlerMethod()
它的作用顾名思义:就是调用我们的目标方法,在这里会组织各个组件进行数据绑定、数据校验、内容协商等等操作控制。
// 它的作用就是执行目标的HandlerMethod,然后返回一个ModelAndView @Nullable protected ModelAndView invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception { ServletWebRequest webRequest = new ServletWebRequest(request, response); // 注意:此处只有try-finally 哦 // 因为invocableMethod.invokeAndHandle(webRequest, mavContainer)是可能会抛出异常的(交给全局异常处理) try { // 最终创建的是一个ServletRequestDataBinderFactory,持有所有@InitBinder的method方法们 WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod); // 创建一个ModelFactory,@ModelAttribute啥的方法就会被引用进来 ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory); // 把HandlerMethod包装为ServletInvocableHandlerMethod,具有invoke执行的能力喽 // 下面这几部便是一直给invocableMethod的各大属性赋值~~~ ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod); if (this.argumentResolvers != null) { invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers); } if (this.returnValueHandlers != null) { invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers); } invocableMethod.setDataBinderFactory(binderFactory); invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer); ModelAndViewContainer mavContainer = new ModelAndViewContainer(); // 把上个request里的值放进来到本request里 mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request)); // model工厂:把它里面的Model值放进mavContainer容器内(此处@ModelAttribute/@SessionAttribute啥的生效) 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); // 它不管是不是异步请求都先用AsyncWebRequest 包装了一下,但是若是同步请求 // asyncManager.hasConcurrentResult()肯定是为false的~~~ if (asyncManager.hasConcurrentResult()) { Object result = asyncManager.getConcurrentResult(); mavContainer = (ModelAndViewContainer) asyncManager.getConcurrentResultContext()[0]; asyncManager.clearConcurrentResult(); LogFormatUtils.traceDebug(logger, traceOn -> { String formatted = LogFormatUtils.formatValue(result, !traceOn); return "Resume with async result [" + formatted + "]"; }); invocableMethod = invocableMethod.wrapConcurrentResult(result); } // 此处其实就是调用ServletInvocableHandlerMethod#invokeAndHandle()方法喽 // 关于它你可以来这里:https://fangshixiang.blog.csdn.net/article/details/98385163 // 注意哦:任何HandlerMethod执行完后都是把结果放在了mavContainer里(它可能有Model,可能有View,可能啥都木有~~) // 因此最后的getModelAndView()又得一看 invocableMethod.invokeAndHandle(webRequest, mavContainer); if (asyncManager.isConcurrentHandlingStarted()) { return null; } return getModelAndView(mavContainer, modelFactory, webRequest); } finally { webRequest.requestCompleted(); } }
可以看到任何处理器执行完后,最终返回的的都是一个ModelAndView对象,保持了很好的同一性。这得益于getModelAndView()这个方法的适配处理:
// @Nullable:表示它返回的可以是个null哦~(若木有视图,就直接不会render啦~因为response已经写入过值了) @Nullable private ModelAndView getModelAndView(ModelAndViewContainer mavContainer, ModelFactory modelFactory, NativeWebRequest webRequest) throws Exception { // 把session里面的内容写入 modelFactory.updateModel(webRequest, mavContainer); // Tips:若已经被处理过,那就返回null喽~~(比如若是@ResponseBody这种,这里就是true) if (mavContainer.isRequestHandled()) { return null; } // 通过View、Model、Status构造出一个ModelAndView,最终就可以完成渲染了 ModelMap model = mavContainer.getModel(); ModelAndView mav = new ModelAndView(mavContainer.getViewName(), model, mavContainer.getStatus()); if (!mavContainer.isViewReference()) { // 是否是String类型 mav.setView((View) mavContainer.getView()); } // 对重定向RedirectAttributes参数的支持(两个请求之间传递参数,使用的是ATTRIBUTE) if (model instanceof RedirectAttributes) { Map<String, ?> flashAttributes = ((RedirectAttributes) model).getFlashAttributes(); HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class); if (request != null) { RequestContextUtils.getOutputFlashMap(request).putAll(flashAttributes); } } return mav; }
执行完HandlerMethod后得到一个ModelAndView,它可能是null(比如已被处理过),那么最终交给DispatcherServlet就没有后续处理(渲染)了,否则会做视图渲染:render()。
关于DispatcherServlet的处理流程,站内搜索相关关键字也能找到相关文章的。
Spring MVC默认装配了哪些HandlerAdapter呢?
开启@EnableWebMvc:
不开启:
相关阅读
web九大组件之—HandlerAdapter适配器模式实践源码分析【享学Spring MVC】
总结
RequestMappingHandlerAdapter作为HandlerAdapter适配模式实现,由于@RequestMapping成为了使用Spring MVC的近乎唯一选择,所以它成为了实际意义上的标准实现,深入了解掌握它其实非常有必要。
本类具有内容多、体系庞大、实现复杂等特点,源码啃起来相较于其它模块还是要更加费劲的,这主要是由于它"集成"进来的组件非常之多,而每一个基础组件也是一个重要的且较难理解的知识点,因此路漫漫其修远兮…多看几遍吧,说不定啥时候就豁然开朗了。