Spring AOP 代理创建流程与执行流程

Spring Aop 代理创建方式:https://www.cnblogs.com/jhxxb/p/14097866.html

最后都会走到 ProxyCreatorSupport#createAopProxy 中,拿到 AopProxy,然后调用 getProxy 方法获取代理对象

public class ProxyCreatorSupport extends AdvisedSupport {
    protected final synchronized AopProxy createAopProxy() {
        if (!this.active) {
            activate();
        }
        return getAopProxyFactory().createAopProxy(this);
    }

DefaultAopProxyFactory

createAopProxy 方法,它的唯一实现为 DefaultAopProxyFactory

/**
 * 默认情况下,实现了接口,就使用 JDK 动态代理,没有就使用 CGLIB
 */
public class DefaultAopProxyFactory implements AopProxyFactory, Serializable {
    @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() || Proxy.isProxyClass(targetClass)) {
                return new JdkDynamicAopProxy(config);
            }
            return new ObjenesisCglibAopProxy(config);
        } else {
            return new JdkDynamicAopProxy(config);
        }
    }

    /**
     * Determine whether the supplied {@link AdvisedSupport} has only the {@link org.springframework.aop.SpringProxy} interface specified (or no proxy interfaces specified at all).
     */
    private boolean hasNoUserSuppliedProxyInterfaces(AdvisedSupport config) {
        Class<?>[] ifcs = config.getProxiedInterfaces();
        return (ifcs.length == 0 || (ifcs.length == 1 && SpringProxy.class.isAssignableFrom(ifcs[0])));
    }
}

AopProxy 有两个实现类,通过 getProxy 方法创建代理对象

JdkDynamicAopProxy

/**
 * 实现了 InvocationHandler,所以处理器就是自己。会实现 invoke 方法
 * 是 final 类,默认是 package 的访问权限
 */
final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable {

    /**
     * 保存这个 AOP 代理所有的配置信息,包括所有的增强器等等
     */
    private final AdvisedSupport advised;

    // 标记 equals 和 hashCode 方法是否定义在了接口上
    private boolean equalsDefined;
    private boolean hashCodeDefined;

    public JdkDynamicAopProxy(AdvisedSupport config) throws AopConfigException {
        Assert.notNull(config, "AdvisedSupport must not be null");
        // 内部再校验一次:必须有至少一个增强器和目标实例才行
        if (config.getAdvisors().length == 0 && config.getTargetSource() == AdvisedSupport.EMPTY_TARGET_SOURCE) {
            throw new AopConfigException("No advisors and no TargetSource specified");
        }
        this.advised = config;
    }


    @Override
    public Object getProxy() {
        return getProxy(ClassUtils.getDefaultClassLoader());
    }

    /**
     * 真正创建 JDK 动态代理实例的地方
     */
    @Override
    public Object getProxy(@Nullable ClassLoader classLoader) {
        if (logger.isTraceEnabled()) {
            logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource());
        }
        // 这部很重要,就是去找接口,我们看到最终代理的接口就是这里返回的所有接口们(除了我们自己的接口,还有 Spring 默认的一些接口)大致过程如下:
        // 1、获取目标对象自己实现的接口们(最终肯定都会被代理的)
        // 2、是否添加 SpringProxy 接口:目标对象实现对就不添加了,没实现过就添加 true
        // 3、是否新增 Adviced 接口,注意不是 Advice 通知接口。实现过就不实现了,没实现过并且 advised.isOpaque()=false 就添加(默认是会添加的)
        // 4、是否新增 DecoratingProxy 接口(Spring4.3 后才提供)。传入的参数 decoratingProxy 为 true,并且没实现过就添加(显然这里,首次进来是会添加的)
        // 5、代理类的接口一共是目标对象的接口加上面三个接口 SpringProxy、Advised、DecoratingProxy(SpringProxy 是个标记接口而已,其余的接口都有对应的方法的)
        Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
        findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
        // 第三个参数传的 this,处理器就是自己,到此一个代理对象就此 new 出来了
        return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
    }

    /**
     * 看接口里有没有自己定义 equals 和 hashCode方法,这个很重要,然后标记一下
     */
    private void findDefinedEqualsAndHashCodeMethods(Class<?>[] proxiedInterfaces) {
        for (Class<?> proxiedInterface : proxiedInterfaces) {
            Method[] methods = proxiedInterface.getDeclaredMethods(); // 此处用的是 getDeclaredMethods,只会找自己的
            for (Method method : methods) {
                if (AopUtils.isEqualsMethod(method)) {
                    this.equalsDefined = true;
                }
                if (AopUtils.isHashCodeMethod(method)) {
                    this.hashCodeDefined = true;
                }
                if (this.equalsDefined && this.hashCodeDefined) { // 两个都找到了就没必要继续循环
                    return;
                }
            }
        }
    }

    /**
     * 对于这部分代码和采用 CGLIB 的大部分逻辑都是一样的,Spring 对此的解释很有意思:
     * 本来是可以抽取出来的,使得代码看起来更优雅。但是因为此会带来 10% 的性能损耗,所以 Spring 最终采用了粘贴复制的方式各用一份
     * Spring 说它提供了基础的套件,来保证两个的执行行为是一致的。
     * proxy:指的是我们所代理的那个真实对象;method:指的是我们所代理的那个真实对象的某个方法的 Method 对象;args:指的是调用那个真实对象方法的参数。
     */
    @Override
    @Nullable
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object oldProxy = null;
        boolean setProxyContext = false;

        // 进入 invoke 方法后,最终操作的是 targetSource 对象
        // 因为 InvocationHandler 持久的就是 targetSource,最终通过 getTarget 拿到目标对象
        TargetSource targetSource = this.advised.targetSource;
        Object target = null;

        try {
            // “通常情况” Spring AOP 不会对 equals、hashCode 方法进行拦截增强,所以此处做了处理
            // equalsDefined 为 false(表示自己没有定义过 eequals 方法),那就交给代理去比较
            // hashCode 同理,只要你自己没有实现过此方法,那就交给代理
            // 需要注意的是:这里统一指的是,如果接口上有此方法,但是你自己并没有实现 equals 和 hashCode 方法,那就走 AOP 这里的实现
            // 如果接口上没有定义此方法,只是实现类里自己 @Override 了 HashCode,那是无效的,就是普通执行
            if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
                return equals(args[0]);
            } else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
                return hashCode();
            }
            // DecoratingProxy 的方法和 Advised 接口的方法,都是最终调用了 config,也就是 this.advised 去执行的
            else if (method.getDeclaringClass() == DecoratingProxy.class) {
                return AopProxyUtils.ultimateTargetClass(this.advised);
            } else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
                    method.getDeclaringClass().isAssignableFrom(Advised.class)) {
                return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
            }

            Object retVal; // 这个是最终该方法的返回值

            // 是否暴露代理对象,默认 false 可配置为 true,如果暴露就意味着允许在线程内共享代理对象,
            // 注意这是在线程内,也就是说同一线程的任意地方都能通过 AopContext 获取该代理对象,这应该算是比较高级一点的用法了。
            if (this.advised.exposeProxy) {
                // 这里缓存一份代理对象在 oldProxy 里,后面有用
                oldProxy = AopContext.setCurrentProxy(proxy);
                setProxyContext = true;
            }

            // 通过目标源获取目标对象(此处 Spring 建议获取目标对象靠后获取,而不是放在上面)
            target = targetSource.getTarget();
            Class<?> targetClass = (target != null ? target.getClass() : null);

            // 获取作用在这个方法上的所有拦截器链,参见 DefaultAdvisorChainFactory#getInterceptorsAndDynamicInterceptionAdvice 方法
            // 会根据切点表达式去匹配这个方法。因此其实每个方法都会进入这里,只是有很多方法的 chain 是 Empty 而已
            List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

            if (chain.isEmpty()) {
                // 若拦截器为空,那就直接调用目标方法了
                // 对参数进行适配:主要处理一些数组类型的参数,看是表示一个参数,还是表示多个参数(可变参数最终到此都是数组类型,所以最好是需要一次适配)
                Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
                // 直接调用目标方法
                retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
            } else {
                // 创建一个 invocation ,此处为 ReflectiveMethodInvocation 最终是通过它,去执行前置加强、后置加强等等逻辑
                MethodInvocation invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
                // 此处会执行所有的拦截器链,交给 AOP 联盟的 MethodInvocation 去处理。当然实现还是 Spring 的 ReflectiveMethodInvocation
                retVal = invocation.proceed();
            }

            // 获取返回值的类型
            Class<?> returnType = method.getReturnType();
            if (retVal != null && retVal == target &&
                    returnType != Object.class && returnType.isInstance(proxy) &&
                    !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
                // 一些列的判断条件,如果返回值不为空,且为目标对象的话,就直接将目标对象赋值给 retVal
                retVal = proxy;
            } else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) { // 返回 null,且还不是 Void 类型,就抛错
                throw new AopInvocationException("Null return value from advice does not match primitive return type for: " + method);
            }
            return retVal;
        } finally {
            if (target != null && !targetSource.isStatic()) { // 释放
                targetSource.releaseTarget(target);
            }
            if (setProxyContext) { // 把老的代理对象重新 set 进去
                AopContext.setCurrentProxy(oldProxy);
            }
        }
    }

    /**
     * AOP 帮我们实现的 equals 方法
     */
    @Override
    public boolean equals(@Nullable Object other) {
        if (other == this) {
            return true;
        }
        if (other == null) {
            return false;
        }

        JdkDynamicAopProxy otherProxy;
        if (other instanceof JdkDynamicAopProxy) {
            otherProxy = (JdkDynamicAopProxy) other;
        } else if (Proxy.isProxyClass(other.getClass())) {
            InvocationHandler ih = Proxy.getInvocationHandler(other);
            if (!(ih instanceof JdkDynamicAopProxy)) {
                return false;
            }
            otherProxy = (JdkDynamicAopProxy) ih;
        } else {
            return false;
        }

        return AopProxyUtils.equalsInProxy(this.advised, otherProxy.advised);
    }

    /**
     * AOP 帮我们实现的 hashCode 方法
     */
    @Override
    public int hashCode() {
        return JdkDynamicAopProxy.class.hashCode() * 13 + this.advised.getTargetSource().hashCode();
    }
}

