天天看點

Spring AOP源碼解讀3 - 代理的生成前言正文

前言

前面兩部分講了程式入口 和 切面和增強的取得。這一部分講解代理的建立。

正文

查找Advisor的getAdvicesAndAdvisorsForBean方法的實作方式已經介紹完了,接下來我們介紹一下生成代理的createProxy方法的實作方式。在這個方法裡重要的方法如下:

  1. buildAdvisors:建立切面(todo:在找出适合的Advisor時,取得的結果可能是Advice嗎)
  2. getProxy:取得代理(也是建立代理過程)
protected Object createProxy(
        Class<?> beanClass, String beanName, Object[] specificInterceptors, TargetSource targetSource) {

    ProxyFactory proxyFactory = new ProxyFactory();
    proxyFactory.copyFrom(this);

    // 設定ProxyTargetClass屬性。
    // 如果ProxyTargetClass為True,使用CGLIB方式代理;False,使用JdkDynamicProxy方式
    if (!proxyFactory.isProxyTargetClass()) {
        if (shouldProxyTargetClass(beanClass, beanName)) {
            proxyFactory.setProxyTargetClass(true);
        }
        else {
            evaluateProxyInterfaces(beanClass, proxyFactory);
        }
    }
    // 建立切面
    Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
    // 把建立的切面添加到ProxyFactory裡
    for (Advisor advisor : advisors) {
        proxyFactory.addAdvisor(advisor);
    }

    proxyFactory.setTargetSource(targetSource);
    customizeProxyFactory(proxyFactory);

    proxyFactory.setFrozen(this.freezeProxy);
    if (advisorsPreFiltered()) {
        proxyFactory.setPreFiltered(true);
    }
    // 建立代理
    return proxyFactory.getProxy(getProxyClassLoader());
}
           

1,建立切面流程

在buildAdvisors方法中,比較重要的是advisorAdapterRegistry.wrap方法的調用,這個方法是把Advice包裝成一個Advisor。

protected Advisor[] buildAdvisors(String beanName, Object[] specificInterceptors) {
    // Handle prototypes correctly...
    // 通過interceptorNames屬性,獲得聲明式代理方式下,指定的interceptorNames屬性裡聲明的advice或者advisor
    // 在AspectJ代理方式時,應該沒有使用(因為感覺沒發現地方指定interceptorNames屬性)
    Advisor[] commonInterceptors = resolveInterceptorNames();

    List<Object> allInterceptors = new ArrayList<Object>();
    if (specificInterceptors != null) {
        allInterceptors.addAll(Arrays.asList(specificInterceptors));
        if (commonInterceptors != null) {
            if (this.applyCommonInterceptorsFirst) {
                allInterceptors.addAll(0, Arrays.asList(commonInterceptors));
            }
            else {
                allInterceptors.addAll(Arrays.asList(commonInterceptors));
            }
        }
    }
    if (logger.isDebugEnabled()) {
        int nrOfCommonInterceptors = (commonInterceptors != null ? commonInterceptors.length : 0);
        int nrOfSpecificInterceptors = (specificInterceptors != null ? specificInterceptors.length : 0);
        logger.debug("Creating implicit proxy for bean '" + beanName + "' with " + nrOfCommonInterceptors +
                " common interceptors and " + nrOfSpecificInterceptors + " specific interceptors");
    }

    Advisor[] advisors = new Advisor[allInterceptors.size()];
    for (int i = 0; i < allInterceptors.size(); i++) {
        // 通過AdvisorAdapter把allInterceptors裡的元素包裝成Advisor。
        // allInterceptors裡的元素不一定是Advisor類型,可能是Advice
        advisors[i] = this.advisorAdapterRegistry.wrap(allInterceptors.get(i));
    }
    return advisors;
}
           

wrap方法是,如果參數是Advice類型,就包裝成Advisor。包裝時候是使用DefaultPointcutAdvisor進行包裝的。

包裝時候使用的是AdvisorAdapter接口。這個接口有兩個方法:

  • supportsAdvice(Advice advice):判斷參數的Advice是不是目前Adapter支援的Advice。
  • getInterceptor(Advisor advisor):根據參數Advice生成Interceptor。

