spring-webmvc-4.3.19.RELEASE

下面来看DispatcherServlet中的执行:

    /**
* Exposes the DispatcherServlet-specific request attributes and delegates to {@link #doDispatch}
* for the actual dispatching.
*/
@Override
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
if (logger.isDebugEnabled()) {
String resumed = WebAsyncUtils.getAsyncManager(request).hasConcurrentResult() ? " resumed" : "";
logger.debug("DispatcherServlet with name '" + getServletName() + "'" + resumed +
" processing " + request.getMethod() + " request for [" + getRequestUri(request) + "]");
} // Keep a snapshot of the request attributes in case of an include,
// to be able to restore the original attributes after the include.
Map<String, Object> attributesSnapshot = null;
if (WebUtils.isIncludeRequest(request)) {
attributesSnapshot = new HashMap<String, Object>();
Enumeration<?> attrNames = request.getAttributeNames();
while (attrNames.hasMoreElements()) {
String attrName = (String) attrNames.nextElement();
if (this.cleanupAfterInclude || attrName.startsWith(DEFAULT_STRATEGIES_PREFIX)) {
attributesSnapshot.put(attrName, request.getAttribute(attrName));
}
}
} // Make framework objects available to handlers and view objects.
request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());
request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource()); FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response);
if (inputFlashMap != null) {
request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap));
}
request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());
request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager); try {
doDispatch(request, response);
}
finally {
if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
// Restore the original attribute snapshot, in case of an include.
if (attributesSnapshot != null) {
restoreAttributesAfterInclude(request, attributesSnapshot);
}
}
}
}
org.springframework.web.servlet.DispatcherServlet#doService
    /**
* Process the actual dispatching to the handler.
* <p>The handler will be obtained by applying the servlet's HandlerMappings in order.
* The HandlerAdapter will be obtained by querying the servlet's installed HandlerAdapters
* to find the first that supports the handler class.
* <p>All HTTP methods are handled by this method. It's up to HandlerAdapters or handlers
* themselves to decide which methods are acceptable.
* @param request current HTTP request
* @param response current HTTP response
* @throws Exception in case of any kind of processing failure
*/
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 {
processedRequest = checkMultipart(request);//文件上传处理解析器
multipartRequestParsed = (processedRequest != request);//是否文件上传请求 // Determine handler for the current request. 获取匹配的HandlerExecutionChain
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null || mappedHandler.getHandler() == null) {
noHandlerFound(processedRequest, response);
return;
} // Determine handler adapter for the current request.
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler()); // Process last-modified header, if supported by the handler.
String method = request.getMethod();
boolean isGet = "GET".equals(method);
if (isGet || "HEAD".equals(method)) {
long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
if (logger.isDebugEnabled()) {
logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
}
if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
return;
}
}//todo:确认下这个代码块是不是为了处理etag? https://www.cnblogs.com/softidea/p/5986339.html
//执行拦截器的applyPreHandle,如果返回false,则流程直接结束
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
} // Actually invoke the handler. 执行处理器,返回mav
mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); if (asyncManager.isConcurrentHandlingStarted()) {
return;
} applyDefaultViewName(processedRequest, mv);//如果视图为空,给予设置默认视图的名称
mappedHandler.applyPostHandle(processedRequest, response, mv); //执行处理器拦截器的applyPostHandle
}
catch (Exception ex) {
dispatchException = ex;
}
catch (Throwable err) {
// As of 4.3, we're processing Errors thrown from handler methods as well,
// making them available for @ExceptionHandler methods and other scenarios.
dispatchException = new NestedServletException("Handler dispatch failed", err);
}
//处理请求结果。显然,此时请求已经结束【也是@ControlAdvice生效的地方】
//如果是逻辑视图【MVC场景有指定的模板需要渲染或页面需要跳转】,则解析名称;否则,就不解析
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);//
}
catch (Exception ex) {
triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
}
catch (Throwable err) {
triggerAfterCompletion(processedRequest, response, mappedHandler,
new NestedServletException("Handler processing failed", err));
}
finally {
//释放资源
if (asyncManager.isConcurrentHandlingStarted()) {
// Instead of postHandle and afterCompletion
if (mappedHandler != null) {
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);//执行拦截器的方法
}
}
else {
// Clean up any resources used by a multipart request. 文件请求资源释放
if (multipartRequestParsed) {
cleanupMultipart(processedRequest);
}
}
}
} org.springframework.web.servlet.DispatcherServlet#doDispatch

