1.1 前言

  • RequestMappingHandlerAdapterHanlderAdapter 中最复杂的也是最常用的处理适配器,他的作用是根据HanlderMapping找到的Handler调用我们Controller 里的方法

  • 既然是调用方法我们推测它的工作应该主要设及3步:

    • 1、方法参数绑定
    • 2、方法执行
    • 3、返回结果处理
  • 方法执行的流程已经在代码里写好了,重点是参数绑定及结果处理,各个方法参数类型不同个数不同,想想就复杂,下面来看人家是怎么做的

2.1 RequestMappingHandlerAdapter初始化解析

  • 查看RequestMappingHandlerAdapter的继承关系

RequestMappingHandlerAdapter.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
/**
* 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 {

private List<HandlerMethodArgumentResolver> customArgumentResolvers;

// 用于给处理器方法和注释了@ModelAttribute的方法设置参数
private HandlerMethodArgumentResolverComposite argumentResolvers;

// 用于添加了@initBinder的方法设置参数
private HandlerMethodArgumentResolverComposite initBinderArgumentResolvers;

private List<HandlerMethodReturnValueHandler> customReturnValueHandlers;

// 用于将处理器的返回值处理为ModelAndView类型
private HandlerMethodReturnValueHandlerComposite returnValueHandlers;

private List<ModelAndViewResolver> modelAndViewResolvers;

private ContentNegotiationManager contentNegotiationManager = new ContentNegotiationManager();

private List<HttpMessageConverter<?>> messageConverters;

private List<Object> requestResponseBodyAdvice = new ArrayList<Object>();

private WebBindingInitializer webBindingInitializer;

private AsyncTaskExecutor taskExecutor = new SimpleAsyncTaskExecutor("MvcAsync");

private Long asyncRequestTimeout;

private CallableProcessingInterceptor[] callableInterceptors = new CallableProcessingInterceptor[0];

private DeferredResultProcessingInterceptor[] deferredResultInterceptors = new DeferredResultProcessingInterceptor[0];

private boolean ignoreDefaultModelOnRedirect = false;

private int cacheSecondsForSessionAttributeHandlers = 0;

private boolean synchronizeOnSession = false;

private SessionAttributeStore sessionAttributeStore = new DefaultSessionAttributeStore();

private ParameterNameDiscoverer parameterNameDiscoverer = new DefaultParameterNameDiscoverer();

private ConfigurableBeanFactory beanFactory;


private final Map<Class<?>, SessionAttributesHandler> sessionAttributesHandlerCache =
new ConcurrentHashMap<Class<?>, SessionAttributesHandler>(64);

private final Map<Class<?>, Set<Method>> initBinderCache = new ConcurrentHashMap<Class<?>, Set<Method>>(64);

private final Map<ControllerAdviceBean, Set<Method>> initBinderAdviceCache =
new LinkedHashMap<ControllerAdviceBean, Set<Method>>();

private final Map<Class<?>, Set<Method>> modelAttributeCache = new ConcurrentHashMap<Class<?>, Set<Method>>(64);

private final Map<ControllerAdviceBean, Set<Method>> modelAttributeAdviceCache =
new LinkedHashMap<ControllerAdviceBean, Set<Method>>();


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());
}
  • 可以看到实现了InitializingBean接口,这个方法注册了this.argumentResolvers this.initBinderArgumentResolvers this.returnValueHandlers
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@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);
}
}
  • 例如getDefaultArgumentResolvers方法,可以看到是直接写死了有那些默认的参数解析组件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
/**
* Return the list of argument resolvers to use including built-in resolvers
* and custom resolvers provided via {@link #setCustomArgumentResolvers}.
*/
private List<HandlerMethodArgumentResolver> getDefaultArgumentResolvers() {
List<HandlerMethodArgumentResolver> resolvers = new ArrayList<HandlerMethodArgumentResolver>();

// Annotation-based argument resolution
resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), false));
resolvers.add(new RequestParamMapMethodArgumentResolver());
resolvers.add(new org.springframework.web.servlet.mvc.method.annotation.PathVariableMethodArgumentResolver());
resolvers.add(new org.springframework.web.servlet.mvc.method.annotation.PathVariableMapMethodArgumentResolver());
resolvers.add(new org.springframework.web.servlet.mvc.method.annotation.MatrixVariableMethodArgumentResolver());
resolvers.add(new org.springframework.web.servlet.mvc.method.annotation.MatrixVariableMapMethodArgumentResolver());
resolvers.add(new org.springframework.web.servlet.mvc.method.annotation.ServletModelAttributeMethodProcessor(false));
resolvers.add(new org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor(getMessageConverters(), this.requestResponseBodyAdvice));
resolvers.add(new org.springframework.web.servlet.mvc.method.annotation.RequestPartMethodArgumentResolver(getMessageConverters(), this.requestResponseBodyAdvice));
resolvers.add(new RequestHeaderMethodArgumentResolver(getBeanFactory()));
resolvers.add(new RequestHeaderMapMethodArgumentResolver());
resolvers.add(new org.springframework.web.servlet.mvc.method.annotation.ServletCookieValueMethodArgumentResolver(getBeanFactory()));
resolvers.add(new ExpressionValueMethodArgumentResolver(getBeanFactory()));
resolvers.add(new org.springframework.web.servlet.mvc.method.annotation.SessionAttributeMethodArgumentResolver());
resolvers.add(new org.springframework.web.servlet.mvc.method.annotation.RequestAttributeMethodArgumentResolver());