supportsAdvice

方法裡使用的adapters屬性在DefaultAdvisorAdapterRegistry的構造函數裡就進行指派了,設定了3個Adapter:

  • MethodBeforeAdviceAdapter
  • AfterReturningAdviceAdapter
  • ThrowsAdviceAdapter

這時在我們主要用到了supportsAdvice方法。這3個Adapter循環對Advice進行處理,如果Advice是Adapter支援的類型,就傳回一個Advisor。

public Advisor wrap(Object adviceObject) throws UnknownAdviceTypeException {
    if (adviceObject instanceof Advisor) {
        return (Advisor) adviceObject;
    }
    if (!(adviceObject instanceof Advice)) {
        throw new UnknownAdviceTypeException(adviceObject);
    }
    Advice advice = (Advice) adviceObject;
    // 如果Advice是已經實作了MethodInterceptor接口的執行個體,就不用包裝了,
    // 因為我們最終要生成的是Interceptor,現在包裝成Advisor隻是一個過程。
    if (advice instanceof MethodInterceptor) {
        // So well-known it doesn't even need an adapter.
        return new DefaultPointcutAdvisor(advice);
    }
    // 循環對Advice進行判斷,如果是支援類型,就傳回包裝後的Advisor
    for (AdvisorAdapter adapter : this.adapters) {
        // Check that it is supported.
        if (adapter.supportsAdvice(advice)) {
            return new DefaultPointcutAdvisor(advice);
        }
    }
    throw new UnknownAdviceTypeException(advice);
}
           

2 建立代理相關流程

buildAdvisors

方法及其子方法介紹完了,我們最後來介紹最

proxyFactory.getProxy(getProxyClassLoader())

方法的實作過程。

前在的一切都是準備資源,這個方法是利用資源生成代理的實作。我們先來看一看

getProxy

方法的内容。

這個方法裡隻有行代碼

createAopProxy().getProxy(classLoader)

。這行代碼中,首先調用了

createAopProxy

這個方法,

createAopProxy

方法裡又調用了

getAopProxyFactory().createAopProxy(this)

方法。

public Object getProxy(ClassLoader classLoader) {
    return createAopProxy().getProxy(classLoader);
}
           
protected final synchronized AopProxy createAopProxy() {
    if (!this.active) {
        activate();
    }
    return getAopProxyFactory().createAopProxy(this);
}
           

我們看一下createAopProxy方法的具體内容。這個方法的實作是在DefaultAopProxyFactory類中。

這個方法的主要功能是,根據optimize、ProxyTargetClass等參數來決定生成Jdk動态代理,還是生成Cglib代理。

@Override
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
    if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
        Class<?> targetClass = config.getTargetClass();
        if (targetClass == null) {
            throw new AopConfigException("TargetSource cannot determine target class: " +
                    "Either an interface or a target is required for proxy creation.");
        }
        if (targetClass.isInterface()) {
            // 生成Jdk動态代理
            return new JdkDynamicAopProxy(config);
        }
        // 成生Cglib代理
        return new ObjenesisCglibAopProxy(config);
    }
    else {
        // 生成Jdk動态代理
        return new JdkDynamicAopProxy(config);
    }
           

Jdk動态代理和Cglib代理的差別和實作方式在這裡就不具體講解了,請大家上網找一些資料。

Spring對這兩種代理做了包裝,包裝類分别是:

  • JdkDynamicAopProxy
  • ObjenesisCglibAopProxy類。

這兩個類的構造函數是AdvisedSupport,這個類保包含了 Spring AOP的配置和對配置的一些通路方法(例如:Advisor),還有AdvisorChainFactory對象。AdvisorChainFactory對象的功能主要是,根據在前面找到的合适的Advisor成生Interceptor,最後代理調用時實際上都是調用的Interceptor。

createAopProxy方法講完後,createAopProxy後面調用getProxy方法。這個方法不算難,主要是根據要生成代理的類型(Jdk動态代理和Cglib),把這兩種技術各自獨特的實作代理的過程給封裝了。比較複雜的邏輯是在,代理被調用時回調方法裡面。在回調方法裡面,及到了Intercceptor鍊(Interceptor包裝了Advisor)的調用,這個實作也挺巧妙的。

我們拿Jdk動态代理的回調來說明。了解Jdk動态代理的話都會知道,在實作Jdk動态代理功能,要實作InvocationHandler接口的invoke方法(這個方法是一個回調方法)。

被代理類中的方法被調用時,實際上是調用的invoke方法,我們看一看這個方法的實作。

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    MethodInvocation invocation;
    Object oldProxy = null;
    boolean setProxyContext = false;

    TargetSource targetSource = this.advised.targetSource;
    Class<?> targetClass = null;
    Object target = null;

    try {
        if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
            // The target does not implement the equals(Object) method itself.
            return equals(args[]);
        }
        if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
            // The target does not implement the hashCode() method itself.
            return hashCode();
        }
        if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
                method.getDeclaringClass().isAssignableFrom(Advised.class)) {
            // Service invocations on ProxyConfig with the proxy config...
            return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
        }

        Object retVal;

        if (this.advised.exposeProxy) {
            // Make invocation available if necessary.
            oldProxy = AopContext.setCurrentProxy(proxy);
            setProxyContext = true;
        }

        // May be null. Get as late as possible to minimize the time we "own" the target,
        // in case it comes from a pool.
        target = targetSource.getTarget();
        if (target != null) {
            targetClass = target.getClass();
        }

        // Get the interception chain for this method.
        // 利用Adivsor,生成一個我們之前定義的Advice調用鍊。在調用被代理方法前後時,調用這個鍊。
        // 在這個方法裡面,實際上調用advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice方法來實作了,
        // 這個方法的作用我們在上面已經說過了,在這裡不再重複了。
        // 這裡生成的鍊的對象全部都封裝成了MethodInterceptor。
        List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

        // Check whether we have any advice. If we don't, we can fallback on direct
        // reflective invocation of the target, and avoid creating a MethodInvocation.
        if (chain.isEmpty()) {
            // We can skip creating a MethodInvocation: just invoke the target directly
            // Note that the final invoker must be an InvokerInterceptor so we know it does
            // nothing but a reflective operation on the target, and no hot swapping or fancy proxying.
            retVal = AopUtils.invokeJoinpointUsingReflection(target, method, args);
        }
        else {
            // We need to create a method invocation...
            // 這裡非常重要。生成一個方法調用的控制類,并調用proceed方法,進行鍊和被代理方法的調用
            invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
            // Proceed to the joinpoint through the interceptor chain.
            retVal = invocation.proceed();
        }

        // Massage return value if necessary.
        Class<?> returnType = method.getReturnType();
        if (retVal != null && retVal == target && returnType.isInstance(proxy) &&
                !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
            // Special case: it returned "this" and the return type of the method
            // is type-compatible. Note that we can't help if the target sets
            // a reference to itself in another returned object.
            retVal = proxy;
        }
        else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
            throw new AopInvocationException(
                    "Null return value from advice does not match primitive return type for: " + method);
        }
        return retVal;
    }
    finally {
        if (target != null && !targetSource.isStatic()) {
            // Must have come from TargetSource.
            targetSource.releaseTarget(target);
        }
        if (setProxyContext) {
            // Restore old proxy.
            AopContext.setCurrentProxy(oldProxy);
        }
    }
}
           

上面的方法裡使用了ReflectiveMethodInvocation類,進行鍊和被代理方法的調用的控制。那麼它到底是怎麼進行控制的呢?

下面是ReflectiveMethodInvocation類Proceed方法:

public Object proceed() throws Throwable {
    //  We start with an index of -1 and increment early.
    // 首先,判斷是不是所有的interceptor(也可以想像成advisor)都被執行完了。
    // 判斷的方法是看currentInterceptorIndex這個變量的值,增加到Interceptor總個數這個數值沒有,
    // 如果到了,就執行被代理方法(invokeJoinpoint());如果沒到,就繼續執行Interceptor。
    if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - ) {
        return invokeJoinpoint();
    }

    // 如果Interceptor沒有被全部執行完,就取出要執行的Interceptor,并執行。
    Object interceptorOrInterceptionAdvice =
this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
    // 如果Interceptor是PointCut類型
    if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
        // Evaluate dynamic method matcher here: static part will already have
        // been evaluated and found to match.
        InterceptorAndDynamicMethodMatcher dm =
                (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
        // 如果目前方法符合Interceptor的PointCut限制,就執行Interceptor
        if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
            return dm.interceptor.invoke(this);
        }
        // 如果不符合,就跳過目前Interceptor,執行下一個Interceptor
        // 這裡是遞歸執行proceed方法,currentInterceptorIndex的值一直在增加
        // 當currentInterceptorIndex值達到了方法最大的界限的話,就會從遞歸最裡層的proceed方法一層層傳回來。
        else {
            // Dynamic matching failed.
            // Skip this interceptor and invoke the next in the chain.
            return proceed();
        }
    }
    // 如果Interceptor不是PointCut類型,就直接執行Interceptor裡面的增強。
    else {
        // It's an interceptor, so we just invoke it: The pointcut will have
        // been evaluated statically before this object was constructed.
        return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
    }
}
           

看完上面的代碼,思考一下,可能會有兩個問題。

1,我們定義增加時,可以定義很多種,比如前置增加BeforeAdvice,後置增強等。在這個方法裡隻看到了調用Interceptor(也就是Advisor),是在哪裡控制這些增強的調用順序的呢?比如,先調用前置增強,再調用被代理方法,再調用後置增強等。

2,增強調用完後,是如何調用下一個增強的呢?上面的代碼中,調用完增強後,就傳回了。

上面問題的答案可以在MethodInterceptor的實作類裡找到,我們拿MethodBeforeAdviceInterceptor為例子。

從下面代碼可以看出來,當invoke方法被調用時,首先調用的是前置增強,然後再調用MethodInvocation的proceed方法,也就是我們上面介紹的proceed方法。這個MethodInvocation的引用,就是在ReflectiveMethodInvocation調用interceptor時,把自己傳了過來。在Interceptor裡調用proceed方法的意思是告訴MethodInvocation,

我(增強)執行完了,你繼續吧

,接下來是繼續執行其它增強,還是執行被代理方法,就由上面的ReflectiveMethodInvocation邏輯判斷了。

public class MethodBeforeAdviceInterceptor implements MethodInterceptor, Serializable {

    private MethodBeforeAdvice advice;


    /**
     * Create a new MethodBeforeAdviceInterceptor for the given advice.
     * @param advice the MethodBeforeAdvice to wrap
     */
    public MethodBeforeAdviceInterceptor(MethodBeforeAdvice advice) {
        Assert.notNull(advice, "Advice must not be null");
        this.advice = advice;
    }

    @Override
    public Object invoke(MethodInvocation mi) throws Throwable {
        this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis() );
        return mi.proceed();
    }
}
           

AfterReturningAdviceInterceptor的invoke方法代碼如下:

@Override
public Object invoke(MethodInvocation mi) throws Throwable {
    Object retVal = mi.proceed();
    this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());
    return retVal;
}
           

假設一共有兩個Interceptor

1, Interceptor1:前置增強