首先看下doDispatch()方法如何找到适合的适配器来执行方法的:

    /**
* Return the HandlerAdapter for this handler object.
* @param handler the handler object to find an adapter for
* @throws ServletException if no HandlerAdapter can be found for the handler. This is a fatal error.
*/
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
for (HandlerAdapter ha : this.handlerAdapters) {
if (logger.isTraceEnabled()) {
logger.trace("Testing handler adapter [" + ha + "]");
}
if (ha.supports(handler)) {
return ha;
}
}
throw new ServletException("No adapter for handler [" + handler +
"]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
}

org.springframework.web.servlet.DispatcherServlet#getHandlerAdapter

0 = {RequestMappingHandlerAdapter@11772} 
1 = {HttpRequestHandlerAdapter@11773} 
2 = {SimpleControllerHandlerAdapter@11774}

【0】 RequestMappingHandlerAdapter 【org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter】:

/**
* Provides a method for invoking the handler method for a given request after resolving its
* method argument values through registered {@link HandlerMethodArgumentResolver}s.
*
* <p>Argument resolution often requires a {@link WebDataBinder} for data binding or for type
* conversion. Use the {@link #setDataBinderFactory(WebDataBinderFactory)} property to supply
* a binder factory to pass to argument resolvers.
*
* <p>Use {@link #setHandlerMethodArgumentResolvers} to customize the list of argument resolvers.
*
* @author Rossen Stoyanchev
* @author Juergen Hoeller
* @since 3.1
*/
public class InvocableHandlerMethod extends HandlerMethod {
/**
* An {@link AbstractHandlerMethodAdapter} that supports {@link HandlerMethod}s
* with their method argument and return type signature, as defined via
* {@code @RequestMapping}.
*
* <p>Support for custom argument and return value types can be added via
* {@link #setCustomArgumentResolvers} and {@link #setCustomReturnValueHandlers}.
* Or alternatively, to re-configure all argument and return value types,
* use {@link #setArgumentResolvers} and {@link #setReturnValueHandlers}.
*
* @author Rossen Stoyanchev
* @author Juergen Hoeller
* @since 3.1
* @see HandlerMethodArgumentResolver
* @see HandlerMethodReturnValueHandler
*/
public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter
implements BeanFactoryAware, InitializingBean { 【org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter#supports】
/**
* This implementation expects the handler to be an {@link HandlerMethod}.
* @param handler the handler instance to check
* @return whether or not this adapter can adapt the given handler
*/
@Override
public final boolean supports(Object handler) {
return (handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler));
}
/**
* Extends {@link InvocableHandlerMethod} with the ability to handle return
* values through a registered {@link HandlerMethodReturnValueHandler} and
* also supports setting the response status based on a method-level
* {@code @ResponseStatus} annotation.
*
* <p>A {@code null} return value (including void) may be interpreted as the
* end of request processing in combination with a {@code @ResponseStatus}
* annotation, a not-modified check condition
* (see {@link ServletWebRequest#checkNotModified(long)}), or
* a method argument that provides access to the response stream.
*
* @author Rossen Stoyanchev
* @author Juergen Hoeller
* @since 3.1
*/
public class ServletInvocableHandlerMethod extends InvocableHandlerMethod { private static final Method CALLABLE_METHOD = ClassUtils.getMethod(Callable.class, "call");

((ApplicationContextFacade) ((ServletContextResource) resource).getServletContext()).context.getContext().getDocBase():
docBase : C:\Users\TANGCH~1\AppData\Local\Temp\tomcat-docbase.8903617127552296966.8080
C:\Users\TANGCH~1\AppData\Local\Temp\tomcat-docbase.8903617127552296966.8080

/**
* Records model and view related decisions made by
* {@link HandlerMethodArgumentResolver}s and
* {@link HandlerMethodReturnValueHandler}s during the course of invocation of
* a controller method.
*
* <p>The {@link #setRequestHandled} flag can be used to indicate the request
* has been handled directly and view resolution is not required.
*
* <p>A default {@link Model} is automatically created at instantiation.
* An alternate model instance may be provided via {@link #setRedirectModel}
* for use in a redirect scenario. When {@link #setRedirectModelScenario} is set
* to {@code true} signalling a redirect scenario, the {@link #getModel()}
* returns the redirect model instead of the default model.
*
* @author Rossen Stoyanchev
* @author Juergen Hoeller
* @since 3.1
*/
public class ModelAndViewContainer {

【1】 HttpRequestHandlerAdapter 【org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter】

/**
* Adapter to use the plain {@link org.springframework.web.HttpRequestHandler}
* interface with the generic {@link org.springframework.web.servlet.DispatcherServlet}.
* Supports handlers that implement the {@link LastModified} interface.
*
* <p>This is an SPI class, not used directly by application code.
*
* @author Juergen Hoeller
* @since 2.0
* @see org.springframework.web.servlet.DispatcherServlet
* @see org.springframework.web.HttpRequestHandler
* @see LastModified
* @see SimpleControllerHandlerAdapter
*/
public class HttpRequestHandlerAdapter implements HandlerAdapter { @Override
public boolean supports(Object handler) {
return (handler instanceof HttpRequestHandler);
}

注: 这块也有点责任链模式的意思...

下面看下RequestMappingHandlerAdapter是怎么实现support方法的,看之前先上类图。

实际上support方法是在AbstractHandlerMethodAdapter这个父类实现的,然后给自己留个钩子方法,让子类实现

