HandlerMethod
HandlerMethod封装了目标handler处理器方法和目标方法所属的Bean对象,提供了更方便的访问handler参数和返回值的接口。其子类在得到这些属性之后,对外提供了调用目标处理器的方法。
一、属性方法
1.1 主要属性
主要属性是封装里了目标方法、目标Bean对象、参数以及Bean类型等细节信息。
private final Object bean;
@Nullable
private final BeanFactory beanFactory;
private final Class< ? > beanType;
private final Method method;
private final Method bridgedMethod;
private final MethodParameter[ ] parameters;
@Nullable
private HttpStatus responseStatus;
@Nullable
private String responseStatusReason;
@Nullable
private HandlerMethod resolvedFromHandlerMethod;
@Nullable
private volatile List< Annotation[ ] [ ] > interfaceParameterAnnotations;
1.2 主要方法
1.2.1 构造方法
构造方法有很多重载的,下面这个构造方法传入的是一个BeanName,Bean工厂和方法对象,后续会根据BeanName从工厂获取真正的Bean对象
public HandlerMethod ( String beanName, BeanFactory beanFactory, Method method) {
Assert. hasText ( beanName, "Bean name is required" ) ;
Assert. notNull ( beanFactory, "BeanFactory is required" ) ;
Assert. notNull ( method, "Method is required" ) ;
this . bean = beanName;
this . beanFactory = beanFactory;
Class< ? > beanType = beanFactory. getType ( beanName) ;
if ( beanType == null) {
throw new IllegalStateException ( "Cannot resolve bean type for bean with name '" + beanName + "'" ) ;
}
this . beanType = ClassUtils. getUserClass ( beanType) ;
this . method = method;
this . bridgedMethod = BridgeMethodResolver. findBridgedMethod ( method) ;
this . parameters = initMethodParameters ( ) ;
evaluateResponseStatus ( ) ;
}
1.2.2 创建对象
createWithResolvedBean方法用于创建HandlerMethod对象,从注释能够看出,如果提供的只是一个String类型的BeanName而不是Bean实例,在HandlerMethod创建之前会通过createWithResolvedBean方法获取Bean实例,其实就是从Bean工厂里面获取Bean实例,这个Bean实例就行目标方法所属的Bean,比如我们自己写的控制器类。
public HandlerMethod createWithResolvedBean ( ) {
Object handler = this . bean;
if ( this . bean instanceof String ) {
String beanName = ( String) this . bean;
handler = this . beanFactory. getBean ( beanName) ;
}
return new HandlerMethod ( this , handler) ;
}
其他很多都是属性获取方法、注解相关获取等方法、另外还有方法参数的辅助类MethodParameter等,细节就不关注了。
二、InvocableHandlerMethod
InvocableHandlerMethod是HandlerMethod的子类,我们通过Adapter调用目标执行链,最终通过反射的方式调用目标方法,而这个调用的过程就是通过InvocableHandlerMethod来完成的。
下面是从InvocableHandlerMethod的注释翻译过来
InvocableHandlerMethod 提供了调用目标处理器的方法来处理对应的请求,不过在调用之前需要通
过 HandlerMethodArgumentResolver 来处理好请求的参数值。
参数处理通常需要WebDataBinder来做参数绑定或者类型转换,使用setDataBinderFactory方法来提
供一个binder factory来获取参数解析器。
2.1 主要属性
下面是主要属性,属性相关的setXX方法省略,构造方法省略
private WebDataBinderFactory dataBinderFactory;
private HandlerMethodArgumentResolverComposite argumentResolvers = new HandlerMethodArgumentResolverComposite ( ) ;
private ParameterNameDiscoverer parameterNameDiscoverer = new DefaultParameterNameDiscoverer ( ) ;
2.2 主要方法
2.2.1 invokeForRequest
invokeForRequest方法是处理请求的入口,
public Object invokeForRequest ( NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer, Object. . . providedArgs) throws Exception {
Object[ ] args = getMethodArgumentValues ( request, mavContainer, providedArgs) ;
Object returnValue = doInvoke ( args) ;
return returnValue;
}
2.2.2 getMethodArgumentValues
getMethodArgumentValues用于获取参数,核心代码如下,不具体分析了
private Object[ ] getMethodArgumentValues ( NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer, Object. . . providedArgs) throws Exception {
for ( int i = 0 ; i < parameters. length; i++ ) {
if ( this . argumentResolvers. supportsParameter ( parameter) ) {
try {
args[ i] = this . argumentResolvers. resolveArgument ( parameter, mavContainer, request, this . dataBinderFactory) ;
continue ;
}
catch ( Exception ex) {
}
}
if ( args[ i] == null) {
}
}
return args;
}
@RestController
public class TestController {
@PostMapping ( value = "/hello" )
public String hello ( @RequestParam ( "a" ) String a, @RequestParam ( "b" ) String b) {
System. out. println ( "--------1----------" + a + " --- " + b) ;
return "hello!" ;
}
}
参数: 给a和b参数传值分别是:aaaaaa和bbbbbb
可以看到,通过getMethodArgumentValues拿到了方法的入参实参,后面就通过doInvoke来调用目标方法了。
这里的提取参数的细节在argumentResolvers.resolveArgument方法,深入需要分析HandlerMethodArgumentResolver接口和其实现类,具体后续文章再分析。
2.2.3 doInvoke
protected Object doInvoke ( Object. . . args) throws Exception {
ReflectionUtils. makeAccessible ( getBridgedMethod ( ) ) ;
try {
return getBridgedMethod ( ) . invoke ( getBean ( ) , args) ;
}
catch ( IllegalArgumentException ex) {
}
}
注意这里getBridgedMethod()会得到一个Method对象,然后Method.invoke(Object,args);
里面的getBean()调用的就是父类的HandlerMethod里面封装的Bean,其实就是我们的目标Bean,args就是方法参数
最后invoke调用就到了Method的invoke方法,代码如下,其实就是通过反射调用目标对象的方法
@CallerSensitive
public Object invoke ( Object obj, Object. . . args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException{
if ( ! override) {
if ( ! Reflection. quickCheckMemberAccess ( clazz, modifiers) ) {
Class< ? > caller = Reflection. getCallerClass ( ) ;
checkAccess ( caller, clazz, obj, modifiers) ;
}
}
MethodAccessor ma = methodAccessor;
if ( ma == null) {
ma = acquireMethodAccessor ( ) ;
}
return ma. invoke ( obj, args) ;
}
这里大体把 InvocableHandlerMethod 的核心方法走读了一遍,内部主要是先提取真正的参数,然后通过反射调用,因为其内部持有目标Bean对象和目标方法Method对象,得到参数之后反射调用就很容易了。
三、ServletInvocableHandlerMethod
ServletInvocableHandlerMethod是InvocableHandlerMethod的一个子类,调试过程中真正的对象是 ServletInvocableHandlerMethod实例,invokeForRequest方法也是从ServletInvocableHandlerMethod往父类调用的
那么 它继承 InvocableHandlerMethod之后又增加了什么特性了?我们先还是看看源码中类的注释:
3.1 属性方法
private HandlerMethodReturnValueHandlerComposite returnValueHandlers;
invokeAndHandle方法是ServletInvocableHandlerMethod在处理请求过程中最重要的方法,请求先被该方法处理,然后才走到父类 InvocableHandlerMethod 的invokeForRequest方法
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) {
throw ex;
}
}
3.2 内部类ConcurrentResultHandlerMethod
ConcurrentResultHandlerMethod是ServletInvocableHandlerMethod的一个内部类,也是ServletInvocableHandlerMethod的子类,按照注释来看是关于异步处理相关的;
四、小结
本文主要介绍HandlerMethod这个类的作用,它内部封装了目标对象Bean,方法对象Method,方法参数、Bean类型和Bean工厂等参数,便于外部直接调用目标方法。
不过在HandlerMethod中只定义了相关的属性和一些属性的读取方法,处理请求的主体逻辑在子类InvocableHandlerMethod的invokeForRequest和doInvoke方法,内部通过反射来调用目标对象的指定方法。
子类ServletInvocableHandlerMethod通过 InvocableHandlerMethod的invokeForRequest和doInvoke方法处理请求,自身会做关于响应状态的操作以及通过结果处理器处理结果等细节。