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[0]);
        }
        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() - 1) {
        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

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值