    /**
* This implementation expects the handler to be an {@link HandlerMethod}.
* @param handler the handler instance to check
* @return whether or not this adapter can adapt the given handler
*/
@Override
public final boolean supports(Object handler) {
return (handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler));//延迟做决定,由子类来决定相关的逻辑
}
org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter#supports
【org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter】
    /**
* Always return {@code true} since any method argument and return value
* type will be processed in some way. A method argument not recognized
* by any HandlerMethodArgumentResolver is interpreted as a request parameter
* if it is a simple type, or as a model attribute otherwise. A return value
* not recognized by any HandlerMethodReturnValueHandler will be interpreted
* as a model attribute.
*/
@Override
protected boolean supportsInternal(HandlerMethod handlerMethod) {
return true;
}
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter#supportsInternal

这里RequestMappingHandlerAdapter的supportInternal直接是返回的true,估计后续扩展其他子类可能会复杂些,这就是设计模式的好处。

这样就找到了合适的适配器。

拦截器这里就不在多说,这块就是返回false就不在往下执行。下面我们重点满ha.handle()方法,是如果映射参数,找到我们的方法,封装结果的。

类图前面已经展示了,实际上handle是在父类AbstractHandlerMethodAdapter实现的

public final ModelAndView handle(HttpServletRequest request, 
HttpServletResponse response,
Object handler) throws Exception {
return this.handleInternal(request, response, (HandlerMethod)handler); //子类实现这个方法
} protected abstract ModelAndView handleInternal(HttpServletRequest var1,
HttpServletResponse var2,
HandlerMethod var3) throws Exception;
protected final ModelAndView handleInternal(HttpServletRequest request, 
HttpServletResponse response,
HandlerMethod handlerMethod) throws Exception {
if (this.getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
this.checkAndPrepare(request, response, this.cacheSecondsForSessionAttributeHandlers, true);
} else {
this.checkAndPrepare(request, response, true);
} //看代码应该是从session中获取一些信息,然后初始化header等信息,不知道准确不?请大家指正!
//这块就是根据需要是否进行同步操作
if (this.synchronizeOnSession) {
HttpSession session = request.getSession(false);
if (session != null) {
Object mutex = WebUtils.getSessionMutex(session);
synchronized(mutex) {
return this.invokeHandleMethod(request, response, handlerMethod);
}
}
}
//正式进入执行环节
return this.invokeHandleMethod(request, response, handlerMethod);
}

下面这个方法非常重要,将重点讲解:

private ModelAndView invokeHandleMethod(HttpServletRequest request, 
HttpServletResponse response,
HandlerMethod handlerMethod) throws Exception {
ServletWebRequest webRequest = new ServletWebRequest(request, response);
WebDataBinderFactory binderFactory = this.getDataBinderFactory(handlerMethod); //创建@InitBinder注解的方法的工厂类,进行缓存
ModelFactory modelFactory = this.getModelFactory(handlerMethod, binderFactory);//创建@ModelAttribute@ControllerAdvice注解方法工厂并缓存
ServletInvocableHandlerMethod requestMappingMethod = this.createRequestMappingMethod(handlerMethod, binderFactory);
ModelAndViewContainer mavContainer = new ModelAndViewContainer(); //创建结果容器并初始化一些参数,
mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
modelFactory.initModel(webRequest, mavContainer, requestMappingMethod);//执行@ModelAttribute注解的方法,将结果放到结果容器中
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 (this.logger.isDebugEnabled()) {
this.logger.debug("Found concurrent result value [" + result + "]");
} requestMappingMethod = requestMappingMethod.wrapConcurrentResult(result);
} requestMappingMethod.invokeAndHandle(webRequest, mavContainer, new Object[0]); //继续执行方法
return asyncManager.isConcurrentHandlingStarted() ? null : this.getModelAndView(mavContainer, modelFactory, webRequest); //返回值了,两种情况
}
public final 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.hasResponseStatus() || mavContainer.isRequestHandled()) {
mavContainer.setRequestHandled(true);
return;
}
} else if (StringUtils.hasText(this.responseReason)) {
mavContainer.setRequestHandled(true);
return;
} mavContainer.setRequestHandled(false); try { //处理返回值 ,封装结果集
this.returnValueHandlers.handleReturnValue(returnValue, this.getReturnValueType(returnValue), mavContainer, webRequest);
} catch (Exception var6) {
if (this.logger.isTraceEnabled()) {
this.logger.trace(this.getReturnValueHandlingErrorMessage("Error handling return value", returnValue), var6);
} throw var6;
}
}
public final Object invokeForRequest(NativeWebRequest request, ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
Object[] args = this.getMethodArgumentValues(request, mavContainer, providedArgs); //处理 参数
if (this.logger.isTraceEnabled()) {
StringBuilder builder = new StringBuilder("Invoking [");
builder.append(this.getMethod().getName()).append("] method with arguments ");
builder.append(Arrays.asList(args));
this.logger.trace(builder.toString());
} Object returnValue = this.invoke(args); //反射执行方法
if (this.logger.isTraceEnabled()) {
this.logger.trace("Method [" + this.getMethod().getName() + "] returned [" + returnValue + "]");
} return returnValue;
}
private Object[] getMethodArgumentValues(NativeWebRequest request, ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
MethodParameter[] parameters = this.getMethodParameters();
Object[] args = new Object[parameters.length]; for(int i = 0; i < parameters.length; ++i) { //遍历方法的所有参数
MethodParameter parameter = parameters[i];
parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);
GenericTypeResolver.resolveParameterType(parameter, this.getBean().getClass()); //获取设置参数类型
args[i] = this.resolveProvidedArgument(parameter, providedArgs);
if (args[i] == null) {
if (this.argumentResolvers.supportsParameter(parameter)) { //这块是遍历预置的参数解析器,就是前面说的责任链模式,**composite负责查找和执行
try { //由找到的参数解析器,来解析参数
args[i] = this.argumentResolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory);
} catch (Exception var9) {
if (this.logger.isTraceEnabled()) {
this.logger.trace(this.getArgumentResolutionErrorMessage("Error resolving argument", i), var9);
} throw var9;
}
} else if (args[i] == null) {
String msg = this.getArgumentResolutionErrorMessage("No suitable resolver for argument", i);
throw new IllegalStateException(msg);
}
}
} return args;
}

