原文:SpringAOP聯盟(5)-MethodInvocation(攔截器的調用) - 簡書 (jianshu.com)
在上文中,代理對象創建后,最終的攔截工作都是交給了MethodInvocation。JDK交給了ReflectiveMethodInvocation,而CGLIB交給CglibMethodInvocation。
此處所說的MethodInvocation是AOP聯盟包下的,也就是org.aopalliance.intercept.MethodInvocation。
此接口會繼承Joinpoint接口,注意不要和org.aspectj.lang.JoinPoint搞混。
org.aspectj.lang.JoinPoint:該對象封裝了SpringAop中切面方法信息,在切面方法添加JoinPoint參數,可以很方便的獲取更多信息。(一般用於@Aspect標注的切面方法入參)。org.aopalliance.intercept.Joinpoint是AOP聯盟中的類,關系如下圖所示:
//此接口表示運行時的連接點(AOP術語) public interface Joinpoint { //執行此攔截點,並進入下一個連接點 Object proceed() throws Throwable; //保存當前連接點靜態對象,這里一般指的是target Object getThis(); //返回此靜態連接點,一般就為當前的Method AccessibleObject getStaticPart(); }
public interface Invocation extends Joinpoint { //獲取參數,例如方法的參數 Object[] getArguments(); }
// 方法調用時,對這部分進行描述 public interface MethodInvocation extends Invocation { // 返回正在被調用得方法,返回的是當前Method對象。 // 此時,效果同父類的AccessibleObject getStaticPart() 這個方法 Method getMethod(); }
MethodInvocation作為aopalliance里提供的最底層的接口。Spring也提供了相關的實現。

Spring也提供了一個接口
proxyMethodInvoation來進行擴展使用。
public interface ProxyMethodInvocation extends MethodInvocation { //返回代理對象 Object getProxy(); //clone一個,使用的是Object的clone方法 MethodInvocation invocableClone(); MethodInvocation invocableClone(Object... arguments); //設置參數 增強器、通知執行的時候可能會使用到 void setArguments(Object... arguments); //添加一些kv,但這些kv並不會用於AOP框架,而是保存起來給特殊的攔截器使用 void setUserAttribute(String key, @Nullable Object value); @Nullable Object getUserAttribute(String key); }
1. ReflectiveMethodInvocation
Spring提供的實現類:org.springframework.aop.framework.ReflectiveMethodInvocation
該類作為實現類,會實現包含父父類所有的抽象方法。
他也是JdkDynamicAopProxy最終要new出來的類。
public class ReflectiveMethodInvocation implements ProxyMethodInvocation, Cloneable { protected final Object proxy; // 代理對象 @Nullable protected final Object target; // 目標對象 protected final Method method; // 被攔截的方法 protected Object[] arguments = new Object[0]; @Nullable private final Class<?> targetClass; @Nullable private Map<String, Object> userAttributes; protected final List<?> interceptorsAndDynamicMethodMatchers; // currentInterceptorIndex初始值為 -1(攔截鏈初始值為-1) private int currentInterceptorIndex = -1; //Spring內部使用的類 protected ReflectiveMethodInvocation( Object proxy, @Nullable Object target, Method method, @Nullable Object[] arguments, @Nullable Class<?> targetClass, List<Object> interceptorsAndDynamicMethodMatchers) { this.proxy = proxy; this.target = target; this.targetClass = targetClass; // 找到橋接方法,作為最后執行的方法。 this.method = BridgeMethodResolver.findBridgedMethod(method); // 對參數進行適配 this.arguments = AopProxyUtils.adaptArgumentsIfNecessary(method, arguments); this.interceptorsAndDynamicMethodMatchers = interceptorsAndDynamicMethodMatchers; } @Override public final Object getProxy() { return this.proxy; } @Override @Nullable public final Object getThis() { return this.target; } // 此處:getStaticPart返回的就是當前得method @Override public final AccessibleObject getStaticPart() { return this.method; } // 注意:這里返回的可能是橋接方法哦 @Override public final Method getMethod() { return this.method; } @Override public final Object[] getArguments() { return this.arguments; } @Override public void setArguments(Object... arguments) { this.arguments = arguments; } //這里是執行的核心,要執行方法,執行通知都是在此處搞定的。 //這里是遞歸調用的方式,執行所有的過濾器鏈 @Override @Nullable public Object proceed() throws Throwable { // currentInterceptorIndex初始值為 -1 如果執行到鏈條的末尾 則直接調用連接點方法 即 直接調用目標方法 if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) { // 這個方法相當於調用了目標方法~~~下面會分析 return invokeJoinpoint(); } // 獲取集合中的 MethodInterceptor(並且currentInterceptorIndex + 1了哦) Object interceptorOrInterceptionAdvice = this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex); //InterceptorAndDynamicMethodMatcher它是Spring內部使用的一個類。很簡單,就是把MethodInterceptor實例和MethodMatcher放在了一起。看看在advisor chain里面是否能夠匹配上 if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) { InterceptorAndDynamicMethodMatcher dm = (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice; // 去匹配這個攔截器是否適用於這個目標方法 試用就執行攔截器得invoke方法 if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) { return dm.interceptor.invoke(this); } else { // 如果不匹配。就跳過此攔截器,而繼續執行下一個攔截器 // 注意:這里是遞歸調用 並不是循環調用 return proceed(); } } else { // 直接執行此攔截器。說明之前已經匹配好了,只有匹配上的方法才會被攔截進來的 // 這里傳入this就是傳入了ReflectiveMethodInvocation,從而形成了一個鏈條了 return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this); } } /** ** AopUtils.invokeJoinpointUsingReflection源碼: ** ReflectionUtils.makeAccessible(method); ** return method.invoke(target, args); **/ //方法調用時簡單的`method.invoke(target, args);`。 //子類可以復寫該方法,比如唯一子類`CglibAopProxy`內部類`CglibMethodInvocation`就復寫了這個方法(后續有介紹) @Nullable protected Object invokeJoinpoint() throws Throwable { //此處傳入的是target,而不能是proxy。否則會進入死循環 return AopUtils.invokeJoinpointUsingReflection(this.target, this.method, this.arguments); } }
2. CglibMethodInvocation
它是
並且
ReflectiveMethodInvocation的唯一子類,是Cglib自己使用的執行器。你可以將其看做為工廠模式,它會實現一些Cglib特有的方法。
並且
CglibMethodInvocation是
CglibAopProxy的靜態內部類。
private static class CglibMethodInvocation extends ReflectiveMethodInvocation { @Nullable private final MethodProxy methodProxy; public CglibMethodInvocation(Object proxy, @Nullable Object target, Method method, Object[] arguments, @Nullable Class<?> targetClass, List<Object> interceptorsAndDynamicMethodMatchers, MethodProxy methodProxy) { super(proxy, target, method, arguments, targetClass, interceptorsAndDynamicMethodMatchers); //做出了特殊處理,methodProxy是子類特有的參數,表示被CGLIB攔截的時候的類 //MethodProxy:為生成代理類對方法的代理引用,使用MethodProxy比直接調用JDK本身的Method直接執行方法效率會有提升。 //MethodProxy有兩個重要的方法:invoke和invokeSuper。 //method.getDeclaringClass用來判斷當前這個方法是哪個類的方法。 //若該方法是public方法 且 method不是Object類的方法 且 method不是equals 且 method不是 hashCode 且 method不是toString方法,返回methodProxy對象。 this.methodProxy = (Modifier.isPublic(method.getModifiers()) && method.getDeclaringClass() != Object.class && !AopUtils.isEqualsMethod(method) && !AopUtils.isHashCodeMethod(method) && !AopUtils.isToStringMethod(method) ? methodProxy : null); } @Override protected Object invokeJoinpoint() throws Throwable { if (this.methodProxy != null) { //如果符合上述條件,調用methodProxy去執行目標方法。(使用FastClass調用) return this.methodProxy.invoke(this.target, this.arguments); } else { return super.invokeJoinpoint(); } } }
那些
@AspectJ定義的通知(增強器),或者自己實現的
MethodBeforeAdvice、AfterReturningAdvice...最終都會被包裝為一個
org.aopalliance.intercept.MethodInterceptor,交由MethodInvocation(其子類是
ReflectiveMethodInvocation)去執行,它會將該方法上的攔截器鏈緩存,並遞歸調用執行。
