AOP横切逻辑的执行

AOP横切逻辑的执行主要由一个接口来执行AopProxy,它有两个实现JdkDynamicAopProxy和Cglib2AopProxy,Spring会根据不同的情况选择不同的AopProxy来执行横切逻辑,先来看一下JdkDynamicAopProxy的一个情况:

JdkDynamicAopProxy

看下JdkDynamicAopProxy的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 {
        // equals hashcode等方法处理
        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.
        List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

        // 检查拦截器链是否为空,如果为空,就直接通过反射调用目标对象的方法,避免创建多余的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 {
            // 创建一个MethodInvocation
            invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
            // 通过拦截器链调用切面逻辑
            retVal = invocation.proceed();
        }

        // Massage return value if necessary.
        if (retVal != null && retVal == target && method.getReturnType().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;
        }
        return retVal;
    }
    finally {
        if (target != null && !targetSource.isStatic()) {
            // Must have come from TargetSource.
            targetSource.releaseTarget(target);
        }
        if (setProxyContext) {
            // Restore old proxy.
            AopContext.setCurrentProxy(oldProxy);
        }
    }
}

以上这个方法的重点是:invocation.proceed()方法,这个方法是通过递归的方式来调用拦截器链里面的每一个拦截器,我们看一下这个方法的具体实现:

public Object proceed() throws Throwable {
    // 从-1开始,然后先加
    if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
        // 如果上一次调用的已经是最后一个拦截器,则调用切面逻辑
        return invokeJoinpoint();
    }

    Object interceptorOrInterceptionAdvice =
        this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
    if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
        // 动态方法匹配
        InterceptorAndDynamicMethodMatcher dm =
        (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
        if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
            return dm.interceptor.invoke(this);
        }
        else {
            // 动态方法匹配失败,然后直接调用拦截器链的下一个拦截器
            // Skip this interceptor and invoke the next in the chain.
            return proceed();
        }
    }
    else {
        // 非动态方法匹配,静态方法匹配,之前已经匹配过,这是一个拦截器,直接调用
        return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
    }
}

单看这一段代码还看不出递归影子,看下MethodInterceptor的各个实现类的invoke方法便可以看到,虽然MethodInterceptor的实现类对于invoke方法的具体实现有所不同,然是它们都调用了mi.proceed()这个方法,从而实现对拦截器链的递归调用。

Cglib2AopProxy

Cglib调用横切逻辑的方式和Jdk基本相似,代码上区别在于调用的方法不一样那个,Cglib2AopProxy调用的是其内部类DynamicAdvicedInterceptor中的intercept方法:

public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
    Object oldProxy = null;
    boolean setProxyContext = false;
    Class targetClass = null;
    Object target = null;
    try {
        if (this.advised.exposeProxy) {
            // Make invocation available if necessary.
            oldProxy = AopContext.setCurrentProxy(proxy);
            setProxyContext = true;
        }
        // May be <code>null</code>. Get as late as possible to minimize the time we
        // "own" the target, in case it comes from a pool.
        target = getTarget();
        if (target != null) {
            targetClass = target.getClass();
        }
        List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
        Object retVal;
        // 检查是否只是有一个InvokerInterceptor:没有真正的Advice,直接反射调用目标方法
        if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
            // 跳过创建MethodInvocation的步骤:直接调用目标方法
            // 注意最后一个invoker必须使一个InvokerInterceptor,这样我们才能知道它并没有做任何事情,只是对目标做了一个反射操作
            retVal = methodProxy.invoke(target, args);
        }
        else {
            // 创建一个MethodInvocation并调用
            retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
        }
        retVal = massageReturnTypeIfNecessary(proxy, target, method, retVal);
        return retVal;
    }
    finally {
        if (target != null) {
            releaseTarget(target);
        }
        if (setProxyContext) {
            // Restore old proxy.
            AopContext.setCurrentProxy(oldProxy);
        }
    }
}

从这段代码中可以看出,Cglib2AopProxy是创建了一个CglibMethodInvocation并调用其proceed()方法,而CglibMethodInvocation是继承了RefectiveMethodInvocation,所以最后还是调用了ReflectiveMethodInvocation的proceed()方法。但是CglibMethodInvocation重写了ReflectiveMethodInvocation的invokeJoinpoint()方法,按照作者写的注释似乎能带来微小的性能提升:

/**
 * Gives a marginal performance improvement versus using reflection to
 * invoke the target when invoking public methods.
 */
protected Object invokeJoinpoint() throws Throwable {
    if (this.protectedMethod) {
        return super.invokeJoinpoint();
    }
    else {
        return this.methodProxy.invoke(this.target, this.arguments);
    }
}