这块没有任何注解,参数为javaBean的解析器为例:ModelAttributeMethodProcessor

public boolean supportsParameter(MethodParameter parameter) {
if (parameter.hasParameterAnnotation(ModelAttribute.class)) {
return true;
} else if (this.annotationNotRequired) {
return !BeanUtils.isSimpleProperty(parameter.getParameterType());
} else {
return false;
}
} public final Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest request, WebDataBinderFactory binderFactory) throws Exception {
String name = ModelFactory.getNameForParameter(parameter); //如果当前参数用@ModelAttribute修饰了,返回value值或者参数类型第一个字母小写
// 获取需要绑定的表单对象,看参数容器包含name为key的对象不,有的话就用它,没有创建个新的。
      Object attribute = mavContainer.containsAttribute(name) ? mavContainer.getModel().get(name) : this.createAttribute(name, parameter, binderFactory, request);
WebDataBinder binder = binderFactory.createBinder(request, attribute, name);
if (binder.getTarget() != null) {
this.bindRequestParameters(binder, request);
this.validateIfApplicable(binder, parameter);
if (binder.getBindingResult().hasErrors() && this.isBindExceptionRequired(binder, parameter)) {
throw new BindException(binder.getBindingResult());
}
}
     //以上就是参数绑定, 这块领开一篇文章详细说
Map<String, Object> bindingResultModel = binder.getBindingResult().getModel();
mavContainer.removeAttributes(bindingResultModel);
mavContainer.addAllAttributes(bindingResultModel);
return binder.getTarget();
}

