SpringAOP[5]-MethodInvocation(攔截器的調用)


原文:SpringAOP聯盟(5)-MethodInvocation(攔截器的調用) - 簡書 (jianshu.com)

在上文中,代理對象創建后,最終的攔截工作都是交給了MethodInvocation。JDK交給了ReflectiveMethodInvocation,而CGLIB交給CglibMethodInvocation

此處所說的MethodInvocation是AOP聯盟包下的,也就是org.aopalliance.intercept.MethodInvocation

此接口會繼承Joinpoint接口,注意不要和org.aspectj.lang.JoinPoint搞混。

  1. org.aspectj.lang.JoinPoint:該對象封裝了SpringAop中切面方法信息,在切面方法添加JoinPoint參數,可以很方便的獲取更多信息。(一般用於@Aspect標注的切面方法入參)。
  2. 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特有的方法。
並且 CglibMethodInvocationCglibAopProxy的靜態內部類。
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)去執行,它會將該方法上的攔截器鏈緩存,並遞歸調用執行。


推薦閱讀

https://blog.csdn.net/f641385712/article/details/88975543

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM