添加方法:(基于spring-boot 2.2.x)
-
如果要添加自定义Handler, 可以写一个实现
WebMvcConfigurer
接口中addReturnValueHandlers()
的配置类,Spring容器启动时,会读取到这里的配置,最终增加到RequestMappingHandlerAdapter
的customReturnValueHandlers
成员变量中。
但是执行到这些Handler的顺序必定是在默认的Handler执行完之后。@Configuration public class MyHandlerConfig implements WebMvcConfigurer { @Override public void addReturnValueHandlers(List<HandlerMethodReturnValueHandler> handlers) { handlers.add(new MyHandler()); }
-
如果要改变顺序,或者注入特定的几种Handler,有两种方法:
-
方法1:RequestMappingHandlerAdapter对象创建时,显式调用
setReturnValueHandlers()
方法:做一个WebMvcConfigurationSupport
的子类,并且注入到容器中,并且重写createRequestMappingHandlerAdapter()
方法:@Component public MyWebMvcConfigurationSupport extends WebMvcConfigurationSupport { @Override protected RequestMappingHandlerAdapter createRequestMappingHandlerAdapter() { RequestMappingHandlerAdapter adapter = super.createRequestMappingHandlerAdapter(); List<HandlerMethodReturnValueHandler> myHandlerList = new ArrayList<>(); // 这里自定义Handler的顺序 myHandlerList.add(new MyHandler()); .... adapter.setReturnValueHandlers(myHandlerList); } }
-
方法2:直接将调用容器中的
RequestMappingHandlerAdapter
的setReturnValueHandlers()
方法重新设置Handler:@Configuration public class MyConfig { @Autowired RequestMappingHandlerAdapter requestMappingHandlerAdapter; @Bean public MyHandler createMyHandler() { MyHandler myHandler = new MyHandler(); ArrayList<HandlerMethodReturnValueHandler> returnValueHandlers = new ArrayList<>(); returnValueHandlers.add(myHandler); requestMappingHandlerAdapter.setReturnValueHandlers(returnValueHandlers); return myHandler; } }
-
源码分析(基于spring-webmvc-5.1.9.RELEASE)
-
HandlerMethodReturnValueHandler
是用来处理AbstractHandlerMethodMapping
所有映射的HandlerMethod
-
所有的
HandlerMethodReturnValueHandler
注册在RequestMappingHandlerAdapter
的returnValueHandlers
成员变量中, 其类型为HandlerMethodReturnValueHandlerComposite
, 它是一个复合Handler。另外还有一个List类型的customReturnValueHandlers
成员变量,用来注册自定义的Handler。private List<HandlerMethodReturnValueHandler> customReturnValueHandlers; private HandlerMethodReturnValueHandlerComposite returnValueHandlers;
-
RequestMappingHandlerAdapter
初始化时, 会调用getDefaultReturnValueHandlers()
方法:添加完一系列默认的Handler之后,再调用getCustomReturnValueHandlers()
方法注册自定义的Handler。private List<HandlerMethodReturnValueHandler> getDefaultReturnValueHandlers() { List<HandlerMethodReturnValueHandler> handlers = new ArrayList<>(); // Single-purpose return value types handlers.add(new ModelAndViewMethodReturnValueHandler()); handlers.add(new ModelMethodProcessor()); handlers.add(new ViewMethodReturnValueHandler()); handlers.add(new ResponseBodyEmitterReturnValueHandler(getMessageConverters(), this.reactiveAdapterRegistry, this.taskExecutor, this.contentNegotiationManager)); handlers.add(new StreamingResponseBodyReturnValueHandler()); 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 handlers.add(new ModelAttributeMethodProcessor(false)); handlers.add(new RequestResponseBodyMethodProcessor(getMessageConverters(), this.contentNegotiationManager, this.requestResponseBodyAdvice)); // Multi-purpose return value types handlers.add(new ViewNameMethodReturnValueHandler()); handlers.add(new MapMethodProcessor()); // Custom return value types if (getCustomReturnValueHandlers() != null) { handlers.addAll(getCustomReturnValueHandlers()); } // Catch-all if (!CollectionUtils.isEmpty(getModelAndViewResolvers())) { handlers.add(new ModelAndViewResolverMethodReturnValueHandler(getModelAndViewResolvers())); } else { handlers.add(new ModelAttributeMethodProcessor(true)); } return handlers; }
-
customReturnValueHandlers
可通过setCustomReturnValueHandlers
()方法设置,这个方法是在WebMvcConfigurationSupport
类中requestMappingHandlerAdapter()
方法中进行的, 可以复写此类的addReturnValueHandlers()
方法设置需要注册的Handler,而这个子类是DelegatingWebMvcConfiguration
,其内部有一个WebMvcConfigurerComposite
类型的复合配置configurers
,里面包含了所有的实现了WebMvcConfigurer
接口的配置对象,最终会调到配置类的addReturnValueHandlers()
方法,把自定义的Handler加到一开始的customReturnValueHandlers
成员变量里。 -
真正的去选取哪个Handler去调用
HandlerMethod
的逻辑是在ServletInvocableHandlerMethod
中调用HandlerMethodReturnValueHandlerComposite
进行的:// RequestMappingHandlerAdapter protected ModelAndView invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception { .... ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod); .... invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers); .... invocableMethod.invokeAndHandle(webRequest, mavContainer); .... return getModelAndView(mavContainer, modelFactory, webRequest); } // ServletInvocableHandlerMethod public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception { Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs); .... this.returnValueHandlers.handleReturnValue( returnValue, getReturnValueType(returnValue), mavContainer, webRequest); } // HandlerMethodReturnValueHandlerComposite public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception { HandlerMethodReturnValueHandler handler = selectHandler(returnValue, returnType); .... handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest); } private HandlerMethodReturnValueHandler selectHandler(@Nullable Object value, MethodParameter returnType) { boolean isAsyncValue = isAsyncReturnValue(value, returnType); for (HandlerMethodReturnValueHandler handler : this.returnValueHandlers) { if (isAsyncValue && !(handler instanceof AsyncHandlerMethodReturnValueHandler)) { continue; } if (handler.supportsReturnType(returnType)) { return handler; } } return null; }
-
所有Handler的实现都没有实现
Ordered
接口, 从注入默认到自定义,到最后的执行,也没有对Handler进行排序。Handler的选取顺序,全靠往List中add的顺序。
SpringBoot默认注入的HandlerMethodReturnValueHandler列表
No | 类型 | 支持的Return Type |
---|---|---|
1 | ModelAndViewMethodReturnValueHandler | ModelAndView |
2 | ModelMethodProcessor | Model |
3 | ViewMethodReturnValueHandler | View |
4 | ResponseBodyEmitterReturnValueHandler | ResponseBodyEmitter | ResponseEntity <ResponseBodyEmitter> |
5 | StreamingResponseBodyReturnValueHandler | StreamingResponseBody | ResponseEntity <StreamingResponseBody> |
6 | HttpEntityMethodProcessor | HttpEntity |
7 | HttpHeadersReturnValueHandler | HttpHeaders |
8 | CallableMethodReturnValueHandler | Callable |
9 | DeferredResultMethodReturnValueHandler | DeferredResult, ListenableFuture, CompletionStage |
10 | AsyncTaskMethodReturnValueHandler | WebAsyncTask |
11 | ModelAttributeMethodProcessor | @ModelAttribute |
12 | RequestResponseBodyMethodProcessor | @ResponseBody |
13 | ViewNameMethodReturnValueHandler | CharSequence, void |
14 | MapMethodProcessor | Map |
15 | ModelAndViewResolverMethodReturnValueHandler | All (modelAndViewResolvers 不为空) |
customReturnValueHandlers
注册的Handler在No14和No15之间。
疑惑
有两点比较疑惑
-
为什么注入的Handler不实现
Ordered
接口,不按照自己定义的顺序去加入。 -
为什么
customReturnValueHandlers
的优先级那么低,其实主要是No13的ViewNameMethodReturnValueHandler
,这时候如果返回了String或者void,这两种很常见的returnType直接就被劫走了,根本到达不了自定义Handler那边。
官方的Javadoc也明确这么说了:A String return value can be interpreted in more than one ways depending on the presence of annotations like {@code @ModelAttribute} or {@code@ResponseBody}.
Therefore this handler should be configured after the handlers that support these annotations.
我猜测可能是这个SpringMVC自己的规则,不能破坏,如果要完全打破这个规则,那直接自定义一个 RequestMappingHandlerAdapter
同级别的Adapter,自己去定义这些规则。但是工作量可能会大很多。