参数就这样遍历处理,然后就开始通过反射 invoke执行了。接下来我们看是怎么封装换回结果的

try {
this.returnValueHandlers.handleReturnValue(returnValue, this.getReturnValueType(returnValue), mavContainer, webRequest);
} catch (Exception var6) {
if (this.logger.isTraceEnabled()) {
this.logger.trace(this.getReturnValueHandlingErrorMessage("Error handling return value", returnValue), var6);
} throw var6;
}

this.returnValuehandlers. 就是那个返回结果的包装类,初始化的结果解析器就保存这里,处理思路和参数解析器一样的,

public void handleReturnValue(Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
HandlerMethodReturnValueHandler handler = this.getReturnValueHandler(returnType);
Assert.notNull(handler, "Unknown return value type [" + returnType.getParameterType().getName() + "]");
handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);
} private HandlerMethodReturnValueHandler getReturnValueHandler(MethodParameter returnType) {
Iterator i$ = this.returnValueHandlers.iterator(); HandlerMethodReturnValueHandler returnValueHandler;
do {
if (!i$.hasNext()) {
return null;
} returnValueHandler = (HandlerMethodReturnValueHandler)i$.next();
if (this.logger.isTraceEnabled()) {
this.logger.trace("Testing if return value handler [" + returnValueHandler + "] supports [" + returnType.getGenericParameterType() + "]");
}
} while(!returnValueHandler.supportsReturnType(returnType)); return returnValueHandler;
}

遍历预置的所有结果解析器,结果解析器统一实现HandlerMethodReturnValueHandler 接口,实现supportReturnType方法:

这里我们距离用@ResponseBody注解的结果解析器RequestResponseBodyMethodProcessor 前面说了,参数和结果集他都实现了

    /**
* Whether the given {@linkplain MethodParameter method parameter} is
* supported by this resolver.
* @param parameter the method parameter to check
* @return {@code true} if this resolver supports the supplied parameter;
* {@code false} otherwise
org.springframework.web.method.support.HandlerMethodArgumentResolver#supportsParameter
*/
@Override
public boolean supportsParameter(MethodParameter parameter) {
return parameter.hasParameterAnnotation(RequestBody.class);
}
org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor#supportsParameter /**
* Whether the given {@linkplain MethodParameter method return type} is
* supported by this handler.
* @param returnType the method return type to check
* @return {@code true} if this handler supports the supplied return type;
* {@code false} otherwise
org.springframework.web.method.support.HandlerMethodReturnValueHandler#supportsReturnType
*/ @Override
public boolean supportsReturnType(MethodParameter returnType) {
return (AnnotatedElementUtils.hasAnnotation(returnType.getContainingClass(), ResponseBody.class) ||
returnType.hasMethodAnnotation(ResponseBody.class));
}
org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor#supportsReturnType
    /**
* Handle the given return value by adding attributes to the model and
* setting a view or setting the
* {@link ModelAndViewContainer#setRequestHandled} flag to {@code true}
* to indicate the response has been handled directly.
* @param returnValue the value returned from the handler method
* @param returnType the type of the return value. This type must have
* previously been passed to {@link #supportsReturnType} which must
* have returned {@code true}.
* @param mavContainer the ModelAndViewContainer for the current request
* @param webRequest the current request
* @throws Exception if the return value handling results in an error
org.springframework.web.method.support.HandlerMethodReturnValueHandler#handleReturnValue
*/ @Override
public void handleReturnValue(Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest)
throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException { mavContainer.setRequestHandled(true);
ServletServerHttpRequest inputMessage = createInputMessage(webRequest);
ServletServerHttpResponse outputMessage = createOutputMessage(webRequest); // Try even with null return value. ResponseBodyAdvice could get involved.
writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage);//用内置的消息转换器来转换结果集
}
org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor#handleReturnValue