// Type-based argument resolution
resolvers.add(new org.springframework.web.servlet.mvc.method.annotation.ServletRequestMethodArgumentResolver());
resolvers.add(new org.springframework.web.servlet.mvc.method.annotation.ServletResponseMethodArgumentResolver());
resolvers.add(new org.springframework.web.servlet.mvc.method.annotation.HttpEntityMethodProcessor(getMessageConverters(), this.requestResponseBodyAdvice));
resolvers.add(new org.springframework.web.servlet.mvc.method.annotation.RedirectAttributesMethodArgumentResolver());
resolvers.add(new ModelMethodProcessor());
resolvers.add(new MapMethodProcessor());
resolvers.add(new ErrorsMethodArgumentResolver());
resolvers.add(new SessionStatusMethodArgumentResolver());
resolvers.add(new org.springframework.web.servlet.mvc.method.annotation.UriComponentsBuilderMethodArgumentResolver());

// Custom arguments
if (getCustomArgumentResolvers() != null) {
resolvers.addAll(getCustomArgumentResolvers());
}

// Catch-all
resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), true));
resolvers.add(new org.springframework.web.servlet.mvc.method.annotation.ServletModelAttributeMethodProcessor(true));

return resolvers;
}

2.2 处理解析

  • 查看 RequestMappingHandlerAdapter 类是怎么实现的HandlerAdapter接口的handle方法的,由下面代码可以看到是转到了handleInternal(HttpServletRequest request,HttpServletResponse response, HandlerMethod handlerMethod)这个方法来处理,进入该方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
   // org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter#handle
@Override
public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {

return handleInternal(request, response, (HandlerMethod) handler);
}

// org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter#handleInternal
@Override
protected ModelAndView handleInternal(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
ModelAndView mav;
// 检查是否支持当前的请求,如果不支持则抛出异常
checkRequest(request);
// Execute invokeHandlerMethod in synchronized block if required.
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;
}
  • 关注mav = invokeHandlerMethod(request, response, handlerMethod);方法,进入该方法之后可以看到该方法主要是一些参数准备及组装各种处理单元,先备兵粮
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
/**
* Invoke the {@link RequestMapping} handler method preparing a {@link ModelAndView}
* if view resolution is required.
* @since 4.2
* @see #createInvocableHandlerMethod(HandlerMethod)
*/
protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {

ServletWebRequest webRequest = new ServletWebRequest(request, response);
try {
// 创建WebDataBinder,WebDataBinder用于参数绑定,将符合条件的注释了@InitBinder的方法找出来
WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
// 用来处理Model,在处理器具体处理之前对Model进行初始化,在处理完请求之后对Model参数进行更新
ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);

// 继承自HandlerMethod,实际请求的处理就是通过它来执行的,包括参数绑定,请求处理,以及返回值处理都是在它里面完成
org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
invocableMethod.setDataBinderFactory(binderFactory);
invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);

