其实在我们平常使用的@RestController注解中,就已经包含了对返回结果的处理:
其关键点便在于@ResponseBody这个注解,在我们的普通MVC框架中,在获取结果以后是要同时返回ModelAndView的,也就是数据和视图。
如果标注了@ResponseBody注解,则会触发默认的后置处理器,对返回结果进行处理,其核心方法如下:
其核心方法便是实现接口HandlerMethodReturnValueHandler中的两个方法:
public interface HandlerMethodReturnValueHandler {
boolean supportsReturnType(MethodParameter var1);
void handleReturnValue(@Nullable Object var1, MethodParameter var2, ModelAndViewContainer var3, NativeWebRequest var4) throws Exception;
}
通过supportsReturnType确认进入此类,然后执行handleReturnValue对返回结果进行处理。
额外说一句,DispatchServelet中的
mappedHandler.applyPostHandle(processedRequest, response, mv);
调用
HandlerInterceptor中的postHandle方法
也可以实现类似的效果,但是到了这一步中,结果已经被转换成了流对象,只能对response的字节流进行处理,这样就会麻烦许多。
接着说SpringMVC的后置处理器,我们只需要自定义一个HandlerMethodReturnValueHandler的实现类,自定义一个注解,仿照上文解析@ResponseBody注解的类的写法,便可以自定义我们自己的后置处理器,可以认为自己写了一个仿版@ResponseBody后置处理器。
在使用自定义的后置处理器的过程中,有2点需要注意,避免踩坑。
1、类上不能使用@RestController这个组合注解,要把@Controller和@ResponseBody分开,这样在普通的方法中加入@ResponseBody注解,自定义的方法加入我们自定义的注解。
2、在完成第一步以后,检查一下Controller层方法的返回类型是不是Map类型,如果是换一个。
其原因便是由于请求完成以后,后置处理器执行逻辑会遍历已经存在的后置处理器,我们自定义的一定是在@ResponseBody和Map类型的后置处理器后面,如果前面有满足条件的处理器,后面的便不会执行。
后置处理器的执行原理如下:
RequestMappingHandlerAdapter可以自定义一个controller请求的返回结果。
DispatcherServlet进入doDispatch方法,
通过mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
进入controller层,调用请求的具体方法为:
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
boolean multipartRequestParsed = false;
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
try {
try {
ModelAndView mv = null;
Object dispatchException = null;
try {
processedRequest = this.checkMultipart(request);
multipartRequestParsed = processedRequest != request;
mappedHandler = this.getHandler(processedRequest);
if (mappedHandler == null) {
this.noHandlerFound(processedRequest, response);
return;
}
HandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler());
String method = request.getMethod();
boolean isGet = "GET".equals(method);
if (isGet || "HEAD".equals(method)) {
long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
if ((new ServletWebRequest(request, response)).checkNotModified(lastModified) && isGet) {
return;
}
}
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
之后,再选择合适的适配器来进行controller层的调用:
@Nullable
public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
return this.handleInternal(request, response, (HandlerMethod)handler);
}
进入找到的适配器RequestMappingHandlerAdapter执行handleInternal
protected ModelAndView handleInternal(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
this.checkRequest(request);
ModelAndView mav;
if (this.synchronizeOnSession) {
HttpSession session = request.getSession(false);
if (session != null) {
Object mutex = WebUtils.getSessionMutex(session);
synchronized(mutex) {
mav = this.invokeHandlerMethod(request, response, handlerMethod);
}
} else {
mav = this.invokeHandlerMethod(request, response, handlerMethod);
}
} else {
mav = this.invokeHandlerMethod(request, response, handlerMethod);
}
下一步:
public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
Object returnValue = this.invokeForRequest(webRequest, mavContainer, providedArgs);
this.setResponseStatus(webRequest);
if (returnValue == null) {
if (this.isRequestNotModified(webRequest) || this.getResponseStatus() != null || mavContainer.isRequestHandled()) {
this.disableContentCachingIfNecessary(webRequest);
mavContainer.setRequestHandled(true);
return;
}
} else if (StringUtils.hasText(this.getResponseStatusReason())) {
mavContainer.setRequestHandled(true);
return;
}
mavContainer.setRequestHandled(false);
Assert.state(this.returnValueHandlers != null, "No return value handlers");
try {
this.returnValueHandlers.handleReturnValue(returnValue, this.getReturnValueType(returnValue), mavContainer, webRequest);
} catch (Exception var6) {
if (this.logger.isTraceEnabled()) {
this.logger.trace(this.formatErrorForReturnValue(returnValue), var6);
}
throw var6;
}
}
通过invocableMethod.invokeAndHandle(webRequest, mavContainer, new Object[0])方法,进入controller层后(Object returnValue = this.invokeForRequest(webRequest, mavContainer, providedArgs);),请求完成后再执行对返回数据的后置处理(this.returnValueHandlers.handleReturnValue(returnValue, this.getReturnValueType(returnValue), mavContainer, webRequest);)。
进入HandlerMethodReturnValueHandlerComposite类中,选择合适的后置处理器,对请求成功的数据进行处理:
这时候可以对标有@ResponseBody注解的方法进行特殊的后置处理,也就是把数据转换成json,返回前端。
public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
HandlerMethodReturnValueHandler handler = this.selectHandler(returnValue, returnType);
if (handler == null) {
throw new IllegalArgumentException("Unknown return value type: " + returnType.getParameterType().getName());
} else {
handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);
}
}
如果我们需要自定义数据的后置处理,我们可以扩展selectHandler方法中引用的returnValueHandlers属性,也就是实现上文提到的HandlerMethodReturnValueHandler接口,我们可以对其进行扩展。
@Nullable
private HandlerMethodReturnValueHandler selectHandler(@Nullable Object value, MethodParameter returnType) {
boolean isAsyncValue = this.isAsyncReturnValue(value, returnType);
Iterator var4 = this.returnValueHandlers.iterator();
HandlerMethodReturnValueHandler handler;
do {
do {
if (!var4.hasNext()) {
return null;
}
handler = (HandlerMethodReturnValueHandler)var4.next();
} while(isAsyncValue && !(handler instanceof AsyncHandlerMethodReturnValueHandler));
} while(!handler.supportsReturnType(returnType));
return handler;
}
依然是在HandlerMethodReturnValueHandlerComposite中,可以看到其类型为:
private final List<HandlerMethodReturnValueHandler> returnValueHandlers = new ArrayList();
那么returnValueHandlers 是如何初始化的呢?
我们可以通过在HandlerMethodReturnValueHandlerComposite中的addHandlers方法打上断点,在重启项目,就可以看到其加载来源。
通过debugger我们可以看到,在执行doGetBean的过程中,执行了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()).addResolvers(handlers);
}
if (this.returnValueHandlers == null) {
handlers = this.getDefaultReturnValueHandlers();
this.returnValueHandlers = (new HandlerMethodReturnValueHandlerComposite()).addHandlers(handlers);
}
}
最终对
public HandlerMethodReturnValueHandlerComposite addHandlers(@Nullable List<? extends HandlerMethodReturnValueHandler> handlers) {
if (handlers != null) {
this.returnValueHandlers.addAll(handlers);
}
return this;
}
执行了调用。
通过同一个断点,可以看到这整个流程其实就是RequestMappingHandlerAdapter这个bean的初始化过程。
也就是说在ioc容器启动的过程中对RequestMappingHandlerAdapter进行初始化的时候,通过afterPropertiesSet方法中,通过addHandlers(handlers)直接把controller执行完成后的后置处理器给配置好了。
那么关键的代码便是在RequestMappingHandlerAdapter中的:
if (this.returnValueHandlers == null) {
handlers = this.getDefaultReturnValueHandlers();
this.returnValueHandlers = (new HandlerMethodReturnValueHandlerComposite()).addHandlers(handlers);
}
可以看到,第一步是先加载了默认的controller执行完成后,可能执行的handler。第二步就是把这个handlers塞给returnValueHandlers。
此后再从returnValueHandlers中选择需要执行的后置处理器。
其中关键方法便是getDefaultReturnValueHandlers:
private List<HandlerMethodReturnValueHandler> getDefaultReturnValueHandlers() {
List<HandlerMethodReturnValueHandler> handlers = new ArrayList(20);
handlers.add(new ModelAndViewMethodReturnValueHandler());
handlers.add(new ModelMethodProcessor());
handlers.add(new ViewMethodReturnValueHandler());
handlers.add(new ResponseBodyEmitterReturnValueHandler(this.getMessageConverters(), this.reactiveAdapterRegistry, this.taskExecutor, this.contentNegotiationManager));
handlers.add(new StreamingResponseBodyReturnValueHandler());
handlers.add(new HttpEntityMethodProcessor(this.getMessageConverters(), this.contentNegotiationManager, this.requestResponseBodyAdvice));
handlers.add(new HttpHeadersReturnValueHandler());
handlers.add(new CallableMethodReturnValueHandler());
handlers.add(new DeferredResultMethodReturnValueHandler());
handlers.add(new AsyncTaskMethodReturnValueHandler(this.beanFactory));
handlers.add(new ModelAttributeMethodProcessor(false));
handlers.add(new RequestResponseBodyMethodProcessor(this.getMessageConverters(), this.contentNegotiationManager, this.requestResponseBodyAdvice));
handlers.add(new ViewNameMethodReturnValueHandler());
handlers.add(new MapMethodProcessor());
if (this.getCustomReturnValueHandlers() != null) {
handlers.addAll(this.getCustomReturnValueHandlers());
}
if (!CollectionUtils.isEmpty(this.getModelAndViewResolvers())) {
handlers.add(new ModelAndViewResolverMethodReturnValueHandler(this.getModelAndViewResolvers()));
} else {
handlers.add(new ModelAttributeMethodProcessor(true));
}
return handlers;
}
可以看到,我们可以基于handlers.addAll(this.getCustomReturnValueHandlers());这段代码对后置处理器进行自定义。
可以看到RequestMappingHandlerAdapter的初始化过程就在WebMvcAutoConfiguration的内部类,EnableWebMvcConfiguration中:
public static class EnableWebMvcConfiguration extends DelegatingWebMvcConfiguration implements ResourceLoaderAware {
private final ResourceProperties resourceProperties;
private final WebMvcProperties mvcProperties;
private final WebMvcRegistrations mvcRegistrations;
private ResourceLoader resourceLoader;
private final ListableBeanFactory beanFactory;
public EnableWebMvcConfiguration(ResourceProperties resourceProperties, ObjectProvider<WebMvcProperties> mvcPropertiesProvider, ObjectProvider<WebMvcRegistrations> mvcRegistrationsProvider, ListableBeanFactory beanFactory) {
this.resourceProperties = resourceProperties;
this.mvcProperties = (WebMvcProperties)mvcPropertiesProvider.getIfAvailable();
this.mvcRegistrations = (WebMvcRegistrations)mvcRegistrationsProvider.getIfUnique();
this.beanFactory = beanFactory;
}
@Bean
public RequestMappingHandlerAdapter requestMappingHandlerAdapter(@Qualifier("mvcContentNegotiationManager") ContentNegotiationManager contentNegotiationManager, @Qualifier("mvcConversionService") FormattingConversionService conversionService, @Qualifier("mvcValidator") Validator validator) {
RequestMappingHandlerAdapter adapter = super.requestMappingHandlerAdapter(contentNegotiationManager, conversionService, validator);
adapter.setIgnoreDefaultModelOnRedirect(this.mvcProperties == null || this.mvcProperties.isIgnoreDefaultModelOnRedirect());
return adapter;
}
@Bean
public RequestMappingHandlerAdapter requestMappingHandlerAdapter(@Qualifier("mvcContentNegotiationManager") ContentNegotiationManager contentNegotiationManager, @Qualifier("mvcConversionService") FormattingConversionService conversionService, @Qualifier("mvcValidator") Validator validator) {
RequestMappingHandlerAdapter adapter = this.createRequestMappingHandlerAdapter();
adapter.setContentNegotiationManager(contentNegotiationManager);
adapter.setMessageConverters(this.getMessageConverters());
adapter.setWebBindingInitializer(this.getConfigurableWebBindingInitializer(conversionService, validator));
adapter.setCustomArgumentResolvers(this.getArgumentResolvers());
adapter.setCustomReturnValueHandlers(this.getReturnValueHandlers());
在初始化的时候调用了setCustomReturnValueHandlers:
public void setCustomReturnValueHandlers(@Nullable List<HandlerMethodReturnValueHandler> returnValueHandlers) {
this.customReturnValueHandlers = returnValueHandlers;
}
所以我们可以在
@Configuration
public class CustomWebMvcConfigurer implements WebMvcConfigurer
的配置中,自定义我们的:
default void addReturnValueHandlers(List<HandlerMethodReturnValueHandler> handlers) {
}
以上,就是SpringMVC框架中的后置处理器实现方法和原理。