下面来看是怎么寻找可以合适的消息转换器的

    /**
* Writes the given return type to the given output message.
* @param value the value to write to the output message
* @param returnType the type of the value
* @param inputMessage the input messages. Used to inspect the {@code Accept} header.
* @param outputMessage the output message to write to
* @throws IOException thrown in case of I/O errors
* @throws HttpMediaTypeNotAcceptableException thrown when the conditions indicated
* by the {@code Accept} header on the request cannot be met by the message converters
*/
@SuppressWarnings("unchecked")
protected <T> void writeWithMessageConverters(T value, MethodParameter returnType,
ServletServerHttpRequest inputMessage, ServletServerHttpResponse outputMessage)
throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException { Object outputValue;
Class<?> valueType;
Type declaredType; if (value instanceof CharSequence) {
outputValue = value.toString();
valueType = String.class;
declaredType = String.class;
}
else {
outputValue = value;
valueType = getReturnValueType(outputValue, returnType);
declaredType = getGenericType(returnType);
} HttpServletRequest request = inputMessage.getServletRequest();
List<MediaType> requestedMediaTypes = getAcceptableMediaTypes(request);//获取请求的MediaType,eg:"application/json"
List<MediaType> producibleMediaTypes = getProducibleMediaTypes(request, valueType, declaredType);//寻找支持这个返回类型的转换器支持的MediaType if (outputValue != null && producibleMediaTypes.isEmpty()) {
throw new IllegalArgumentException("No converter found for return value of type: " + valueType);
}
//双循环两个list,进行匹配,把复核条件的MediaType放到compatibleMediaTypes中 //TODO有些不懂得是为啥这块要过滤一遍,  后面实现了 父类也做了判断每个字类是否支持MediaType了??
Set<MediaType> compatibleMediaTypes = new LinkedHashSet<MediaType>();
for (MediaType requestedType : requestedMediaTypes) {
for (MediaType producibleType : producibleMediaTypes) {
if (requestedType.isCompatibleWith(producibleType)) {
compatibleMediaTypes.add(getMostSpecificMediaType(requestedType, producibleType));
}
}
}
if (compatibleMediaTypes.isEmpty()) {
if (outputValue != null) {
throw new HttpMediaTypeNotAcceptableException(producibleMediaTypes);
}
return;
} List<MediaType> mediaTypes = new ArrayList<MediaType>(compatibleMediaTypes);
MediaType.sortBySpecificityAndQuality(mediaTypes); MediaType selectedMediaType = null;
for (MediaType mediaType : mediaTypes) {
if (mediaType.isConcrete()) {
selectedMediaType = mediaType;
break;
}
else if (mediaType.equals(MediaType.ALL) || mediaType.equals(MEDIA_TYPE_APPLICATION)) {
selectedMediaType = MediaType.APPLICATION_OCTET_STREAM;
break;
}
} if (selectedMediaType != null) {
selectedMediaType = selectedMediaType.removeQualityValue();
for (HttpMessageConverter<?> messageConverter : this.messageConverters) {

//遍历所有消息转换器,canWrite是接口方法,相当于前面的support等,模式都是一个。然后满足的进行write。输出结果。

if (messageConverter instanceof GenericHttpMessageConverter) {
if (((GenericHttpMessageConverter) messageConverter).canWrite(
declaredType, valueType, selectedMediaType)) {
outputValue = (T) getAdvice().beforeBodyWrite(outputValue, returnType, selectedMediaType,
(Class<? extends HttpMessageConverter<?>>) messageConverter.getClass(),
inputMessage, outputMessage);
if (outputValue != null) {
addContentDispositionHeader(inputMessage, outputMessage);
((GenericHttpMessageConverter) messageConverter).write(
outputValue, declaredType, selectedMediaType, outputMessage);
if (logger.isDebugEnabled()) {
logger.debug("Written [" + outputValue + "] as \"" + selectedMediaType +
"\" using [" + messageConverter + "]");
}
}
return;
}
}
else 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);
if (logger.isDebugEnabled()) {
logger.debug("Written [" + outputValue + "] as \"" + selectedMediaType +
"\" using [" + messageConverter + "]");
}
}
return;
}
}
} if (outputValue != null) {
throw new HttpMediaTypeNotAcceptableException(this.allSupportedMediaTypes);
}
}
org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodProcessor#writeWithMessageConverters(T, org.springframework.core.MethodParameter, org.springframework.http.server.ServletServerHttpRequest, org.springframework.http.server.ServletServerHttpResponse)

这里可能有人会问,消息转换器什么时候加载的?
是在RequestMappingHandlerAdapter这个bean实例化的时候加载的,同时加载参数和结果解析器时候注入到解析器当中的