// ModelAndViewContainer承载着整个请求过程中数据的传递工作
ModelAndViewContainer mavContainer = new ModelAndViewContainer();
mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
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);
}
// 执行方法
invocableMethod.invokeAndHandle(webRequest, mavContainer);
if (asyncManager.isConcurrentHandlingStarted()) {
return null;
}

return getModelAndView(mavContainer, modelFactory, webRequest);
}
finally {
webRequest.requestCompleted();
}
}
  • 这个方法重点关注ServletInvocableHandlerMethod此对象,该类继承自HandlerMethod,实际请求的处理就是通过它来执行的,包括参数绑定,请求处理,以及返回值处理都是在它里面完成
1
2
3
4
5
6
// 继承自HandlerMethod,实际请求的处理就是通过它来执行的,包括参数绑定,请求处理,以及返回值处理都是在它里面完成
org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
invocableMethod.setDataBinderFactory(binderFactory);
invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
  • 查看上面代码可以看到这里设置了参数解析器 结果解析器 等等

  • ServletInvocableHandlerMethod 解析

    • 先查看ServletInvocableHandlerMethod的继承关系,此类的继承关系有三层

    • 顶层HandlerMethod类,该类封装了方法调用相关信息,比如是属于哪个bean下的的,那个Method,方法的参数MethodParameter[]等等

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      /**
      * 封装了方法调用相关信息,子类还提供调用,参数准备和返回值处理的职责
      *
      * Encapsulates information about a handler method consisting of a
      * {@linkplain #getMethod() method} and a {@linkplain #getBean() bean}.
      * Provides convenient access to method parameters, the method return value,
      * method annotations, etc.
      *
      * <p>The class may be created with a bean instance or with a bean name
      * (e.g. lazy-init bean, prototype bean). Use {@link #createWithResolvedBean()}
      * to obtain a {@code HandlerMethod} instance with a bean instance resolved
      * through the associated {@link BeanFactory}.
      *
      * @author Arjen Poutsma
      * @author Rossen Stoyanchev
      * @author Juergen Hoeller
      * @author Sam Brannen
      * @since 3.1
      */
      public class HandlerMethod {

      /** Logger that is available to subclasses */
      protected final Log logger = LogFactory.getLog(getClass());

      private final Object bean;

      private final BeanFactory beanFactory;

      private final Class<?> beanType;

      private final Method method;

      private final Method bridgedMethod;

      /**
      * 方法的参数
      */
      private final MethodParameter[] parameters;

      private HttpStatus responseStatus;

      private String responseStatusReason;

      private HandlerMethod resolvedFromHandlerMethod;

      ...
    • InvocableHandlerMethodHandlerMethod类的基础上添加了方法调用功能及注册了参数解析组件

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      /**
      * 在 HandlerMethod类的基础上添加了方法调用功能及注册了参数解析组件
      *
      * 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 {

      /**
      * 用于参数解析器ArgumentResolver
      */
      private WebDataBinderFactory dataBinderFactory;

      /**
      * 解析参数
      */
      private org.springframework.web.method.support.HandlerMethodArgumentResolverComposite argumentResolvers = new org.springframework.web.method.support.HandlerMethodArgumentResolverComposite();

      /**
      * 用来获取参数名
      */
      private ParameterNameDiscoverer parameterNameDiscoverer = new DefaultParameterNameDiscoverer();


      /**
      * Create an instance from a {@code HandlerMethod}.
      */
      public InvocableHandlerMethod(HandlerMethod handlerMethod) {
      super(handlerMethod);
      }

      ...
  • 得到ServletInvocableHandlerMethod 对象之后进入到ServletInvocableHandlerMethod 类的invocableMethod.invokeAndHandle(webRequest, mavContainer); 方法,可以说这个方法是RequestMappingHandlerAdapter的核心方法,可以看到Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs); 是执行了方法体,得到returnValue 之后就是调用this.returnValueHandlers.handleReturnValue(returnValue, getReturnValueType(returnValue), mavContainer, webRequest);该方法处理结果对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