除了实现类里自己写的方法(接口上没有),其余方法统一都会进入代理的 invoke() 方法里面。只是 invoke 上做了很多特殊处理,比如 DecoratingProxy 和 Advised 等的方法,都是直接执行了。

object 的方法中,toString() 方法会被增强。

ObjenesisCglibAopProxy

/**
 * 继承自 CglibAopProxy,它只重写了 createProxyClassAndInstance 方法
 */
class ObjenesisCglibAopProxy extends CglibAopProxy {

    private static final Log logger = LogFactory.getLog(ObjenesisCglibAopProxy.class);

    // 另外一种创建实例的方式,可以不用空的构造函数
    private static final SpringObjenesis objenesis = new SpringObjenesis();

    public ObjenesisCglibAopProxy(AdvisedSupport config) {
        super(config);
    }

    @Override
    protected Object createProxyClassAndInstance(Enhancer enhancer, Callback[] callbacks) { // 创建一个代理得实例
        Class<?> proxyClass = enhancer.createClass();
        Object proxyInstance = null;

        if (objenesis.isWorthTrying()) { // 如果为 true,就采用 objenesis 去 new 一个实例
            try {
                proxyInstance = objenesis.newInstance(proxyClass, enhancer.getUseCache());
            } catch (Throwable ex) {
                logger.debug("Unable to instantiate proxy using Objenesis, falling back to regular proxy construction", ex);
            }
        }

        if (proxyInstance == null) { // 若果还为 null,就再去拿构造函数(指定参数的)
            try {
                Constructor<?> ctor = (this.constructorArgs != null ? proxyClass.getDeclaredConstructor(this.constructorArgTypes) : proxyClass.getDeclaredConstructor());
                // 通过此构造函数去 new 一个实例
                ReflectionUtils.makeAccessible(ctor);
                proxyInstance = (this.constructorArgs != null ? ctor.newInstance(this.constructorArgs) : ctor.newInstance());
            } catch (Throwable ex) {
                throw new AopConfigException("Unable to instantiate proxy using Objenesis, and regular proxy instantiation via default constructor fails as well", ex);
            }
        }

        ((Factory) proxyInstance).setCallbacks(callbacks);
        return proxyInstance;
    }
}

父类 CglibAopProxy

class CglibAopProxy implements AopProxy, Serializable {

    /**
     * 它的两个 getProxy() 相对来说比较简单,就是使用 CGLIB 的方式,利用 Enhancer 创建了一个增强的实例
     * 这里面比较复杂的地方在:getCallbacks() 这步是比较繁琐的
     * setCallbackFilter 就是看看哪些方法需要拦截,哪些不需要
     */
    @Override
    public Object getProxy() {
        return getProxy(null);
    }

    // CGLIB 重写的两个方法
    @Override
    public boolean equals(@Nullable Object other) {
        return (this == other || (other instanceof CglibAopProxy && AopProxyUtils.equalsInProxy(this.advised, ((CglibAopProxy) other).advised)));
    }