public RequestMappingHandlerAdapter() { //无参构造函数中初始化
StringHttpMessageConverter stringHttpMessageConverter = new StringHttpMessageConverter();
stringHttpMessageConverter.setWriteAcceptCharset(false);
this.messageConverters = new ArrayList();
this.messageConverters.add(new ByteArrayHttpMessageConverter());
this.messageConverters.add(stringHttpMessageConverter);
this.messageConverters.add(new SourceHttpMessageConverter());
this.messageConverters.add(new AllEncompassingFormHttpMessageConverter());
}
private List<HandlerMethodReturnValueHandler> getDefaultReturnValueHandlers() { //构造参数解析器时候,注入进去
List<HandlerMethodReturnValueHandler> handlers = new ArrayList();
handlers.add(new ModelAndViewMethodReturnValueHandler());
handlers.add(new ModelMethodProcessor());
handlers.add(new ViewMethodReturnValueHandler());
handlers.add(new HttpEntityMethodProcessor(this.getMessageConverters(), this.contentNegotiationManager));
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));
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;
}

下面介绍下,@ResponseBode标签用的消息转换器是MappingJacksonHttpMessageConverter;先看下类图吧

MappingJacksonHttpMessageConverter重写了父类的write方法:

 public boolean canWrite(Class<?> clazz, MediaType mediaType) {
return this.objectMapper.canSerialize(clazz) && this.canWrite(mediaType); //canWrite(mediaType)是父类实现的
}
    protected boolean canWrite(MediaType mediaType) {
if (mediaType == null || MediaType.ALL.equals(mediaType)) {
return true;
}
for (MediaType supportedMediaType : getSupportedMediaTypes()) {//获取子类解析器支持的MediaType,看下是否支持
if (supportedMediaType.isCompatibleWith(mediaType)) {
return true;
}
}
return false;
}
org.springframework.http.converter.AbstractHttpMessageConverter#canWrite(org.springframework.http.MediaType)

write方法 父类也帮着实现了,父类具体做了如输出,拼输出流头等信息