/**
* Invoke the method and handle the return value through one of the
* configured {@link HandlerMethodReturnValueHandler}s.
* @param webRequest the current request
* @param mavContainer the ModelAndViewContainer for this request
* @param providedArgs "given" arguments matched by type (not resolved)
*/
public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {

Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
setResponseStatus(webRequest);

if (returnValue == null) {
if (isRequestNotModified(webRequest) || getResponseStatus() != null || mavContainer.isRequestHandled()) {
mavContainer.setRequestHandled(true);
return;
}
}
else if (StringUtils.hasText(getResponseStatusReason())) {
mavContainer.setRequestHandled(true);
return;
}

mavContainer.setRequestHandled(false);
try {
this.returnValueHandlers.handleReturnValue(
returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
}
catch (Exception ex) {
if (logger.isTraceEnabled()) {
logger.trace(getReturnValueHandlingErrorMessage("Error handling return value", returnValue), ex);
}
throw ex;
}
}
  • 进入Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs); 方法,可以看到该方法很简单,先是得到方法参数Object[] args,然后执行Object returnValue = doInvoke(args); 该方法得到结果
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
/**
* Invoke the method after resolving its argument values in the context of the given request.
* <p>Argument values are commonly resolved through {@link HandlerMethodArgumentResolver}s.
* The {@code providedArgs} parameter however may supply argument values to be used directly,
* i.e. without argument resolution. Examples of provided argument values include a
* {@link WebDataBinder}, a {@link SessionStatus}, or a thrown exception instance.
* Provided argument values are checked before argument resolvers.
* @param request the current request
* @param mavContainer the ModelAndViewContainer for this request
* @param providedArgs "given" arguments matched by type, not resolved
* @return the raw value returned by the invoked method
* @exception Exception raised if no suitable argument resolver can be found,
* or if the method raised an exception
*/
public Object invokeForRequest(NativeWebRequest request, org.springframework.web.method.support.ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {

// 1、这里得到了方法参数值
Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
if (logger.isTraceEnabled()) {
logger.trace("Invoking '" + ClassUtils.getQualifiedMethodName(getMethod(), getBeanType()) +
"' with arguments " + Arrays.toString(args));
}
// 2、传入方法参数值并执行方法
Object returnValue = doInvoke(args);
if (logger.isTraceEnabled()) {
logger.trace("Method [" + ClassUtils.getQualifiedMethodName(getMethod(), getBeanType()) +
"] returned [" + returnValue + "]");
}
// 3、返回结果
return returnValue;
}

2.1.1 方法参数绑定

  • 方法参数的绑定需要关注Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs); 这行代码,先进入该方法,可以看到该方法先是判断相应类型的参数已经在providedArgs中提供了,如果有的话就是直接返回,否则则使用argumentResolvers解析
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
/**
* 根据当前请求获取方法的请求参数
* Get the method argument values for the current request.
*
*/
private Object[] getMethodArgumentValues(NativeWebRequest request, org.springframework.web.method.support.ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
// 获取方法的参数,在HanderMethod中
MethodParameter[] parameters = getMethodParameters();
// 用于保存解析出参数的值
Object[] args = new Object[parameters.length];
// 遍历每一个参数进行解析
for (int i = 0; i < parameters.length; i++) {
MethodParameter parameter = parameters[i];
// 给Parameter设置参数名解析器
parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);
// 如果相应类型的参数已经在providedArgs中提供了,则直接设置到parameter
args[i] = resolveProvidedArgument(parameter, providedArgs);
if (args[i] != null) {
continue;
}
if (this.argumentResolvers.supportsParameter(parameter)) {
try {
// 使用argumentResolvers解析参数
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;
}
  • RequestMappingHandlerAdapter中只有argumentResolvers解析,因为invocableMethod.invokeAndHandle(webRequest, mavContainer); 只传了两个参数,到了Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs); 方法之后也是没有传入providedArgs的,由上面代码可以看到先是调用supportsParameter()方法判断当前解析器是否支持这个参数解析,如果支持的话就是调用resolveArgument()方法来解析,这两个方法都是HandlerMethodArgumentResolver接口的方法

  • argumentResolvers 存放在HandlerMethodArgumentResolverComposite 类中,所有的ArgumentResolver都存放在List<HandlerMethodArgumentResolver> argumentResolvers中,也可以看到该类也做了一个argumentResolverCacheCache缓存处理,也是为了性能

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
/**
* HandlerMethodArgumentResolver 的仓库
*
* Resolves method parameters by delegating to a list of registered {@link HandlerMethodArgumentResolver}s.
* Previously resolved method parameters are cached for faster lookups.
*
* @author Rossen Stoyanchev
* @author Juergen Hoeller
* @since 3.1
*/
public class HandlerMethodArgumentResolverComposite implements HandlerMethodArgumentResolver {

protected final Log logger = LogFactory.getLog(getClass());

private final List<HandlerMethodArgumentResolver> argumentResolvers =
new LinkedList<HandlerMethodArgumentResolver>();

private final Map<MethodParameter, HandlerMethodArgumentResolver> argumentResolverCache =
new ConcurrentHashMap<MethodParameter, HandlerMethodArgumentResolver>(256);


/**
* Add the given {@link HandlerMethodArgumentResolver}.
*/
public HandlerMethodArgumentResolverComposite addResolver(HandlerMethodArgumentResolver resolver) {
this.argumentResolvers.add(resolver);
return this;
}
  • 通过调试可以看到有下面这些argumentResolvers,看类名称是不是很熟悉,就是我们平常使用的@RequestBody @RequestParam 是一一对应的,还是专人做专事,可以得出不同的参数是有不同的参数解析组件来专门处理的
  • 下面来看主要XXXArgumentResolver的作用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
1. SessionAttributeMethodArgumentResolver
针对 被 @SessionAttribute 修饰的参数起作用, 参数的获取一般通过 HttpServletRequest.getAttribute(name, RequestAttributes.SCOPE_SESSION)
2. RequestParamMethodArgumentResolver
针对被 @RequestParam 注解修饰, 但类型不是 Map, 或类型是 Map, 并且 @RequestParam 中指定 name, 一般通过 MultipartHttpServletRequest | HttpServletRequest 获取数据
3. RequestHeaderMethodArgumentResolver
针对 参数被 RequestHeader 注解, 并且 参数不是 Map 类型, 数据通过 HttpServletRequest.getHeaderValues(name) 获取
4. RequestAttributeMethodArgumentResolver
针对 被 @RequestAttribute 修饰的参数起作用, 参数的获取一般通过 HttpServletRequest.getAttribute(name, RequestAttributes.SCOPE_REQUEST)
5. PathVariableMethodArgumentResolver
解决被注解 @PathVariable 注释的参数 <- 这个注解对应的是 uri 中的数据, 在解析 URI 中已经进行解析好了 <- 在 RequestMappingInfoHandlerMapping.handleMatch -> getPathMatcher().extractUriTemplateVariables
6. MatrixVariableMethodArgumentResolver
针对被 @MatrixVariable 注解修饰的参数起作用, 从 HttpServletRequest 中获取去除 ; 的 URI Template Variables 获取数据
7. ExpressionValueMethodArgumentResolver
针对被 @Value 修饰, 返回 ExpressionValueNamedValueInfo
8. ServletCookieValueMethodArgumentResolver
针对被 @CookieValue 修饰, 通过 HttpServletRequest.getCookies 获取对应数据
  • 然后进入HandlerMethodArgumentResolverComposite类的args[i] = this.argumentResolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory); 方法,可以看到逻辑十分简单,就是遍历this.argumentResolvers 然后做了个缓存处理,得到HandlerMethodArgumentResolver之后就是调用resolver.resolveArgument(parameter, mavContainer, webRequest, binderFactory);方法了,该方法是参数解析的主体方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
/**
* 迭代注册过的 HandlerMethodArgumentResolver, 然后找到对应的ArgumentResolver
* Iterate over registered {@link HandlerMethodArgumentResolver}s and invoke the one that supports it.
* @throws IllegalStateException if no suitable {@link HandlerMethodArgumentResolver} is found.
*/
@Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {

HandlerMethodArgumentResolver resolver = getArgumentResolver(parameter);
if (resolver == null) {
throw new IllegalArgumentException("Unknown parameter type [" + parameter.getParameterType().getName() + "]");
}
return resolver.resolveArgument(parameter, mavContainer, webRequest, binderFactory);
}

/**
* 先从缓存里取,没有的再遍历,注意这里是先来先得的
* Find a registered {@link HandlerMethodArgumentResolver} that supports the given method parameter.
*/
private HandlerMethodArgumentResolver getArgumentResolver(MethodParameter parameter) {
HandlerMethodArgumentResolver result = this.argumentResolverCache.get(parameter);
if (result == null) {
for (HandlerMethodArgumentResolver methodArgumentResolver : this.argumentResolvers) {
if (logger.isTraceEnabled()) {
logger.trace("Testing if argument resolver [" + methodArgumentResolver + "] supports [" +
parameter.getGenericParameterType() + "]");
}
if (methodArgumentResolver.supportsParameter(parameter)) {
result = methodArgumentResolver;
this.argumentResolverCache.put(parameter, result);
break;
}
}
}
return result;
}
  • 再来回顾HandlerMethodArgumentResolver接口,该接口就两个方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
/**
* 方法参数解析器
*
* Strategy interface for resolving method parameters into argument values in
* the context of a given request.
*
* @author Arjen Poutsma
* @since 3.1
* @see HandlerMethodReturnValueHandler
*/
public interface HandlerMethodArgumentResolver {

/**
* 是否支持
*
* 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
*/
boolean supportsParameter(MethodParameter parameter);

/**
* 根据request解析方法参数值
*
* Resolves a method parameter into an argument value from a given request.
* A {@link ModelAndViewContainer} provides access to the model for the
* request. A {@link WebDataBinderFactory} provides a way to create
* a {@link WebDataBinder} instance when needed for data binding and
* type conversion purposes.
* @param parameter the method parameter to resolve. This parameter must
* have previously been passed to {@link #supportsParameter} which must
* have returned {@code true}.
* @param mavContainer the ModelAndViewContainer for the current request
* @param webRequest the current request
* @param binderFactory a factory for creating {@link WebDataBinder} instances
* @return the resolved argument value, or {@code null}
* @throws Exception in case of errors with the preparation of argument values
*/
Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception;

}
  • HandlerMethodArgumentResolverresolveArgument 的解析将在之后的章节介绍

2.2.2 方法执行

  • 回到InvocableHandlerMethod类的invokeForRequest 方法,上一小节介绍了方法参数绑定的主体逻辑(Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);),这一小节介绍Object returnValue = doInvoke(args);,该行代码是方法执行的主体方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public Object invokeForRequest(NativeWebRequest request, org.springframework.web.method.support.ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {

// 1、这里得到了方法参数值
Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
if (logger.isTraceEnabled()) {
logger.trace("Invoking '" + ClassUtils.getQualifiedMethodName(getMethod(), getBeanType()) +
"' with arguments " + Arrays.toString(args));
}
// 2、传入方法参数值并执行方法
Object returnValue = doInvoke(args);
if (logger.isTraceEnabled()) {
logger.trace("Method [" + ClassUtils.getQualifiedMethodName(getMethod(), getBeanType()) +
"] returned [" + returnValue + "]");
}
// 3、返回结果
return returnValue;
}
  • 进入Object returnValue = doInvoke(args); 方法,可以看到调用了getBridgedMethod().invoke(getBean(), args); 来执行方法,getBridgedMethod() 得到的是private final Method bridgedMethod,百度了一下这个桥接方法的用途是为了和jdk1.5之前的字节码兼容. 因为范型是在jdk1.5之后才引入的. 在jdk1.5之前例如集合的操作都是没有范型支持的, 所以生成的字节码中参数都是用Object接收的, 所以也可以往集合中放入任意类型的对象, 集合类型的校验也被拖到运行期.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
/**
* Invoke the handler method with the given argument values.
*/
protected Object doInvoke(Object... args) throws Exception {
// 强制将他变为可调用 即使是private方法
ReflectionUtils.makeAccessible(getBridgedMethod());
try {
return getBridgedMethod().invoke(getBean(), args);
}
catch (IllegalArgumentException ex) {
assertTargetBean(getBridgedMethod(), getBean(), args);
String text = (ex.getMessage() != null ? ex.getMessage() : "Illegal argument");
throw new IllegalStateException(getInvocationErrorMessage(text, args), ex);
}
catch (InvocationTargetException ex) {
// Unwrap for HandlerExceptionResolvers ...
Throwable targetException = ex.getTargetException();
if (targetException instanceof RuntimeException) {
throw (RuntimeException) targetException;
}
else if (targetException instanceof Error) {
throw (Error) targetException;
}
else if (targetException instanceof Exception) {
throw (Exception) targetException;
}
else {
String text = getInvocationErrorMessage("Failed to invoke handler method", args);
throw new IllegalStateException(text, targetException);
}
}
}
  • 在此方法执行完成

2.2.3 返回结果处理

  • 方法执行完成之后就对返回结果的处理了,回到ServletInvocableHandlerMethod类,现在方法体已经执行了,就是对结果对象的处理了
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
/**
* Invoke the method and handle the return value through one of the
* configured {@link HandlerMethodReturnValueHandler}s.
* @param webRequest the current request
* @param mavContainer the ModelAndViewContainer for this request
* @param providedArgs "given" arguments matched by type (not resolved)
*/
public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {

Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
setResponseStatus(webRequest);

if (returnValue == null) {
if (isRequestNotModified(webRequest) || getResponseStatus() != null || mavContainer.isRequestHandled()) {
mavContainer.setRequestHandled(true);
return;
}
}
else if (StringUtils.hasText(getResponseStatusReason())) {
mavContainer.setRequestHandled(true);
return;
}

mavContainer.setRequestHandled(false);
try {
this.returnValueHandlers.handleReturnValue(returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
}
catch (Exception ex) {
if (logger.isTraceEnabled()) {
logger.trace(getReturnValueHandlingErrorMessage("Error handling return value", returnValue), ex);
}
throw ex;
}
}
  • 查看上面的代码可以看到this.returnValueHandlers.handleReturnValue(returnValue, getReturnValueType(returnValue), mavContainer, webRequest); 这行代码作用是对结果对象的处理,查看returnValueHandlers 对象(private HandlerMethodReturnValueHandlerComposite returnValueHandlers;)可以看到和我们之前的参数绑定的处理是相似的,HandlerMethodReturnValueHandlerComposite存放了各种结果处理组件

HandlerMethodReturnValueHandlerComposite.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

/**
* Handles method return values by delegating to a list of registered {@link HandlerMethodReturnValueHandler}s.
* Previously resolved return types are cached for faster lookups.
*
* @author Rossen Stoyanchev
* @since 3.1
*/
public class HandlerMethodReturnValueHandlerComposite implements AsyncHandlerMethodReturnValueHandler {

protected final Log logger = LogFactory.getLog(getClass());

// 结果处理组件
private final List<HandlerMethodReturnValueHandler> returnValueHandlers =
new ArrayList<HandlerMethodReturnValueHandler>();

HandlerMethodReturnValueHandler.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
/**
* 结果对象处理
*
* Strategy interface to handle the value returned from the invocation of a
* handler method .
*
* @author Arjen Poutsma
* @since 3.1
* @see HandlerMethodArgumentResolver
*/
public interface HandlerMethodReturnValueHandler {

/**
* 是否支持
*
* 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
*/
boolean supportsReturnType(MethodParameter returnType);

/**
* 处理结果集
*
* 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
*/
void handleReturnValue(Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception;

}
  • 进入handleReturnValue方法,可以看到和之前方法参数绑定处理是一样的套路的
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
/**
* 迭代注册过的 HandlerMethodReturnValueHandler, 然后找到对应的ReturnValueHandler
* Iterate over registered {@link HandlerMethodReturnValueHandler}s and invoke the one that supports it.
* @throws IllegalStateException if no suitable {@link HandlerMethodReturnValueHandler} is found.
*/
@Override
public void handleReturnValue(Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {

HandlerMethodReturnValueHandler handler = selectHandler(returnValue, returnType);
if (handler == null) {
throw new IllegalArgumentException("Unknown return value type: " + returnType.getParameterType().getName());
}
handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);
}

private HandlerMethodReturnValueHandler selectHandler(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;
}
  • 如下图可以看到有如下this.returnValueHandlers

3.1 总结

  • RequestMappingHandlerAdapter 的功能主要是
    • 1、方法参数绑定
    • 2、方法执行,
    • 3、返回结果处理`
  • HandlerMethodArgumentResolver 的方法参数绑定处理是针对于不同的方法参数有专门的ArgumentResolver 专人做专事,专业
  • HandlerMethodReturnValueHandler 的返回结果处理也是和参数处理那样是针对于不同的返回对象有专门的ReturnValueHandler

4.1 参考

官方文档: https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html