2, Interceptor2:後置增強

  • 1, ReflectiveMethodInvocation:判斷Interceptor沒執行完,執行Interceptor1
    • 2, Inerceptor1:執行前置增強,然後執行MethodInvocation的proceed方法。
      • 3, ReflectiveMethodInvocation:判斷Interceptor沒執行完,執行Interceptor2
        • 4, Interceptor2:執行MethodInvocation的proceed方法(後置增強還沒有執行)
          • 5, ReflectiveMethodInvocation:判斷所有Interceptor都執行完了,執行目标方法。目标方法執行完後,回到Interceptor2調用proceed方法的地方。
        • 6, Interceptor2:調用proceed傳回後,繼續調用後面的後置增強。後置增強執行完後,回到MethodInvocation調用Interceptor2的地方
      • 7, ReflectiveMethodInvocation:調用Interceptor2完成傳回後,因為沒有其它(Intercetpor或目标方法)要執行,是以回到Interceptor1調用proceed方法的地方
    • 8, Interceptor1:調用的proceed方法傳回後,因為沒有其它要執行的了,是以回到MethodInvocation調用Interceptor1的地方
  • 9, ReflectiveMethodInvocation:調用Interceptor1完成傳回後,因為沒有其它(Intercetpor或目标方法)要執行,是以回到最初調用proceed方法的地方

ReflectiveMethodInvocation判斷還有Interceptor沒執行完,執行Interceptor1

Interceptor1執行完後,告訴ReflectiveMethodInvocation“我執行完了”,你繼續吧

ReflectiveMethodInvocation判斷還有Interceptor沒執行完,執行Interceptor2

Interceptor2執行完後,告訴ReflectiveMethodInvocation“我執行完了”,你繼續吧

ReflectiveMethodInvocation判斷Interceptor都執行完了,執行代理方法

回到Interceptor2調用執行完後,告訴ReflectiveMethodInvocation“我執行完了”,你繼續吧

在這種結構的控制下,不管在proceed裡調用Interceptor裡面的邏輯是前置增強處理,還是後置增強處理,都可以達到:

所有前置增強執行 -> 被代理方法執行 -> 所有的後置增強執行

的調用順序,是以這個設定還是挺巧妙的。

這種設計還有一個好處,因為這種設計把前置後置增強的調用順序控制,放到了各個增強用的Interceptor裡了,沒有放到proceed方法裡,是以當有新的增強類型出來的話,把調用順序控制放到新的增強的Interceptor裡就好了,不用修改現有的類,例如proceed方法。

為什麼執行代理Chain的時候,每個Chain裡的元素都要是MethodInterceptor類型的呢?

因為“Aop聯盟”定義了一套AOP的接口,而且還定義的接口的調用規則,而且還起草了AOP的一些元件和運作方式。

比如,定義了Interceptor Framework,Reflection,Metadata Handling(應該是注解處理),Class Loading Framework等。

拿我們遇到的接口舉例:

  • Joinpoint:定義了proceed()等方法,proceed這個方法的作用是調用下一個interceptor。
  • MethodInterceptor:定義了invoke(MethodInvocation invocation)方法。
  • MethodInvocation:實作了Joinpoint接口。根據定義來說,這個接口是一個“jointpoint(就是被攔截的方法/對象)”,什麼樣的JointPoint呢?

    可以被攔截到的JointPoint。

看Spring的代碼,被攔截方法的調用和Interceptor Chain的調用都是在這裡控制的。是以可以看出Joinpoint接口是定義Advice,MethodInvocation接口是定義執行Advice的接口。在MethodInterceptor的Javadoc裡還寫了下面的說明和用例:

The user should implement the invoke(MethodInvocation) method to modify the original behavior. E.g. the following class implements a tracing interceptor (traces all the calls on the intercepted method(s)):

使用者需要實作 invoke(MethodInvocation) 方法來修改原來的行為。例如,下面類實作了一個tracing interceptor。

class TracingInterceptor implements MethodInterceptor {
   Object invoke(MethodInvocation i) throws Throwable {
     System.out.println("method "+i.getMethod()+" is called on "+
                       i.getThis()+" with args "+i.getArguments());
     Object ret=i.proceed();
     System.out.println("method "+i.getMethod()+" returns "+ret);
     return ret;
   }
 }
           

看了一上面的代碼,是不是和上面說的MethodBeforeAdviceInterceptor還有AfterReturningAdviceInterceptor的實作方式幾乎一樣。這樣應該就可以了解Spring為什麼要這麼做了吧。

Aop聯盟的接口Javadoc如下,有興趣的可以看看。

http://aopalliance.sourceforge.net/doc/index.html

繼續閱讀