SpringMVC源码解析之RequestMappingHandlerAdapter
发布日期:2021-06-30 12:25:33 浏览次数:2 分类:技术文章

本文共 22107 字,大约阅读时间需要 73 分钟。

RequestMappingHandlerAdapter含有大量的web基础组件协助完成一整个请求的调度、处理

RequestMappingHandlerAdapter

适配@RequestMapping注解标注的Handler(HandlerMethod类型)

Spring3.1新增的一个适配器类,用于数据绑定、数据转换、数据校验、内容协商

因为有了它的存在,使得开发者几乎可以忘掉原生的Servlet API
Spring 5.0在把Servlet容器从必选项变成可选项后,即使切换了web容器(比如换成jetty),也能做到在使用层面上对开发者无感知

@since 3.1 实现了InitializingBean接口和BeanFactoryAware

public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter implements BeanFactoryAware, InitializingBean {
// 唯一构造方法:默认注册一些消息转换器。开启@EnableWebMvc后此默认行为会被set方法覆盖 public RequestMappingHandlerAdapter() {
StringHttpMessageConverter stringHttpMessageConverter = new StringHttpMessageConverter(); stringHttpMessageConverter.setWriteAcceptCharset(false); // see SPR-7316 this.messageConverters = new ArrayList<>(4); this.messageConverters.add(new ByteArrayHttpMessageConverter()); this.messageConverters.add(stringHttpMessageConverter); try {
this.messageConverters.add(new SourceHttpMessageConverter<>()); } catch (Error err) {
// Ignore when no TransformerFactory implementation is available } this.messageConverters.add(new AllEncompassingFormHttpMessageConverter()); } // 此方法在容器启动的时候会执行:扫描解析容器内的@ControllerAdvice等等 // 看起来代码不多,但其实每个方法内部,都可谓是个庞然大物,请详细观察理解~~~~ @Override public void afterPropertiesSet() {
// Do this first, it may add ResponseBody advice beans // 详见下面的解释分析 initControllerAdviceCache(); // 这三大部分,可是自 参数组装 相关的组件~~~~每一份都非常的重要 if (this.argumentResolvers == null) {
List
resolvers = getDefaultArgumentResolvers(); this.argumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers); } if (this.initBinderArgumentResolvers == null) {
List
resolvers = getDefaultInitBinderArgumentResolvers(); this.initBinderArgumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers); } if (this.returnValueHandlers == null) {
List
handlers = getDefaultReturnValueHandlers(); this.returnValueHandlers = new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers); } } }

为了突出重点,本文采用针对重点方法逐一描述的方式进行循序渐进的讲解:

initControllerAdviceCache()它是初始化@ControllerAdvice标注的Bean并解析其内部各部分(@ModelAttribute、@InitBinder、RequestBodyAdvice和ResponseBodyAdvice接口等)然后缓存起来的方法。RequestMappingHandlerAdapter:// ======================相关成员变量们======================// 装载RequestBodyAdvice和ResponseBodyAdvice的实现类们~private List requestResponseBodyAdvice = new ArrayList<>();// MethodIntrospector.selectMethods的过滤器。// 这里意思是:含有@ModelAttribute,但是但是但是不含有@RequestMapping注解的方法~~~~~public static final MethodFilter MODEL_ATTRIBUTE_METHODS = method -> (!AnnotatedElementUtils.hasAnnotation(method, RequestMapping.class) && AnnotatedElementUtils.hasAnnotation(method, ModelAttribute.class));// 标注了注解@InitBinder的方法~~~public static final MethodFilter INIT_BINDER_METHODS = method -> AnnotatedElementUtils.hasAnnotation(method, InitBinder.class);// 存储标注了@ModelAttribute注解的方法的缓存~~~~private final Map
> modelAttributeAdviceCache = new LinkedHashMap<>();// 存储标注了@InitBinder注解的方法的缓存~~~~private final Map
> initBinderAdviceCache = new LinkedHashMap<>(); private void initControllerAdviceCache() {
if (getApplicationContext() == null) {
return; } // 拿到容器内所有的标注有@ControllerAdvice的组件们 // BeanFactoryUtils.beanNamesForTypeIncludingAncestors(context, Object.class) // .filter(name -> context.findAnnotationOnBean(name, ControllerAdvice.class) != null) // .map(name -> new ControllerAdviceBean(name, context)) // 使用ControllerAdviceBean包装起来,持有name的引用(还木实例化哟) // .collect(Collectors.toList()); // 因为@ControllerAdvice注解可以指定包名等属性,具体可参见HandlerTypePredicate的判断逻辑,是否生效 // 注意:@RestControllerAdvice是@ControllerAdvice和@ResponseBody的结合体,所以此处也会被找出来 // 最后Ordered排序 List
adviceBeans = ControllerAdviceBean.findAnnotatedBeans(getApplicationContext()); AnnotationAwareOrderComparator.sort(adviceBeans); // 临时存储RequestBodyAdvice和ResponseBodyAdvice的实现类 // 它哥俩是必须配合@ControllerAdvice一起使用的~ List
requestResponseBodyAdviceBeans = new ArrayList<>(); for (ControllerAdviceBean adviceBean : adviceBeans) {
Class
beanType = adviceBean.getBeanType(); if (beanType == null) {
throw new IllegalStateException("Unresolvable type for ControllerAdviceBean: " + adviceBean); } // 又见到了这个熟悉的方法selectMethods~~~~过滤器请参照成员变量 // 含有@ModelAttribute,但是但是但是不含有@RequestMapping注解的方法~~~~~ 找到之后放在全局变量缓存起来 // 简单的说就是找到@ControllerAdvice里面所有的@ModelAttribute方法们 Set
attrMethods = MethodIntrospector.selectMethods(beanType, MODEL_ATTRIBUTE_METHODS); if (!attrMethods.isEmpty()) { this.modelAttributeAdviceCache.put(adviceBean, attrMethods); } // 找标注了注解@InitBinder的方法~~~(和有没有@RequestMapping木有关系了~~~) // 找到@ControllerAdvice里面所有的@InitBinder方法们 Set
binderMethods = MethodIntrospector.selectMethods(beanType, INIT_BINDER_METHODS); if (!binderMethods.isEmpty()) { this.initBinderAdviceCache.put(adviceBean, binderMethods); } // 这两个接口是Spring4.1 4.2提供的,实现了这两个接口的 // 此处先放在requestResponseBodyAdviceBeans里面装着 最后放到全局缓存requestResponseBodyAdvice里面去 if (RequestBodyAdvice.class.isAssignableFrom(beanType) || ResponseBodyAdvice.class.isAssignableFrom(beanType)) { requestResponseBodyAdviceBeans.add(adviceBean); } } // 这个意思是,放在该list的头部。 // 因为requestResponseBodyAdvice有可能通过set方法进来已经有值了~~~所以此处放在头部 if (!requestResponseBodyAdviceBeans.isEmpty()) { this.requestResponseBodyAdvice.addAll(0, requestResponseBodyAdviceBeans); } // 输出debug日志...略(debug日志哦~) if (logger.isDebugEnabled()) { ... } }

该步骤调理清晰,有4个作用:

找到容器内(包括父容器)所有的标注有@ControllerAdvice注解的Bean们缓存起来,然后一个个解析此种Bean

找到该Advice Bean内所有的标注有@ModelAttribute但没标注@RequestMapping的方法们,缓存到modelAttributeAdviceCache里对全局生效
找到该Advice Bean内所有的标注有@InitBinder的方法们,缓存到initBinderAdviceCache里对全局生效
找到该Advice Bean内所有实现了接口RequestBodyAdvice/ResponseBodyAdvice们,最终放入缓存requestResponseBodyAdvice的头部,他们会介入请求body和返回body
介绍完此initControllerAdviceCache方法后,继续afterPropertiesSet()后续方法:初始化参数解析器、@InitBinder参数解析器、返回值解析器等。

@Override	public void afterPropertiesSet() {
... // 初始化参数解析器 if (this.argumentResolvers == null) {
List
resolvers = getDefaultArgumentResolvers(); this.argumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers); } // 初始化@InitBinder的参数解析器 if (this.initBinderArgumentResolvers == null) {
List
resolvers = getDefaultInitBinderArgumentResolvers(); this.initBinderArgumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers); } // 初始化返回值解析器 if (this.returnValueHandlers == null) {
List
handlers = getDefaultReturnValueHandlers(); this.returnValueHandlers = new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers); } }getDefaultArgumentResolvers()这个步骤作用是初始化HandlerMethodArgumentResolver,提供对方法参数的支持。RequestMappingHandlerAdapter: // Return the list of argument resolvers to use including built-in resolvers and custom resolvers provided via {@link #setCustomArgumentResolvers}. // 返回内建的参数处理器们,以及用户自定义的一些参数处理器(注意顺序) private List
getDefaultArgumentResolvers() {
List
resolvers = new ArrayList<>(); // Annotation-based argument resolution // 基于注解的 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(), this.requestResponseBodyAdvice)); resolvers.add(new RequestPartMethodArgumentResolver(getMessageConverters(), this.requestResponseBodyAdvice)); resolvers.add(new RequestHeaderMethodArgumentResolver(getBeanFactory())); resolvers.add(new RequestHeaderMapMethodArgumentResolver()); resolvers.add(new ServletCookieValueMethodArgumentResolver(getBeanFactory())); resolvers.add(new ExpressionValueMethodArgumentResolver(getBeanFactory())); resolvers.add(new SessionAttributeMethodArgumentResolver()); resolvers.add(new RequestAttributeMethodArgumentResolver()); // Type-based argument resolution // 基于type类型的 resolvers.add(new ServletRequestMethodArgumentResolver()); resolvers.add(new ServletResponseMethodArgumentResolver()); resolvers.add(new HttpEntityMethodProcessor(getMessageConverters(), this.requestResponseBodyAdvice)); resolvers.add(new RedirectAttributesMethodArgumentResolver()); resolvers.add(new ModelMethodProcessor()); resolvers.add(new MapMethodProcessor()); resolvers.add(new ErrorsMethodArgumentResolver()); resolvers.add(new SessionStatusMethodArgumentResolver()); resolvers.add(new UriComponentsBuilderMethodArgumentResolver()); // Custom arguments // 用户自定义的 if (getCustomArgumentResolvers() != null) {
resolvers.addAll(getCustomArgumentResolvers()); } // Catch-all // 兜底方案:这就是为何很多时候不写注解参数也能够被自动封装的原因 resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), true)); resolvers.add(new ServletModelAttributeMethodProcessor(true)); return resolvers; }这里使用的是ArrayList保存的,所以处理器都是有序的。最终会放进HandlerMethodArgumentResolverComposite使用Composite模式统一管理和使用~getDefaultInitBinderArgumentResolvers()这篇文章里有介绍过@InitBinder注解标注的方法入参也是可以写很多类型的参数的,需要注意的是它没有上面支持的那么全面,它支持的内容如下:RequestMappingHandlerAdapter: private List
getDefaultInitBinderArgumentResolvers() { List
resolvers = new ArrayList<>(); // Annotation-based argument resolution 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 ExpressionValueMethodArgumentResolver(getBeanFactory())); resolvers.add(new SessionAttributeMethodArgumentResolver()); resolvers.add(new RequestAttributeMethodArgumentResolver()); // Type-based argument resolution resolvers.add(new ServletRequestMethodArgumentResolver()); resolvers.add(new ServletResponseMethodArgumentResolver()); // Custom arguments if (getCustomArgumentResolvers() != null) { resolvers.addAll(getCustomArgumentResolvers()); } // Catch-all resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), true)); return resolvers; }从此处可以看到它具体支持哪些参数喽,像什么@RequestParam/@PathVariable/ServletRequest...等等都是支持的,但像什么@ModelAttribute/@RequestBody/@RequestPart等等这些它就不支持了。getDefaultReturnValueHandlers()顾名思义,它是提供对HandlerMethod返回值的支持,最终使用的是HandlerMethodReturnValueHandlerComposite相同的模式管理和使用,此处是初始化逻辑,具体使用可点击这里。RequestMappingHandlerAdapter: private List
getDefaultReturnValueHandlers() { List
handlers = new ArrayList<>(); // Single-purpose return value types handlers.add(new ModelAndViewMethodReturnValueHandler()); handlers.add(new ModelMethodProcessor()); handlers.add(new ViewMethodReturnValueHandler()); // 返回值是ResponseBodyEmitter时候,得用reactiveAdapterRegistry看看是Reactive模式还是普通模式 // taskExecutor:异步时使用的线程池,使用当前类的 contentNegotiationManager:内容协商管理器 handlers.add(new ResponseBodyEmitterReturnValueHandler(getMessageConverters(), this.reactiveAdapterRegistry, this.taskExecutor, this.contentNegotiationManager)); handlers.add(new StreamingResponseBodyReturnValueHandler()); // 此处重要的是getMessageConverters()消息转换器,一般情况下Spring MVC默认会有8个,包括`MappingJackson2HttpMessageConverter` // 参见:WebMvcConfigurationSupport定的@Bean --> RequestMappingHandlerAdapter部分 // 若不@EnableWebMvc默认是只有4个消息转换器的哦~(不支持json) // 此处的requestResponseBodyAdvice会介入到请求和响应的body里(消息转换期间) handlers.add(new HttpEntityMethodProcessor(getMessageConverters(), this.contentNegotiationManager, this.requestResponseBodyAdvice)); handlers.add(new HttpHeadersReturnValueHandler()); handlers.add(new CallableMethodReturnValueHandler()); handlers.add(new DeferredResultMethodReturnValueHandler()); handlers.add(new AsyncTaskMethodReturnValueHandler(this.beanFactory)); // Annotation-based return value types // 当标注有@ModelAttribute或者@ResponseBody的时候 这里来处理。显然也用到了消息转换器~ handlers.add(new ModelAttributeMethodProcessor(false)); handlers.add(new RequestResponseBodyMethodProcessor(getMessageConverters(), this.contentNegotiationManager, this.requestResponseBodyAdvice)); // Multi-purpose return value types // 当返回的是个字符串/Map时候,这时候就可能有多个目的了(Multi-purpose) // 比如字符串:可能重定向redirect、或者直接到某个view handlers.add(new ViewNameMethodReturnValueHandler()); handlers.add(new MapMethodProcessor()); // Custom return value types // 自定义的返回值处理器 if (getCustomReturnValueHandlers() != null) { handlers.addAll(getCustomReturnValueHandlers()); } // Catch-all // 兜底:ModelAndViewResolver是需要你自己实现然后set进来的(一般我们不会自定定义) // 所以绝大部分情况兜底使用的是ModelAttributeMethodProcessor表示,即使你的返回值里木有标注@ModelAttribute // 但你是非简单类型(比如对象类型)的话,返回值都会放进Model里 if (!CollectionUtils.isEmpty(getModelAndViewResolvers())) { handlers.add(new ModelAndViewResolverMethodReturnValueHandler(getModelAndViewResolvers())); } else { handlers.add(new ModelAttributeMethodProcessor(true)); } return handlers; }这个步骤完成后,整个RequestMappingHandlerAdapter的初始化就全部完成了。当然它还有一些属性、方法等都没有讲述到,下面做出集中式的统一说明:其它重要属性、方法属性:RequestMappingHandlerAdapter: // ModelAndViewResolver木有内置实现,可自定义实现来参与到返回值到ModelAndView的过程(自定义返回值处理) // 一般不怎么使用,我个人也不太推荐使用 @Nullable private List
modelAndViewResolvers; // 内容协商管理器 默认就是它喽(使用的协商策略是HeaderContentNegotiationStrategy) private ContentNegotiationManager contentNegotiationManager = new ContentNegotiationManager(); // 消息转换器。使用@Bean定义的时候,记得set进来,否则默认只会有4个(不支持json) // 若@EnableWebMvc后默认是有8个的,一般都够用了 private List
> messageConverters; // 它在数据绑定初始化的时候会被使用到,调用其initBinder()方法 // 只不过,现在一般都使用@InitBinder注解来处理了,所以使用较少 // 说明:它作用域是全局的,对所有的HandlerMethod都生效~~~~~ @Nullable private WebBindingInitializer webBindingInitializer; // 默认使用的SimpleAsyncTaskExecutor:每次执行客户提交给它的任务时,它会启动新的线程 // 并允许开发者控制并发线程的上限(concurrencyLimit),从而起到一定的资源节流作用(默认值是-1,表示不限流) // @EnableWebMvc时可通过复写接口的WebMvcConfigurer.getTaskExecutor()自定义提供一个线程池 private AsyncTaskExecutor taskExecutor = new SimpleAsyncTaskExecutor("MvcAsync"); // invokeHandlerMethod()执行目标方法时若需要异步执行,超时时间可自定义(默认不超时) // 使用上面的taskExecutor以及下面的callableInterceptors/deferredResultInterceptors参与异步的执行 @Nullable private Long asyncRequestTimeout; private CallableProcessingInterceptor[] callableInterceptors = new CallableProcessingInterceptor[0]; private DeferredResultProcessingInterceptor[] deferredResultInterceptors = new DeferredResultProcessingInterceptor[0]; // @Since 5.0 private ReactiveAdapterRegistry reactiveAdapterRegistry = ReactiveAdapterRegistry.getSharedInstance(); // 对应ModelAndViewContainer.setIgnoreDefaultModelOnRedirect()属性 // redirect时,是否忽略defaultModel 默认值是false:不忽略 private boolean ignoreDefaultModelOnRedirect = false; // 返回内容缓存多久(默认不缓存) 参考类:WebContentGenerator private int cacheSecondsForSessionAttributeHandlers = 0; // 执行目标方法HandlerMethod时是否要在同一个Session内同步执行??? // 也就是同一个会话时,控制器方法全部同步执行(加互斥锁) // 使用场景:对同一用户同一Session的所有访问,必须串行化~~~~~~ private boolean synchronizeOnSession = false; private SessionAttributeStore sessionAttributeStore = new DefaultSessionAttributeStore(); private ParameterNameDiscoverer parameterNameDiscoverer = new DefaultParameterNameDiscoverer(); @Nullable private ConfigurableBeanFactory beanFactory; // ====================下面是各种缓存们==================== private final Map
, SessionAttributesHandler> sessionAttributesHandlerCache = new ConcurrentHashMap<>(64); private final Map
, Set
> initBinderCache = new ConcurrentHashMap<>(64); private final Map
> initBinderAdviceCache = new LinkedHashMap<>(); private final Map
, Set
> modelAttributeCache = new ConcurrentHashMap<>(64); private final Map
> modelAttributeAdviceCache = new LinkedHashMap<>();方法: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; }

handleInternal

使用给定的处理器方法处理请求。

AbstractHandlerMethodAdapter中定义的 protected 抽象方法,专门由该子类实现。
开始处理请求,返回一个ModelAndView。

@Overrideprotected ModelAndView handleInternal(HttpServletRequest request, 		HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
ModelAndView mav; checkRequest(request); // 如果需要,在同步块中执行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():

// 它的作用就是执行目标的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
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()。

Spring MVC默认装配了哪些HandlerAdapter呢?

开启@EnableWebMvc:

总结

RequestMappingHandlerAdapter作为HandlerAdapter适配模式的实现,由于@RequestMapping成为了使用Spring MVC的几乎唯一选择,所以它成为了实际意义上的标准实现

转载地址:https://javaedge.blog.csdn.net/article/details/106525270 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:SpringMVC源码解析AbstractHandlerMethodAdapter
下一篇:Spring MVC源码解析之HandlerMethod、ServletInvocableHandlerMethod

发表评论

最新留言

不错!
[***.144.177.141]2024年04月29日 16时30分11秒