    @Override
    public int hashCode() {
        return CglibAopProxy.class.hashCode() * 13 + this.advised.getTargetSource().hashCode();
    }

    /**
     * 最后,所有的被代理的类的所有的方法调用,都会进入 DynamicAdvisedInterceptor#intercept 这个方法里面来(相当于 JDK 动态代理的 invoke 方法)
     * 它实现了 MethodInterceptor 接口
     */
    private static class DynamicAdvisedInterceptor implements MethodInterceptor, Serializable {

        private final AdvisedSupport advised;

        public DynamicAdvisedInterceptor(AdvisedSupport advised) {
            this.advised = advised;
        }

        @Override
        @Nullable
        public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
            Object oldProxy = null;
            boolean setProxyContext = false;
            Object target = null;
            // 目标对象源
            TargetSource targetSource = this.advised.getTargetSource();
            try {
                if (this.advised.exposeProxy) {
                    oldProxy = AopContext.setCurrentProxy(proxy);
                    setProxyContext = true;
                }
                // 拿到目标对象,这里就是使用 targetSource 的意义,它提供多个实现类,从而实现了更多的可能性
                // 比如:SingletonTargetSource、HotSwappableTargetSource、PrototypeTargetSource、ThreadLocalTargetSource 等
                target = targetSource.getTarget();
                Class<?> targetClass = (target != null ? target.getClass() : null);
                // 一样的,也是拿到和这个方法匹配的所有增强器和通知,和 JDK Proxy 中是一样的
                List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
                Object retVal;
                if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) { // 没有增强器,同时该方法是 public 的,就直接调用目标方法(不拦截)
                    Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
                    retVal = methodProxy.invoke(target, argsToUse);
                } else {
                    // CglibMethodInvocation 这里采用的是 CglibMethodInvocation,它是 ReflectiveMethodInvocation 的子类,到这里就和 JDK Proxy 保持一致了
                    retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
                }
                retVal = processReturnType(proxy, target, method, retVal);
                return retVal;
            } finally {
                if (target != null && !targetSource.isStatic()) {
                    targetSource.releaseTarget(target);
                }
                if (setProxyContext) {
                    AopContext.setCurrentProxy(oldProxy);
                }
            }
        }

        @Override
        public boolean equals(@Nullable Object other) {
            return (this == other || (other instanceof DynamicAdvisedInterceptor && this.advised.equals(((DynamicAdvisedInterceptor) other).advised)));
        }

        @Override
        public int hashCode() {
            return this.advised.hashCode();
        }
    }

    private static class CglibMethodInvocation extends ReflectiveMethodInvocation {

和 JDK 的一样,Object 的方法,只有 toString() 会被拦截(执行通知)

生成出来的代理对象,Spring 默认都给你实现了接口:SpringProxy、Advised

和 JDK 不同的是,比如 equals 和 hashCode 等方法根本就不会进入 intecept 方法,而是在 getCallbacks() 那里就给特殊处理掉了

总结

关于 final 方法

  • JDK 代理:因为接口的方法不能使用 final 关键字,所以编译器就过不去
  • CGLIB 代理:final 修饰某个方法后,不报错。但也不会拦截了

关于 static 方法

  • JDK 代理:static 修饰接口上的方法,要求有 body 体(JDK8 后支持)。但是因为子类不能 @Override了,所以编译就报错了
  • CGLIB 代理:父类方法用 static 修饰后,子类也是无法进行重写的。因此不报错,但也不会拦截了

关于非 public 方法

  • JDK 代理:接口中的方法都是 public的,所以对于它不存在这种现象
  • CGLIB 代理:记住结论,只有 private 的方法不能被代理(因为子类无法访问),其余的访问权限级别的,都能够被正常代理

使用 JDK 动态代理的入口方法是 JdkDynamicAopProxy.invoke() 方法,使用 CGLIB 动态代理入口方法是 DynamicAdvisedInterceptor.intercept() 方法

JDK 动态代理使用的 MethodInvocation 是: ReflectiveMethodInvocation,CGLIB 动态代理使用的是 CglibMethodInvocation,它俩都是 ProxyMethodInvocation 接口的实现类。且 CglibMethodInvocation 继承自 ReflectiveMethodInvocation

CGLib 更适合代理不需要频繁实例化的类,而 Spring 绝大多数 Bean 都是单例的,因此在 Spring AOP 中推荐使用 CGLib,它的功能更强大些


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

原文地址:https://www.cnblogs.com/jhxxb/p/14098181.html