public final void write(T t, MediaType contentType, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException {
HttpHeaders headers = outputMessage.getHeaders();
if (headers.getContentType() == null) {
if (contentType == null || contentType.isWildcardType() || contentType.isWildcardSubtype()) {
contentType = this.getDefaultContentType(t);
} if (contentType != null) {
headers.setContentType(contentType);
}
} if (headers.getContentLength() == -1L) {
Long contentLength = this.getContentLength(t, headers.getContentType());
if (contentLength != null) {
headers.setContentLength(contentLength);
}
} this.writeInternal(t, outputMessage); //钩子方法,让子类去实现
outputMessage.getBody().flush();
}
protected void writeInternal(Object object, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException {
JsonEncoding encoding = this.getJsonEncoding(outputMessage.getHeaders().getContentType());
JsonGenerator jsonGenerator = this.objectMapper.getJsonFactory().createJsonGenerator(outputMessage.getBody(), encoding);
if (this.objectMapper.getSerializationConfig().isEnabled(Feature.INDENT_OUTPUT)) {
jsonGenerator.useDefaultPrettyPrinter();
}
//这块就是默认用Jackson进行翻译结果集了
try {
if (this.prefixJson) {
jsonGenerator.writeRaw("{} && ");
} this.objectMapper.writeValue(jsonGenerator, object);
} catch (JsonProcessingException var6) {
throw new HttpMessageNotWritableException("Could not write JSON: " + var6.getMessage(), var6);
}
}

因为用@ResponseBody不需要返回视图,所以视图那块就返回Null,不需要渲染视图了

https://www.cnblogs.com/haoerlv/p/8692988.html

https://www.cnblogs.com/softidea/p/10120976.html

Spring MVC之源码速读之RequestMappingHandlerAdapter的更多相关文章

  1. spring-cloud-square源码速读(spring-cloud-square-okhttp篇)

    欢迎访问我的GitHub https://github.com/zq2599/blog_demos 内容:所有原创文章分类汇总及配套源码,涉及Java.Docker.Kubernetes.DevOPS ...

  2. spring-cloud-square源码速读(retrofit + okhttp篇)

    欢迎访问我的GitHub 这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos spring-cloud-square系列文章 五分钟 ...

  3. Spring mvc之源码 handlerMapping和handlerAdapter分析

    Spring mvc之源码 handlerMapping和handlerAdapter分析 本篇并不是具体分析Spring mvc,所以好多细节都是一笔带过,主要是带大家梳理一下整个Spring mv ...

  4. 源码速读及点睛:HashMap

    Java 8 HashMap的分离链表 从Java 2到Java 1.7,HashMap在分离链表上的改变并不多,他们的算法基本上是相同的.如果我们假设对象的Hash值服从平均分布,那么获取一个对象需 ...

  5. Spring IOC 容器源码分析 - 循环依赖的解决办法

    1. 简介 本文,我们来看一下 Spring 是如何解决循环依赖问题的.在本篇文章中,我会首先向大家介绍一下什么是循环依赖.然后,进入源码分析阶段.为了更好的说明 Spring 解决循环依赖的办法,我 ...

  6. Spring IOC 容器源码分析 - 创建原始 bean 对象

    1. 简介 本篇文章是上一篇文章(创建单例 bean 的过程)的延续.在上一篇文章中,我们从战略层面上领略了doCreateBean方法的全过程.本篇文章,我们就从战术的层面上,详细分析doCreat ...

  7. Spring IOC 容器源码分析 - 获取单例 bean

    1. 简介 为了写 Spring IOC 容器源码分析系列的文章,我特地写了一篇 Spring IOC 容器的导读文章.在导读一文中,我介绍了 Spring 的一些特性以及阅读 Spring 源码的一 ...

  8. Spring IOC 容器源码分析系列文章导读

    1. 简介 Spring 是一个轻量级的企业级应用开发框架,于 2004 年由 Rod Johnson 发布了 1.0 版本.经过十几年的迭代,现在的 Spring 框架已经非常成熟了.Spring ...

  9. Spring IOC 容器源码分析

    声明!非原创,本文出处 Spring 最重要的概念是 IOC 和 AOP,本篇文章其实就是要带领大家来分析下 Spring 的 IOC 容器.既然大家平时都要用到 Spring,怎么可以不好好了解 S ...

随机推荐

  1. SQL语句小tips(持续更新)

    统计非法数据 判断people_id是否是32为字母组成的,统计不满足要求的数据 SELECT COUNT(IF(BINARY people_id NOT REGEXP '^[0-9a-z]{32}' ...

  2. ftp服务器问题

    最近ftp服务器迁移,遇到了521问题,可以尝试以下几种方法:    1,服务器管理器->Web服务器->FTP服务器安装完:    2,检查相应文件夹的权限是否足够,    3,检查ft ...

  3. dorado7-HelloWorld

    1.首先在Tomat中将 Auto reloding enable去掉,去掉的目的不用每次更改代码,都要重新部署 2.创建dorado视图文件 2.1 视图文件的格式为xml 2.2 在view中添加 ...

  4. Ocelot中文文档入门

    入门 Ocelot仅适用于.NET Core,目前是根据netstandard2.0构建的,如果Ocelot适合您,这个文档可能会有用. .NET Core 2.1 安装NuGet包 使用nuget安 ...

  5. Linear and Quadratic Programming Solver ( Arithmetic and Algebra) CGAL 4.13 -User Manual

    1 Which Programs can be Solved? This package lets you solve convex quadratic programs of the general ...

  6. Docker容器的原理与实践(上)

    本文来自网易云社区. 虚拟化 是一种资源管理技术,将计算机的各种资源予以抽象.转换后呈现出来, 打破实体结构间的不可切割的障碍,使用户可以比原本更好的方式来应用这些资源. Hypervisor 一种运 ...

  7. bzoj2095: [Poi2010]Bridges(二分+混合图求欧拉回路)

    传送门 这篇题解讲的真吼->这里 首先我们可以二分一个答案,然后把所有权值小于这个答案的都加入图中 那么问题就转化为一张混合图(既有有向边又有无向边)中是否存在欧拉回路 首先 无向图存在欧拉回路 ...

  8. Mac 切换到行首和行末的方法

    苹果笔记本没有home键和end键 但是使用 command + 方向键左键可以回到行首, command + 方向键右键可以去到行末

  9. rawt

    这里写自定义目录标题 欢迎使用Markdown编辑器 新的改变 功能快捷键 合理的创建标题,有助于目录的生成 如何改变文本的样式 插入链接与图片 如何插入一段漂亮的代码片 生成一个适合你的列表 创建一 ...

  10. C++中vector的使用

    在c++中,vector是一个十分有用的容器. 作用:它能够像容器一样存放各种类型的对象,简单地说,vector是一个能够存放任意类型的动态数组,能够增加和压缩数据. vector在C++标准模板库中 ...