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方法處理請求,自身會做關於響應狀態的操作以及通過結果處理器處理結果等細節。