参考资料:
写在开头:本文为个人学习笔记,内容比较随意,夹杂个人理解,如有错误,欢迎指正。
前文:
《SpringMVC源码:DispatcherServlet初始化流程》
《SpringMVC源码:HandlerMapping加载1》
《SpringMVC源码:HandlerMapping加载2》
《SpringMVC源码:getHandler、getHandlerAdapter过程》
前文我们已经介绍了,doDispatch方法过程中的handler查找、适配器查找以及拦截器preHandle方法的执行,本文我们会继续介绍方法的调用。
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
boolean multipartRequestParsed = false;
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
try {
ModelAndView mv = null;
Exception dispatchException = null;
try {
//检查是否为Multipart请求,如果是则HttpServletRequest转换为MultipartHttpServletRequest
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);
//1.根据request信息寻找对应的Handler
//并返回mappedHeadler,它是一个执行链,包含拦截器和自定义controller
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) {
//没有找到Handler则通过response反馈错误信息
noHandlerFound(processedRequest, response);
return;
}
// 2.根据当前的handler寻找对应的HandlerAdapter
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// 当前handler处理last-modified
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;
}
}
//3.mappedHandler调用拦截器的preHandler方法
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// 4.HandlerAdapter调用自定义Controller中的方法并返回ModelAndView
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
//5.视图解析,为request请求找到视图
applyDefaultViewName(processedRequest, mv);
//6.调用拦截器的postHandle方法
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
}
目录
1、AbstractHandlerMethodAdapter#handle
2、RequestMappingHandlerAdapter#handleInternal
3、RequestMappingHandlerAdapter#invokeHandlerMethod
4、ServletInvocableHandlerMethod#invokeAndHandle
InvocableHandlerMethod#invokeForRequest
5、RequestMappingHandlerAdapter#getModelAndView
一、handle
1、AbstractHandlerMethodAdapter#handle
这里以AbstractHandlerMethodAdapter类为例,可以看到内部实际上是调用了handleInternal方法,而这个方法实际上是由子类RequestMappingHandlerAdapter实现的。(注意下这里的返回值为ModelAndView)
@Override
public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
return handleInternal(request, response, (HandlerMethod) handler);
}
2、RequestMappingHandlerAdapter#handleInternal
该方法主要进行了对请求request的相关校验、解析、转换、执行相关的handler的invokeHandlerMethod 并返回对应的数据视图对象。
@Override
protected ModelAndView handleInternal(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
ModelAndView mav;
//如果设置supportMethods、requireSession属性需要对其进行校验
//如果处理的请求方式不是supportMethods集合支持的抛出异常
//或者requireSession为true但是request不包含session同样抛出异常
checkRequest(request);
// 针对线程不安全的session 提供两种方式 一种是同步 从而保证该会话的用户串行执行请求
// 一种是非同步处理请求 不管同步与否最终调用核心方法invokeHandlerMethod 调用HandlerMethod
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);
}
//为响应资源设置对应的缓存时间,指定时间内可以直接使用本地缓存
if (!response.containsHeader(HEADER_CACHE_CONTROL)) {
if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);
}
else {
prepareResponse(response);
}
}
return mav;
}
3、RequestMappingHandlerAdapter#invokeHandlerMethod
这一步中将HandlerMethod被封装ServletInvocableHandlerMethod,包裹上方法执行需要的信息并调用invokeAndHandle方法执行,最后通过getModelAndView获取视图。
protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
//先将请求响应对象包装成ServletWebRequest
ServletWebRequest webRequest = new ServletWebRequest(request, response);
try {
//获取该方法的所有使用@InitBinder注解修饰的方法
//包装成WebDataBinderFactory 在handlerMethod执行前调用(包含类作用范围的和全局作用范围的)
WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
//获取该方法的所有使用@ModelAttribute注解修饰的方法 包装成ModelFactory(包含类作用范围的和全局作用范围的)
ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);
//将HandlerMethod方法包装成ServletInvocableHandlerMethod(该对象是InvocableHandlerMethod子类)
//设置相关的组件 比如设置参数解析组件argumentResolvers和返回结果处理组件returnValueHandlers
//绑定组件binderFactory和parameterNameDiscoverer
ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
invocableMethod.setDataBinderFactory(binderFactory);
invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
//创建数据模型和视图的容器对象 见名知义其包含我们所常见的数据和视图对象
ModelAndViewContainer mavContainer = new ModelAndViewContainer();
//对于重定向相关的参数保存需要依赖flashMap对象,如果一个请求是重定向请求 则input_flash_map保存重定向入参
//如果一个请求需要进行重定向 则参数会存放到output_flash_map中
mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
//调用@ModelAttribute注解修饰的方法将对应的属性存放到mavContainer 的model中
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);
}
//通过反射执行相关的handlerMethod 涉及参数解析,返回值的处理、
//invocableMethod已经包含了进行参数解析和返回值处理的组件对象
invocableMethod.invokeAndHandle(webRequest, mavContainer);
if (asyncManager.isConcurrentHandlingStarted()) {
return null;
}
//主要处理sessionAttribute 以及对model中的属性进行属性编辑器的转换处理@InitBinder
//对于view对象进行逻辑视图到物理视图的转换以及重定向参数的设置
return getModelAndView(mavContainer, modelFactory, webRequest);
}
finally {
webRequest.requestCompleted();
}
}
4、ServletInvocableHandlerMethod#invokeAndHandle
首先调用invokeForRequest进行参数解析与方法调用,得到返回值后将其封装入mavContainer中。
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);
}
InvocableHandlerMethod#invokeForRequest
invokeForRequest方法首先解析参数,然后反射执行方法。
public Object invokeForRequest(NativeWebRequest request, ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
//调用getMethodArgumentValues进行参数解析
Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
//调用doInvoke方法反射执行handler处理器
Object returnValue = doInvoke(args);
return returnValue;
}
protected Object doInvoke(Object... args) throws Exception {
ReflectionUtils.makeAccessible(getBridgedMethod());
return getBridgedMethod().invoke(getBean(), args);
}
5、RequestMappingHandlerAdapter#getModelAndView
从mavContainer取出结果包装成ModelAndView并返回给前端控制器,整个handler处理器的调用完成,后续进入视图处理阶段。
private ModelAndView getModelAndView(ModelAndViewContainer mavContainer,
ModelFactory modelFactory, NativeWebRequest webRequest) throws Exception {
modelFactory.updateModel(webRequest, mavContainer);
if (mavContainer.isRequestHandled()) {
return null;
}
//从mavContainer中取出model
ModelMap model = mavContainer.getModel();
//根据取出的model创建视图对象
ModelAndView mav = new ModelAndView(mavContainer.getViewName(), model, mavContainer.getStatus());
if (!mavContainer.isViewReference()) {
mav.setView((View) mavContainer.getView());
}
//处理redirect请求
if (model instanceof RedirectAttributes) {
Map<String, ?> flashAttributes = ((RedirectAttributes) model).getFlashAttributes();
HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
RequestContextUtils.getOutputFlashMap(request).putAll(flashAttributes);
}
return mav;
}
二、@RequestBody与@ResponseBody
以下内容参考自
《Spring MVC源码(三) —– @RequestBody和@ResponseBody原理解析》
在上文中我们介绍了invokeAndHandle方法,其中的两个步骤分别为参数解析与返回值处理,这一节我们结合两个常用注解@RequestBody与@ResponseBody来进行这部分内容的讲解。
首先来看个样例,第一个requestBody请求,使用@RequestBody将HTTP请求体转换成String类型,第二个responseBody请求,将Map对象转换成json格式输出到HTTP响应中。
@RequestMapping("/requestBody")
public void requestBody(@RequestBody String body, Writer writer) throws IOException{
writer.write(body);
}
@RequestMapping(value="/responseBody", produces="application/json")
@ResponseBody
public Map<String, Object> responseBody(){
Map<String, Object> retMap = new HashMap<>();
retMap.put("param1", "abc");
return retMap;
}
这两个注解都实现了HTTP报文信息同Controller方法中对象的转换,下面我们就来进行原理分析。
1、接口转换
SpringMVC中为了实现HTTP消息体和参数及返回值进行转换,所有转换类都实现了HttpMessageConverter接口,该接口定义了5个方法,用于将HTTP请求报文转换为java对象,以及将java对象转换为HTTP响应报文。
public interface HttpMessageConverter<T> {
// 当前转换器是否能将HTTP报文转换为对象类型
boolean canRead(Class<?> clazz, MediaType mediaType);
// 当前转换器是否能将对象类型转换为HTTP报文
boolean canWrite(Class<?> clazz, MediaType mediaType);
// 转换器能支持的HTTP媒体类型
List<MediaType> getSupportedMediaTypes();
// 转换HTTP报文为特定类型
T read(Class<? extends T> clazz, HttpInputMessage inputMessage)
throws IOException, HttpMessageNotReadableException;
// 将特定类型对象转换为HTTP报文
void write(T t, MediaType contentType, HttpOutputMessage outputMessage)
throws IOException, HttpMessageNotWritableException;
}
对应到SpringMVC的Controller方法,read方法即是读取HTTP请求转换为参数对象,write方法即是将返回值对象转换为HTTP响应报文。SpringMVC定义了两个接口来操作这两个过程:参数解析器HandlerMethodArgumentResolver和返回值处理器HandlerMethodReturnValueHandler。
// 参数解析器接口
public interface HandlerMethodArgumentResolver {
// 解析器是否支持方法参数
boolean supportsParameter(MethodParameter parameter);
// 解析HTTP报文中对应的方法参数
Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception;
}
// 返回值处理器接口
public interface HandlerMethodReturnValueHandler {
// 处理器是否支持返回值类型
boolean supportsReturnType(MethodParameter returnType);
// 将返回值解析为HTTP响应报文
void handleReturnValue(Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception;
}
参数解析器和返回值处理器在底层处理时,都是通过HttpMessageConverter进行转换。流程如下:
RequestResponseBodyMethodProcessor类实现了HandlerMethodArgumentResolver和HandlerMethodReturnValueHandler两个接口,@RequestBody和@ResponseBody这两个注解的解析均由该类来实现。
2、参数解析
在上文中我们介绍了getMethodArgumentValues方法实现了参数解析但并未深入解析,这里我们进行下源码分析
private Object[] getMethodArgumentValues(NativeWebRequest request, ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
MethodParameter[] parameters = getMethodParameters();
Object[] args = new Object[parameters.length];
// 遍历所有参数,逐个解析
for (int i = 0; i < parameters.length; i++) {
MethodParameter parameter = parameters[i];
parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);
args[i] = resolveProvidedArgument(parameter, providedArgs);
if (args[i] != null) {
continue;
}
// 通过supportsParameter方法寻找参数合适的解析器
if (this.argumentResolvers.supportsParameter(parameter)) {
try {
args[i] = this.argumentResolvers.resolveArgument(
parameter, mavContainer, request, this.dataBinderFactory);
continue;
}
catch (Exception ex) {
if (logger.isDebugEnabled()) {
logger.debug(getArgumentResolutionErrorMessage("Failed to resolve", i), ex);
}
throw ex;
}
}
if (args[i] == null) {
throw new IllegalStateException("Could not resolve method parameter at index " +
parameter.getParameterIndex() + " in " + parameter.getMethod().toGenericString() +
": " + getArgumentResolutionErrorMessage("No suitable resolver for", i));
}
}
return args;
}
2.1、查找解析器
HandlerMethodArgumentResolverComposite类实现了supportsParameter方法,后续调用argumentResolverCache即参数解析器
private final List<HandlerMethodArgumentResolver> argumentResolvers =
new LinkedList<HandlerMethodArgumentResolver>();
@Override
public boolean supportsParameter(MethodParameter parameter) {
return getArgumentResolver(parameter) != null;
}
private HandlerMethodArgumentResolver getArgumentResolver(MethodParameter parameter) {
HandlerMethodArgumentResolver result = this.argumentResolverCache.get(parameter);
if (result == null) {
for (HandlerMethodArgumentResolver resolver : this.argumentResolvers) {
if (resolver.supportsParameter(parameter)) {
result = resolver;
this.argumentResolverCache.put(parameter, result);
break;
}
}
}
return result;
}
我们直接进入HandlerMethodArgumentResolver接口的实现类,也正是我们上问提到的RequestResponseBodyMethodProcessor来看看
@Override
public boolean supportsParameter(MethodParameter parameter) {
return parameter.hasParameterAnnotation(RequestBody.class);
}
可以看到这里实际上就是判断方法上是否有@RequestBody,这就印证了我们所说的@RequestBody由RequestResponseBodyMethodProcessor来实现解析。
2.2、解析过程
已经通过supportsParameter确定了由RequestResponseBodyMethodProcessor类来进行解析,下面再看如何解析,于是我们跟着源码进入resolveArgument方法。
@Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
HandlerMethodArgumentResolver resolver = getArgumentResolver(parameter);
if (resolver == null) {
throw new IllegalArgumentException("Unsupported parameter type [" +
parameter.getParameterType().getName() + "]. supportsParameter should be called first.");
}
return resolver.resolveArgument(parameter, mavContainer, webRequest, binderFactory);
}
其核心内容为通过readWithMessageConverters读取HTTP的请求体内容,而该方法由AbstractMessageConverterMethodArgumentResolver负责实现。
// RequestResponseBodyMethodProcessor.java
@Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
parameter = parameter.nestedIfOptional();
// 读取HTTP报文
Object arg = readWithMessageConverters(webRequest, parameter, parameter.getNestedGenericParameterType());
String name = Conventions.getVariableNameForParameter(parameter);
WebDataBinder binder = binderFactory.createBinder(webRequest, arg, name);
if (arg != null) {
validateIfApplicable(binder, parameter);
if (binder.getBindingResult().hasErrors() && isBindExceptionRequired(binder, parameter)) {
throw new MethodArgumentNotValidException(parameter, binder.getBindingResult());
}
}
mavContainer.addAttribute(BindingResult.MODEL_KEY_PREFIX + name, binder.getBindingResult());
return adaptArgumentIfNecessary(arg, parameter);
}
@Override
protected <T> Object readWithMessageConverters(NativeWebRequest webRequest, MethodParameter parameter,
Type paramType) throws IOException, HttpMediaTypeNotSupportedException, HttpMessageNotReadableException {
HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class);
ServletServerHttpRequest inputMessage = new ServletServerHttpRequest(servletRequest);
//调用AbstractMessageConverterMethodArgumentResolver中的实现
Object arg = readWithMessageConverters(inputMessage, parameter, paramType);
if (arg == null) {
if (checkRequired(parameter)) {
throw new HttpMessageNotReadableException("Required request body is missing: " +
parameter.getMethod().toGenericString());
}
}
return arg;
}
这里的关键部分即是遍历所有的HttpMessageConverter,通过canRead方法判断转换器是否支持对参数的转换,然后执行read方法完成转换。
protected <T> Object readWithMessageConverters(HttpInputMessage inputMessage, MethodParameter parameter,
Type targetType) throws IOException, HttpMediaTypeNotSupportedException, HttpMessageNotReadableException {
....
try {
inputMessage = new EmptyBodyCheckingHttpInputMessage(inputMessage);
for (HttpMessageConverter<?> converter : this.messageConverters) {
Class<HttpMessageConverter<?>> converterType = (Class<HttpMessageConverter<?>>) converter.getClass();
....
// 判断转换器是否支持参数类型
if (converter.canRead(targetClass, contentType)) {
if (inputMessage.getBody() != null) {
inputMessage = getAdvice().beforeBodyRead(inputMessage, parameter, targetType, converterType);
// read方法执行HTTP报文到参数的转换
body = ((HttpMessageConverter<T>) converter).read(targetClass, inputMessage);
body = getAdvice().afterBodyRead(body, inputMessage, parameter, targetType, converterType);
}
else {
body = getAdvice().handleEmptyBody(null, inputMessage, parameter, targetType, converterType);
}
break;
}
...
}
}
catch (IOException ex) {
throw new HttpMessageNotReadableException("I/O error while reading input message", ex);
}
....
return body;
}
3、返回值处理
完成Controller方法的调用后,在ServletInvocableHandlerMethod的invokeAndHandle中,使用返回值处理器对返回值进行转换。
这里的returnValueHandlers也是HandlerMethodReturnValueHandler的集合体HandlerMethodReturnValueHandlerComposite
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);
}
3.1、选择处理器
handleReturnValue首先会通过selectHandler找出支持处理当前返回值的处理器,然后再调用该处理器的handleReturnValue方法进行真正的处理。
//HandlerMethodReturnValueHandlerComposite.java
@Override
public void handleReturnValue(Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
// 选择合适的HandlerMethodReturnValueHandler,如果没有用@ResposeBody注解和用了注解其返回值处理器肯定不同
HandlerMethodReturnValueHandler handler = selectHandler(returnValue, returnType);
if (handler == null) {
throw new IllegalArgumentException("Unknown return value type: " + returnType.getParameterType().getName());
}
// 执行返回值处理
handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);
}
而selectHandler方法遍历所有HandlerMethodReturnValueHandler,调用其supportsReturnType方法选择合适的HandlerMethodReturnValueHandler,然后调用其handleReturnValue方法完成处理。
//HandlerMethodReturnValueHandlerComposite.java
private HandlerMethodReturnValueHandler selectHandler(Object value, MethodParameter returnType) {
boolean isAsyncValue = isAsyncReturnValue(value, returnType);
for (HandlerMethodReturnValueHandler handler : this.returnValueHandlers) {
if (isAsyncValue && !(handler instanceof AsyncHandlerMethodReturnValueHandler)) {
continue;
}
// 判断当前的HandlerMethodReturnValueHandler是否支持处理返回值
if (handler.supportsReturnType(returnType)) {
return handler;
}
}
return null;
}
RequestResponseBodyMethodProcessor要求方法上有@ResponseBody注解或者方法所在的Controller类上有@ResponseBody的注解。这就是常常用@RestController注解代替@Controller注解的原因,因为@RestController注解自带@ResponseBody。
@Override
public boolean supportsReturnType(MethodParameter returnType) {
return (AnnotatedElementUtils.hasAnnotation(returnType.getContainingClass(), ResponseBody.class) ||
returnType.hasMethodAnnotation(ResponseBody.class));
}
3.2、处理过程
handleReturnValue方法实际也是调用HttpMessageConverter来完成转换处理。
//RequestResponseBodyMethodProcessor.java
@Override
public void handleReturnValue(Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest)
throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {
// 设置该请求的返回值直接通过response返回,无视图内容
mavContainer.setRequestHandled(true);
ServletServerHttpRequest inputMessage = createInputMessage(webRequest);
ServletServerHttpResponse outputMessage = createOutputMessage(webRequest);
// 调用HttpMessageConverter执行
writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage);
}
因为使用了@ResponseBody已经将返回值通过response的消息体进行了回传,因此这里不再需要视图了,所以设置了setRequestHandled(true)。
// ModelAndViewContainer.java
/**
* Whether the request has been handled fully within the handler, e.g.
* {@code @ResponseBody} method, and therefore view resolution is not
* necessary. This flag can also be set when controller methods declare an
* argument of type {@code ServletResponse} or {@code OutputStream}).
* <p>The default value is {@code false}.
*/
public void setRequestHandled(boolean requestHandled) {
this.requestHandled = requestHandled;
}
AbstractMessageConverterMethodProcessor使用canWrite方法选择合适的HttpMessageConverter,然后调用write方法完成转换。
//AbstractMessageConverterMethodProcessor.java
protected <T> void writeWithMessageConverters(T value, MethodParameter returnType,
ServletServerHttpRequest inputMessage, ServletServerHttpResponse outputMessage)
throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {
....
if (selectedMediaType != null) {
selectedMediaType = selectedMediaType.removeQualityValue();
for (HttpMessageConverter<?> messageConverter : this.messageConverters) {
// 判断是否支持返回值类型,返回值类型很有可能不同,如String,Map,List等
if (messageConverter.canWrite(valueType, selectedMediaType)) {
outputValue = (T) getAdvice().beforeBodyWrite(outputValue, returnType, selectedMediaType,
(Class<? extends HttpMessageConverter<?>>) messageConverter.getClass(),
inputMessage, outputMessage);
if (outputValue != null) {
addContentDispositionHeader(inputMessage, outputMessage);
// 执行返回值转换
((HttpMessageConverter) messageConverter).write(outputValue, selectedMediaType, outputMessage);
...
}
return;
}
}
}
....
}
补充
解析器和转换器在什么时候注册添加的
上文中提到的解析器和转换器都是在适配器初始化的时候添加的。
//RequestMappingHandlerAdapter.java
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());
}
@Override
public void afterPropertiesSet() {
// Do this first, it may add ResponseBody advice beans
initControllerAdviceCache();
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);
}
}