Spring AOP核心源码、原理详解后篇

前篇说到DefaultAopProxyFactory创建代理类,现在我们继续跟进代码,看看具体的代理类是如何创建的
JdkDynamicAopProxy类
作用:采用jdk动态代理的方式创建代理对象,并处理代理对象的所有方法调用。

public class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable {
    private static final long serialVersionUID = 5531744639992436476L;
    private static final Log logger = LogFactory.getLog(MyJdkDynamicAopProxy.class);
    //代理的配置信息
    private final AdvisedSupport advised;
    //需要被代理的接口中是否定义了equals方法
    private boolean equalsDefined;
    //需要被代理的接口中是否定义了hashCode方法
    private boolean hashCodeDefined;

    //通过AdvisedSupport创建实例
    public MyJdkDynamicAopProxy(AdvisedSupport config) {

        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");
        } else {
            this.advised = config;
        }

    }


    /**
     * @param classLoader 生成一个代理对象
     * @return 返回代理对象
     */
    @Override
    public Object getProxy(@Nullable ClassLoader classLoader) {
        //根据advised的信息获取代理需要被代理的所有接口列表 @1
        Class<?>[] proxiedInterfaces = completeProxiedInterfaces(this.advised, true);
        //查找被代理的接口中是否定义了equals、hashCode方法
        this.findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
        /*
         * 这个大家应该很熟悉吧,通过jdk动态代理创建代理对象,注意最后一个参数是this
         * 表示当前类,当前类是InvocationHandler类型的,当调用代理对象的任何方法的时候
         * 都会被被当前类的 invoke 方法处理
         */
        return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
    }

 

    /**
     * @param proxiedInterfaces 判断需要代理的接口中是否定义了这几个方法(equals、hashCode)
     */
    private void findDefinedEqualsAndHashCodeMethods(Class<?>[] proxiedInterfaces) {
        Class[] classes = proxiedInterfaces;
        int length = proxiedInterfaces.length;

        for (int i = 0; i < length; ++i) {
            Class<?> proxiedInterface = classes[i];
            //获取接口中定义的方法
            Method[] methods = proxiedInterface.getDeclaredMethods();
            int len = methods.length;

            for (int j = 0; j < len; ++j) {
                Method method = methods[j];
                //是否是equals方法
                if (AopUtils.isEqualsMethod(method)) {
                    //是的话给实例变量 equalsDefined 赋值
                    this.equalsDefined = true;
                }

                //是否是hashCode方法
                if (AopUtils.isHashCodeMethod(method)) {
                    //是的话给实例变量 hashCodeDefined 赋值
                    this.hashCodeDefined = true;
                }

                //如果发现这2个方法都定义了,结束循环查找,已有可能不同的接口定义的
                if (this.equalsDefined && this.hashCodeDefined) {
                    return;
                }
            }
        }

    }

    /**
     * 这个方法比较关键了,当在程序中调用代理对象的任何方法,最终都会被下面这个invoke方法处理
     *
     * @param proxy
     * @param method
     * @param args
     * @return
     * @throws Throwable
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //旧的代理对象
        Object oldProxy = null;
        //用来标记是否需要将代理对象暴露在ThreadLocal中
        boolean setProxyContext = false;
        //获取目标源
        TargetSource targetSource = this.advised.getTargetSource();
        //目标对象
        Object target = null;

        Class<?> clazz;
        //下面进入代理方法的处理阶段
        try {
            //处理equals方法:被代理的接口中没有定义equals方法 && 当前调用是equals方法
            if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
                //直接调用当前类中的equals方法
                return this.equals(args[0]);

            }

            //处理hashCode方法:被代理的接口中没有定义hashCode方法 && 当前调用是 hashCode方法
            else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
                //直接调用当前类中的hashCode方法
                return this.hashCode();
            }

            /*方法来源于 DecoratingProxy 接口,这个接口中定义了一个方法
            用来获取原始的被代理的目标类,主要是用在嵌套代理的情况下(所谓嵌套代理:代理对
            象又被作为目标对象进行了代理)
            */
            else if (method.getDeclaringClass() == DecoratingProxy.class) {
                return AopProxyUtils.ultimateTargetClass(this.advised);
            }

            // todo 方法来源于 Advised 接口,代理对象默认情况下会实现 Advised 接口,可以通过代理对象来动态向代理对象中添加通知等
            else if (!this.advised.isOpaque() && method.getDeclaringClass().isInterface() && method.getDeclaringClass().isAssignableFrom(Advised.class)) {
                //调用AopProxyUtils工具类的方法,内部通过循环遍历的方式,找到最原始的被代 理的目标类
                return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
            }
            //用来记录方法返回值
            Object retVal;
            //是否需要将代理暴露在threadLocal中
            if (this.advised.isExposeProxy()) {
                /**
                 * 将代理对象暴露在上线文中,即暴露在threadLocal中,那么在当前线程中可以通
                 * 过静态方法AopContext#currentProxy获取当前被暴露的代理对象,这个是非常有用的,稍
                 * 后用案例来讲解,瞬间就会明白
                 */
                oldProxy = AopContext.setCurrentProxy(proxy);
                //将setProxyContext标记为true
                setProxyContext = true;
            }

            //通过目标源获取目标对象
            target = targetSource.getTarget();
            //获取目标对象类型
            Class<?> targetClass = target != null ? target.getClass() : null;

            //todo 获取当前方法的拦截器链@2
            List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

            //拦截器链为空的情况下,表示这个方法上面没有找到任何增强的通知,那么会直接通过反射直接调用目标对象
            if (chain.isEmpty()) {
                /*获取方法请求的参数(有时候方法中有可变参数,所谓可变参数就是带有省略号(...)这种格式的参数,传入的参数类型和这种类型不一样的时候,会通过下面的
                adaptArgumentsIfNecessary方法进行转换)*/
                Object[] argsToUse = adaptArgumentsIfNecessary(method, args);
                retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
            } else {
                //如有增强逻辑
                //创建一个方法调用器(包含了代理对象、目标对象、调用的方法、参数、目标类型、方法拦截器链)
                MethodInvocation invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
                //todo 通过拦截器链一个个调用最终到目标方法的调用@3
                retVal = invocation.proceed();
            }
            //下面会根据方法返回值的类型,做一些处理,比如方法返回的类型为自己,则最后需要将返回值置为代理对象
            Class<?> returnType = method.getReturnType();
            if (retVal != null && retVal == target && returnType != Object.class && returnType.isInstance(proxy) && !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
                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 {
            /**
             * 目标对象不为null && 目标源不是静态的  所谓静态的,你可以理解为是否是单例的
             *isStatic为true,表示目标对象是单例的,同一个代理对象中所有方法共享一个目标对象
             * isStatic为false的时候,通常每次调用代理的方法,target对象是不一样的,所以方
             * 法调用完之后需要进行释放,可能有些资源清理,连接的关闭等操作
             */
            if (target != null && !targetSource.isStatic()) {
                targetSource.releaseTarget(target);
            }

            //setProxyContext为ture 的情况
            if (setProxyContext) {
                //需要将旧的代理再放回到上线文中
                AopContext.setCurrentProxy(oldProxy);
            }

        }

    }

    static Object[] adaptArgumentsIfNecessary(Method method, @Nullable Object[] arguments) {
        if (ObjectUtils.isEmpty(arguments)) {
            return new Object[0];
        } else {
            if (!method.isVarArgs() || method.getParameterCount() != arguments.length) {
                return arguments;
            }
            //返回true如果这个可执行文件被宣布为带有可变数量的参数;返回false其他。

            Class<?>[] paramTypes = method.getParameterTypes();
            int varargIndex = paramTypes.length - 1;
            Class<?> varargType = paramTypes[varargIndex];
            if (varargType.isArray()) {
                Object varargArray = arguments[varargIndex];
                if (varargArray instanceof Object[] && !varargType.isInstance(varargArray)) {
                    Object[] newArguments = new Object[arguments.length];
                    System.arraycopy(arguments, 0, newArguments, 0, varargIndex);
                    Class<?> targetElementType = varargType.getComponentType();
                    int varargLength = Array.getLength(varargArray);
                    Object newVarargArray = Array.newInstance(targetElementType, varargLength);
                    System.arraycopy(varargArray, 0, newVarargArray, 0, varargLength);
                    newArguments[varargIndex] = newVarargArray;
                    return newArguments;
                }

            }
            return arguments;
           
        }
    }


    /**
     * @return 生成一个代理对象
     */
    @Override
    public Object getProxy() {
        return this.getProxy(ClassUtils.getDefaultClassLoader());
    }
}

关于上面代码,有几点细说一下
@1:completeProxiedInterfaces方法
代码如下,根据代理配置信息,获取需要被代理的所有接口

/**
 *  
 * @param advised  代理配置信息
 * @param decoratingProxy  默认是true
 * @return  根据advised的信息获取代理需要被代理的所有接口列表
 */
static Class<?>[] completeProxiedInterfaces(AdvisedSupport advised, boolean decoratingProxy) {
    //获取代理配置中需要被代理的接口
    Class<?>[] specifiedInterfaces = advised.getProxiedInterfaces();
    //需要被代理的接口数量为0
    if (specifiedInterfaces.length == 0) {
        //获取需要被代理的目标类型
        Class<?> targetClass = advised.getTargetClass();
        //目标类型不为空
        if (targetClass != null) {
            //目标类型为接口
            if (targetClass.isInterface()) {
                //将其添加到需要代理的接口中
                advised.setInterfaces(new Class[]{targetClass});
                //目标类型为jdk动态代理创建的代理对象
            } else if (Proxy.isProxyClass(targetClass)) {
                //获取目标类型上的所有接口,将其添加到需要被代理的接口中
                advised.setInterfaces(targetClass.getInterfaces());
            }

            //再次获取代理配置中需要被代理的接口
            specifiedInterfaces = advised.getProxiedInterfaces();
        }
    }

    //判断SpringProxy接口是否已经在被代理的接口中
    boolean addSpringProxy = !advised.isInterfaceProxied(SpringProxy.class);
    //判断Advised接口是否已经在被代理的接口中
    boolean addAdvised = !advised.isOpaque() && !advised.isInterfaceProxied(Advised.class);
    //判断DecoratingProxy接口是否已经在被代理的接口中
    boolean addDecoratingProxy = decoratingProxy && !advised.isInterfaceProxied(DecoratingProxy.class);
    //一个计数器,会根据上面三个boolean值做递增
    int nonUserIfcCount = 0;
    if (addSpringProxy) {
        ++nonUserIfcCount;
    }

    if (addAdvised) {
        ++nonUserIfcCount;
    }

    if (addDecoratingProxy) {
        ++nonUserIfcCount;
    }
    //下面就是构建所有需要被代理的接口,最新的接口个数 + 必须实现的三个默认接口
    Class<?>[] proxiedInterfaces = new Class[specifiedInterfaces.length + nonUserIfcCount];
    System.arraycopy(specifiedInterfaces, 0, proxiedInterfaces, 0, specifiedInterfaces.length);
    int index = specifiedInterfaces.length;
    //下面的代码就简单了,将系统默认的三个接口赋值到数组中
    if (addSpringProxy) {
        proxiedInterfaces[index] = SpringProxy.class;
        ++index;
    }

    if (addAdvised) {
        proxiedInterfaces[index] = Advised.class;
        ++index;
    }

    if (addDecoratingProxy) {
        proxiedInterfaces[index] = DecoratingProxy.class;
    }

    //返回的是最终的代理实现的接口
    return proxiedInterfaces;
}

上面的方法执行完毕之后,会得到一个被代理的接口列表,默认情况下会得到下面的一个列表

[开发者硬编码指定的需要被代理的接口列表,SpringProxy,Advised,DecoratingProxy]

最终创建出来的代理对象,默认会实现上面列的所有接口,后面3个接口是aop中自动给我们加上的。

@2:getInterceptorsAndDynamicInterceptionAdvice

这个方法位于 AdvisedSupport 中,根据方法和目标类型获取方法上面匹配的拦截器链

/**
 * 基于当前配置,获取给定方法的方法调用链列表(即
 * org.aopalliance.intercept.MethodInterceptor对象列表)
 *
 * @param method
 * @param targetClass
 * @return
 */
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, Class<?> targetClass) {
    MethodCacheKey methodCacheKey = new MethodCacheKey(method);
    //会先尝试从还中获取,如果获取不到,会从advisorChainFactory中获取,然后将其丢到缓存中
    return this.methodCache.computeIfAbsent(methodCacheKey, m -> this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(
            this, method, targetClass));
}

从advisorChainFactory中获取拦截器链稍后细说,我们把这个阶段叫做连接器链的获取阶段。

@3:ReflectiveMethodInvocation.proceed()
这个是一次会调用拦截器链,最终会调用到目标方法,获得目标方法的返回值,里面的细节见后面的代理方法调用处理阶段
JdkDynamicAopProxy小结

  1. 被创建的代理对象默认会实现 SpringProxy,Advised,DecoratingProxy 3个接口
  2. SpringProxy 这个接口中没有任何方法,只是起一个标记作用,用来标记代理对象是使用spring
    aop创建的
  3. 代理对象默认都会实现 Advised 接口,所以可以通过这个接口动态变更代理对象中的通知
  4. DecoratingProxy 接口中定义了一个方法 getDecoratedClass ,用来获取被代理的原始目标对象的类型

CglibAopProxy类

下面来看另外一个类: ObjenesisCglibAopProxy ,这个继承了 CglibAopProxy ,大部分逻辑都在CglibAopProxy 中,所以我们主要看 CglibAopProxy 中代码。

作用:采用cglib代理的方式创建代理对象,并处理代理对象的所有方法调用。
以 getProxy 方法为入口,通过方法一个个来解说。
getProxy方法

public Object getProxy(@Nullable ClassLoader classLoader) {

    try {
        //获取被代理的类
        Class<?> rootClass = this.advised.getTargetClass();
        Assert.state(rootClass != null, "Target class must be available for creating a CGLIB proxy");
        //代理对象的父类(cglib是采用继承的方式是创建代理对象的,所以将被代理的类作为代理对象的父类)
        Class<?> proxySuperClass = rootClass;
        //判断被代理的类是不是cglib创建的类,如果是cblib创建的类,会将其父类作为被代理的类
        if (rootClass.getName().contains(ClassUtils.CGLIB_CLASS_SEPARATOR)) {
            proxySuperClass = rootClass.getSuperclass();
            Class<?>[] additionalInterfaces = rootClass.getInterfaces();
            //添加需要被代理的接口
            for(Class<?> additionalInterface : additionalInterfaces) {
                this.advised.addInterface(additionalInterface);
            }
        }

        this.validateClassIfNecessary(proxySuperClass, classLoader);
        //开始cglib创建代理,这个大家对cglib比较熟悉的一看就懂
        Enhancer enhancer = this.createEnhancer();
        if (classLoader != null) {
            enhancer.setClassLoader(classLoader);
            if (classLoader instanceof SmartClassLoader && ((SmartClassLoader)classLoader).isClassReloadable(proxySuperClass)) {
                enhancer.setUseCache(false);
            }
        }

        //设置被代理的父类
        enhancer.setSuperclass(proxySuperClass);
        //设置被代理的接口[开发者硬编码指定的需要被代理的接口列表,SpringProxy,Advised],这个比jdk动态代理的方式少了一个DecoratingProxy接口
        enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));
        //设置代理类类名生成策略
        enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
        //设置字节码的生成策略
        enhancer.setStrategy(new ClassLoaderAwareGeneratorStrategy(classLoader));
        //@1:获取Callback列表,这个稍后详解
        Callback[] callbacks = this.getCallbacks(rootClass);
        Class<?>[] types = new Class[callbacks.length];
        for (int i = 0; i < callbacks.length; i++) {
            types[i] = callbacks[i].getClass();
        }
        //@2:设置CallbackFilter,CallbackFilter内部会判断被代理对象中的方法最终会被 callbacks列表中的那个Callback来处理
        enhancer.setCallbackFilter(new CglibAopProxy.ProxyCallbackFilter(this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));
        enhancer.setCallbackTypes(types);
        //获取代理对象(内部会先创建代理类,然后会根据代理类生成一个代理对象)
        return this.createProxyClassAndInstance(enhancer, callbacks);
    } catch (IllegalArgumentException | CodeGenerationException var9) {
        throw new AopConfigException("Could not generate CGLIB subclass of " + this.advised.getTargetClass() + ": Common causes of this problem include using a final class or a non-visible class", var9);
    } catch (Throwable var10) {
        throw new AopConfigException("Unexpected AOP exception", var10);
    }
}

上面方法中有2个点比较难,需要说明,分别是 @1:getCallbacks方法 和 @2:创建
ProxyCallbackFilter对象
@1:getCallbacks方法
通过被代理的类来获取 Callback 列表, Callback 是用来处理代理对象的方法调用的,代理对象中可能有很多方法,每个方法可能采用不同的处理方式,所以会有多个 Callback

/**
 *
 * @param rootClass 根据目标对象
 * @return 返回 Callback[]
 * @throws Exception
 */
private Callback[] getCallbacks(Class<?> rootClass) throws Exception {
    //是否需要将代理暴露在threadLocal中
    boolean exposeProxy = this.advised.isExposeProxy();
    //配置是否是冻结的
    boolean isFrozen = this.advised.isFrozen();
    //被代理的目标对象是否是动态的(是否是单例的)
    boolean isStatic = this.advised.getTargetSource().isStatic();
    //当方法上有需要执行的拦截器的时候,会用这个来处理
    Callback aopInterceptor = new CglibAopProxy.DynamicAdvisedInterceptor(this.advised);
    //当方法上没有需要执行的拦截器的时候,会使用targetInterceptor来处理,内部会通过反射直接调用目标对象的方法
    Object targetInterceptor;

    /*
     * 这块根据是否需要暴露代理到threadLocal中以及目标对象是否是动态的,会创建不同的Callback
     *    isStatic为true的时候,同一个代理的不同方法可能都是新的目标对象,所以当代理方法执行完毕
     * 之后,需要对目标对象进行释放
     */
    if (exposeProxy) {
        targetInterceptor = isStatic ? new CglibAopProxy.StaticUnadvisedExposedInterceptor(this.advised.getTargetSource().getTarget()) : new CglibAopProxy.DynamicUnadvisedExposedInterceptor(this.advised.getTargetSource());
    } else {
        targetInterceptor = isStatic ? new CglibAopProxy.StaticUnadvisedInterceptor(this.advised.getTargetSource().getTarget()) : new CglibAopProxy.DynamicUnadvisedInterceptor(this.advised.getTargetSource());
    }
    //targetDispatcher会直接调用目标方法
    Callback targetDispatcher = isStatic ? new CglibAopProxy.StaticDispatcher(this.advised.getTargetSource().getTarget()) : new CglibAopProxy.SerializableNoOp();
    Callback[] mainCallbacks = new Callback[]{
            aopInterceptor, //处理匹配到拦截器的方法
            (Callback) targetInterceptor,//处理未匹配到拦截器的方法
            new CglibAopProxy.SerializableNoOp(),
            (Callback) targetDispatcher, //处理未匹配到拦截器的方法,和targetInterceptor有何不同呢?
    //目标方法如果返回值的结果是目标对象类型的,会使用 targetInterceptor 处理,内部会返回代理对象
            this.advisedDispatcher,//处理Advised接口中定义的方法
            new CglibAopProxy.EqualsInterceptor(this.advised),//处理equals方法
            new CglibAopProxy.HashCodeInterceptor(this.advised)};//处理hashCode方法
    Callback[] callbacks;
    /*
     * 如果被代理的对象是单例的 && 配置是冻结的,此时会进行优化,怎么优化呢?
     * 配置冻结的情况下,生成好的代理中通知是无法修改的,所以可以提前将每个方法对应的拦截器链找到给缓存起来
     *  调用方法的时候,就直接从缓存中可以拿到方法对应的缓存信息,效率会高一些
     */
    if (isStatic && isFrozen) {
        Method[] methods = rootClass.getMethods();
        Callback[] fixedCallbacks = new Callback[methods.length];
        this.fixedInterceptorMap = new HashMap<>(methods.length);
        //获取每个方法的调用链,然后给缓存在fixedInterceptorMap中
        for (int x = 0; x < methods.length; ++x) {
            Method method = methods[x];
            List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, rootClass);
            fixedCallbacks[x] = new CglibAopProxy.FixedChainStaticTargetInterceptor(chain, this.advised.getTargetSource().getTarget(), this.advised.getTargetClass());
            this.fixedInterceptorMap.put(method, x);
        }

        callbacks = new Callback[mainCallbacks.length + fixedCallbacks.length];
        System.arraycopy(mainCallbacks, 0, callbacks, 0, mainCallbacks.length);
        System.arraycopy(fixedCallbacks, 0, callbacks, mainCallbacks.length, fixedCallbacks.length);
        this.fixedInterceptorOffset = mainCallbacks.length;
    } else {
        callbacks = mainCallbacks;
    }

    return callbacks;
}

@2:创建ProxyCallbackFilter对象
这块重点在于 ProxyCallbackFilter 中的 accept 方法,这个方法会根据目标方法,获取目标对方最后会让callbacks列表中的哪个Callback处理,大家可以看一下源码,比较简单
上面 getCallbacks 方法中涉及到了5个类如下

  • DynamicAdvisedInterceptor
  • StaticUnadvisedExposedInterceptor
  • StaticUnadvisedInterceptor
  • DynamicUnadvisedInterceptor
  • StaticDispatche
    后面4个比较简单,大家可以去看一下源码,主要来看第一个类,基本上代理对象中的大部分自定义的方法都会进入到这个类的 intercept 方法中进行处理,代码如下
private static class DynamicAdvisedInterceptor implements MethodInterceptor, Serializable {
    //代理配置信息
    private final AdvisedSupport advised;

    //构造器,需要一个AdvisedSupport
    public DynamicAdvisedInterceptor(AdvisedSupport advised) {
        this.advised = advised;
    }

    //这个方法是关键,用来处理代理对象中方法的调用
    @Nullable
    public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        //被暴露在threadLocal中旧的代理对象
        Object oldProxy = null;
        //用来标记代理对象是否被暴露在threadLocal中
        boolean setProxyContext = false;
        //目标对象
        Object target = null;
        //目标对象源
        TargetSource targetSource = this.advised.getTargetSource();

        try {
            //代理配置中是否需要将代理暴露在threadLocal中
            if (this.advised.exposeProxy) {
                oldProxy = AopContext.setCurrentProxy(proxy);
                setProxyContext = true;
            }
            //获取目标对象(即被代理的对象)
            target = targetSource.getTarget();
            Class<?> targetClass = target != null ? target.getClass() : null;
            //@1:获取当前方法的拦截器链
            List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

            //记录方法返回值
            Object retVal;
            //拦截器链不为空 && 方法是public类型的
            if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
                //获取方法调用参数
                Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
                //直接调用目标对象的方法
                retVal = methodProxy.invoke(target, argsToUse);
            } else {
                //创建一个方法调用器(包含了代理对象、目标对象、调用的方法、参数、目标类型、方法拦截器链)
                //@2:并执行方法调用器的processd()方法,此方法会一次执行方法调用链,最终会 调用目标方法,获取返回结果
                retVal = (new CglibAopProxy.CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy)).proceed();
            }

            //处理方法返回结果:会根据方法返回值的类型,做一些处理,比如方法返回的类型为自己,则最后需要将返回值置为代理对象
            retVal = CglibAopProxy.processReturnType(proxy, target, method, retVal);
            return retVal;
        } finally {
            // 目标对象不为null && 目标源不是静态的
            //所谓静态的,你可以理解为是否是单例的
            // isStatic为true,表示目标对象是单例的,同一个代理对象中所有方法共享一个目标对象
            // isStatic为false的时候,通常每次调用代理的方法,target对象是不一样的,所以方
            //法调用万之后需要进行释放,可能有些资源清理,连接的关闭等操作
            if (target != null && !targetSource.isStatic()) {
                targetSource.releaseTarget(target);
            }
            //setProxyContext为ture
            if (setProxyContext) {
                //需要将旧的代理再放回到上线文中
                AopContext.setCurrentProxy(oldProxy);
            }

        }

    }
}

上面代码中2个重点: @1 和 @2
@1:获取当前方法的拦截器链,这个在JdkDynamicAopProxy的也有,稍后说。
@2:调用 CglibMethodInvocation.proceed() ,内部会一次调用方法拦截器链,最终会调用目标方法,获取目标方法返回值,这个稍后放在代理方法处理阶段详解。
下面来看一下方法拦截器链的获取。

方法拦截器链的获取
我们在创建代理的时候,增强的代码通常都放在Advise通知中,但是最终调用方法的时候,这些通知都会被转换为MethodInterceptor来执行,调用方法的过程中,需要先获取方法上匹配的所有方法连接器连,然后依次执行,最终会调用到目标方法。在AdvisedSupport#getInterceptorsAndDynamicInterceptionAdvice方法,然后最终会调用
DefaultAdvisorChainFactory#getInterceptorsAndDynamicInterceptionAdvice方法, 获取
方法上匹配的拦截器链。

image.png

DefaultAdvisorChainFactory类
AdvisorChainFactory接口的默认实现

public class DefaultAdvisorChainFactory implements AdvisorChainFactory, Serializable {


    public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Advised config, Method method, @Nullable Class<?> targetClass) {
        /**
         * 获取Advisor适配器注册器,前面我们有提到过一个知识点:所有的Advisor最终都会转换为
         * MethodInterceptor类型的,
         * 然后注册方法调用链去执行,AdvisorAdapterRegistry就是搞这个事情的,
         * 其内部会将非MethodInterceptor类型通知通过适配器转换为MethodInterceptor类型
         */
        AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
        //获取配置中的Advisor列表
        Advisor[] advisors = config.getAdvisors();
        List<Object> interceptorList = new ArrayList<>(advisors.length);
        //获取被调用方法所在类实际的类型
        Class<?> actualClass = targetClass != null ? targetClass : method.getDeclaringClass();
        Boolean hasIntroductions = null;

        //遍历Advisor列表,找到和actualClass和方法匹配的所有方法拦截器(MethodInterceptor)链列表
        for (Advisor advisor : advisors) {
            //判断是否是PointcutAdvisor类型的,这种类型的匹配分为2个阶段,先看类是否匹配,然后再看方法是否匹配
            if (advisor instanceof PointcutAdvisor) {
                PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
                //如果isPreFiltered为ture,表示类以及匹配过,不需要看类是否匹配了
                if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
                    MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
                    boolean match;
                    if (mm instanceof IntroductionAwareMethodMatcher) {
                        if (hasIntroductions == null) {
                            hasIntroductions = hasMatchingIntroductions(advisors, actualClass);
                        }

                        match = ((IntroductionAwareMethodMatcher) mm).matches(method, actualClass, hasIntroductions);
                    } else {
                        //方法是否匹配
                        match = mm.matches(method, actualClass);
                    }

                    //方法匹配
                    if (match) {
                        //通过AdvisorAdapterRegistry的getInterceptors将advisor转换 为MethodInterceptor列表
                        MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
                        //方法是否动态匹配
                        if (mm.isRuntime()) {
                            //轮询连接器,将其包装为InterceptorAndDynamicMethodMatcher对象,后续方法调用的时候可以做动态匹配
                            for (MethodInterceptor interceptor : interceptors) {
                                interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));

                            }
                        } else {
                            interceptorList.addAll(Arrays.asList(interceptors));
                        }
                    }
                }
            } else if (advisor instanceof IntroductionAdvisor) {
                IntroductionAdvisor ia = (IntroductionAdvisor) advisor;
                if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) {
                    Interceptor[] interceptors = registry.getInterceptors(advisor);
                    interceptorList.addAll(Arrays.asList(interceptors));
                }
            } else {
                Interceptor[] interceptors = registry.getInterceptors(advisor);
                interceptorList.addAll(Arrays.asList(interceptors));
            }
        }

        return interceptorList;
    }

    private static boolean hasMatchingIntroductions(Advisor[] advisors, Class<?> actualClass) {
        Advisor[] var2 = advisors;
        int var3 = advisors.length;

        for(int var4 = 0; var4 < var3; ++var4) {
            Advisor advisor = var2[var4];
            if (advisor instanceof IntroductionAdvisor) {
                IntroductionAdvisor ia = (IntroductionAdvisor)advisor;
                if (ia.getClassFilter().matches(actualClass)) {
                    return true;
                }
            }
        }

        return false;
    }
}

下面来看AdvisorAdapterRegistry这个接口
AdvisorAdapterRegistry接口
AdvisorAdapter注册器,AdvisorAdapter可以将Advisor中的Advice适配为MethodInterceptor

package org.springframework.aop.framework.adapter;
public interface AdvisorAdapterRegistry {
    //将一个通知(Advice)包装为Advisor对象
    Advisor wrap(Object advice) throws UnknownAdviceTypeException;
    //根据Advisor获取方法MethodInterceptor列表
    MethodInterceptor[] getInterceptors(Advisor advisor) throwsUnknownAdviceTypeException;
    //注册AdvisorAdapter,AdvisorAdapter可以将Advisor中的Advice适配为
    MethodInterceptor void registerAdvisorAdapter(AdvisorAdapter adapter);
}

DefaultAdvisorAdapterRegistry类
AdvisorAdapterRegistry的默认实现,目前里面做的事情主要是将负责将前置通知,异常通知,后置通知转换为MethodInterceptor类型的,源码比较简单,大家看一下就懂了。

public class DefaultAdvisorAdapterRegistry implements AdvisorAdapterRegistry, Serializable {
    //AdvisorAdapter转换器列表,AdvisorAdapter负责将Advisor中的Advice转换为 MethodInterceptor类型的
    private final List<AdvisorAdapter> adapters = new ArrayList<>(3);

    //默认会注册3个AdvisorAdapter,这3个负责将前置通知,异常通知,后置通知转换为 MethodInterceptor类型的
    public DefaultAdvisorAdapterRegistry() {
        this.registerAdvisorAdapter(new MethodBeforeAdviceAdapter());
        this.registerAdvisorAdapter(new AfterReturningAdviceAdapter());
        this.registerAdvisorAdapter(new ThrowsAdviceAdapter());
    }

    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;
        if (advice instanceof MethodInterceptor) {
            return new DefaultPointcutAdvisor(advice);
        }
        //轮询adapters
        for (AdvisorAdapter adapter : this.adapters) {
            //adapter是否支持适配advice这个通知
            if (adapter.supportsAdvice(advice)) {
                return new DefaultPointcutAdvisor(advice);
            }
        }
        throw new UnknownAdviceTypeException(advice);


    }

    /**
     * 将Advisor对象转换为MethodInterceptor列表,不过通常情况下一个advisor会返回一个
     * MethodInterceptor
     * @param advisor
     * @return
     * @throws UnknownAdviceTypeException
     */
    public MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException {
        List<MethodInterceptor> interceptors = new ArrayList<>(3);
        Advice advice = advisor.getAdvice();
        if (advice instanceof MethodInterceptor) {
            interceptors.add((MethodInterceptor) advice);
        }
        //轮询adapters
        for (AdvisorAdapter adapter : this.adapters) {
            //先看一下adapter是否支持适配advice这个通知
            if (adapter.supportsAdvice(advice)) {
                //如果匹配,这调用适配器的getInterceptor方法将advisor转换为MethodInterceptor
                interceptors.add(adapter.getInterceptor(advisor));
            }
        }
        if (interceptors.isEmpty()) {
            throw new UnknownAdviceTypeException(advisor.getAdvice());
        } else {
            return  interceptors.toArray(new MethodInterceptor[0]);
        }
    }

    public void registerAdvisorAdapter(AdvisorAdapter adapter) {
        this.adapters.add(adapter);
    }
}

AdvisorAdapter接口

package org.springframework.aop.framework.adapter;
public interface AdvisorAdapter {
    //判断这个适配器支持advice这个通知么
    boolean supportsAdvice(Advice advice);
    //获取advisor对应的MethodInterceptor
    MethodInterceptor getInterceptor(Advisor advisor);
}

MethodBeforeAdviceInterceptor类
将 MethodBeforeAdvice 通知适配为 MethodInterceptor 类型的,代码很简单,大家一看就懂。
就是做了一层包装而已,其他两个类不再复述!

package org.springframework.aop.framework.adapter;

import java.io.Serializable;
import org.aopalliance.aop.Advice;
import org.aopalliance.intercept.MethodInterceptor;
import org.springframework.aop.Advisor;
import org.springframework.aop.MethodBeforeAdvice;

class MethodBeforeAdviceAdapter implements AdvisorAdapter, Serializable {
    MethodBeforeAdviceAdapter() {
    }

    public boolean supportsAdvice(Advice advice) {
        return advice instanceof MethodBeforeAdvice;
    }

    public MethodInterceptor getInterceptor(Advisor advisor) {
        MethodBeforeAdvice advice = (MethodBeforeAdvice)advisor.getAdvice();
        return new MethodBeforeAdviceInterceptor(advice);
    }
}

MethodBeforeAdviceInterceptor类
将 MethodBeforeAdvice 通知适配为 MethodInterceptor 类型的,代码很简单,大家一看就懂

public class MethodBeforeAdviceInterceptor implements MethodInterceptor, BeforeAdvice, Serializable {
    private final MethodBeforeAdvice advice;

    public MethodBeforeAdviceInterceptor(MethodBeforeAdvice advice) {
        Assert.notNull(advice, "Advice must not be null");
        this.advice = advice;
    }

    public Object invoke(MethodInvocation mi) throws Throwable {
        //先调用前置通知
        this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
        //然后继续处理连接器连,内部会调用目标方法
        return mi.proceed();
    }
}

代理方法的调用过程(拦截器链的执行)
拦截器链执行过程
到目前,已经获取到代理对象,接着会开始使用这个代理对象,在代理对象上执行一些方法调用,此时会依次调用此方法上的所有MethodInterceptor,最终会调用到目标上对应的方法,执行过程如下图

image.png

jdk动态代理方式创建代理最终会调用 ReflectiveMethodInvocation#proceed 方法。
cglib方式创建的代理最终会调用 CglibAopProxy.CglibMethodInvocation#proceed 方法

下面来看一下这个两个类的代码
ReflectiveMethodInvocation类

public class ReflectiveMethodInvocation implements ProxyMethodInvocation, Cloneable {
    //生成的代理对象
    protected final Object proxy;
    //被代理的目标对象
    @Nullable
    protected final Object target;
    //被调用的方法
    protected final Method method;
    //调用方法传入参数
    protected Object[] arguments;
    //目标对象类型
    @Nullable
    private final Class<?> targetClass;
    @Nullable
    private Map<String, Object> userAttributes;
    /**
     * 当期被调用的方法上匹配的 MethodInterceptor and
     *  InterceptorAndDynamicMethodMatcher 列表
     * 即方法调用链列表
     */
    protected final List<?> interceptorsAndDynamicMethodMatchers;
    //当前正在调用的连接器索引
    private int currentInterceptorIndex = -1;

    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;
    }

    public final Object getProxy() {
        return this.proxy;
    }

    @Nullable
    public final Object getThis() {
        return this.target;
    }

    public final AccessibleObject getStaticPart() {
        return this.method;
    }

    public final Method getMethod() {
        return this.method;
    }

    public final Object[] getArguments() {
        return this.arguments;
    }

    public void setArguments(Object... arguments) {
        this.arguments = arguments;
    }

    /**
     * 这里是重点,用来处理被调用的方法,会递归进行调用,所有的拦截器都执行完毕之后,会通过反射调
     * 用目标方法
     * @return
     * @throws Throwable
     */
    @Nullable
    public Object proceed() throws Throwable {
        //拦截器都执行完毕之后,通过反射调用目标对象中的方法
        if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
            return this.invokeJoinpoint();
        }
        //获取++this.currentInterceptorIndex指定的拦截器
        Object interceptorOrInterceptionAdvice = this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
        /**
         * 判断拦截器是否是InterceptorAndDynamicMethodMatcher,这种表示是动态拦截器,
         * 所谓动态拦截器就是要根据方法的参数的值来判断拦截器是否需要执行
         */
        if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
            InterceptorAndDynamicMethodMatcher dm = (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
            Class<?> targetClass = this.targetClass != null ? this.targetClass : this.method.getDeclaringClass();
            //判断动态拦截器是否需要执行, 执行当前拦截器的调用 否则 直接递归进入下一个拦截器的调用
            return dm.methodMatcher.matches(this.method, targetClass, this.arguments) ? dm.interceptor.invoke(this) : this.proceed();
        } else {
            //执行拦截器的调用
            return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
        }

    }

    @Nullable
    protected Object invokeJoinpoint() throws Throwable {
        return AopUtils.invokeJoinpointUsingReflection(this.target, this.method, this.arguments);
    }
}

ProxyFactory简化代理的创建

上面代理的整个创建过程和使用过程还是挺复杂的,spring在 AdvisedSupport 类的基础上又添加2个子类

  • ProxyCreatorSupport
  • ProxyFactory

通过这2个子类,将步骤稍微简化了一些,这2个类的代码比较简单,上面的如果理解了,看这2个类的代码会非常的轻松,源码这里就不细说了。
ProxyCreatorSupport 用来对代理的创建提供支持,内部添加了 AopProxyFactory 对象的引用,将代理的创建过程给简化了。

下面来一些案例,通过案例理解会更容易一些。

package com.shiguiwu.springmybatis.spring.aop.principle;

import org.springframework.aop.MethodBeforeAdvice;
import org.springframework.aop.framework.ProxyFactory;

import java.lang.reflect.Method;
import java.util.Arrays;

/**
 * @description: 强制使用cg
 * @author: stone
 * @date: Created by 2021/6/9 15:29
 * @version: 1.0.0
 * @pakeage: com.shiguiwu.springmybatis.spring.aop.principle
 */
public class AopCglibTests {

    public static void main(String[] args) {
        ProxyFactory proxyFactory = new ProxyFactory();

        proxyFactory.addAdvice(new MethodBeforeAdvice() {
            @Override
            public void before(Method method, Object[] objects, Object o) throws Throwable {
                System.out.println(method.getName());
            }
        });

        proxyFactory.setTarget(new FunsService());

        Object proxy = proxyFactory.getProxy();

        System.out.println(proxy.getClass());
        Class<?> superclass = proxy.getClass().getSuperclass();
        System.out.println(superclass.getName());

        Class<?>[] interfaces = proxy.getClass().getInterfaces();
        Arrays.stream(interfaces).forEach(System.out::println);
    }
}

通过设置目标对象的代理,默认情况下是采用cglib的代理方式
输出结果如下:

D:\jdk8\bin\java.exe -agentlib:jdwp=transport=dt_socket,address=127.0.0.1:57209,suspend=y,server=n -javaagent:D:\idea\20190304\system\captureAgent\debugger-agent.jar -Dfile.encoding=UTF-8 -classpath "D:\jdk8\jre\lib\charsets.jar;D:\jdk8\jre\lib\deploy.jar;D:\jdk8\jre\lib\ext\access-bridge-64.jar;D:\jdk8\jre\lib\ext\cldrdata.jar;D:\jdk8\jre\lib\ext\dnsns.jar;D:\jdk8\jre\lib\ext\jaccess.jar;D:\jdk8\jre\lib\ext\jfxrt.jar;D:\jdk8\jre\lib\ext\localedata.jar;D:\jdk8\jre\lib\ext\nashorn.jar;D:\jdk8\jre\lib\ext\sunec.jar;D:\jdk8\jre\lib\ext\sunjce_provider.jar;D:\jdk8\jre\lib\ext\sunmscapi.jar;D:\jdk8\jre\lib\ext\sunpkcs11.jar;D:\jdk8\jre\lib\ext\zipfs.jar;D:\jdk8\jre\lib\javaws.jar;D:\jdk8\jre\lib\jce.jar;D:\jdk8\jre\lib\jfr.jar;D:\jdk8\jre\lib\jfxswt.jar;D:\jdk8\jre\lib\jsse.jar;D:\jdk8\jre\lib\management-agent.jar;D:\jdk8\jre\lib\plugin.jar;D:\jdk8\jre\lib\resources.jar;D:\jdk8\jre\lib\rt.jar;G:\workspace\ideaWorkspace\spring-mybatis\target\classes;G:\maven_repository\com\baomidou\mybatis-plus-boot-starter\3.2.0\mybatis-plus-boot-starter-3.2.0.jar;G:\maven_repository\com\baomidou\mybatis-plus\3.2.0\mybatis-plus-3.2.0.jar;G:\maven_repository\com\baomidou\mybatis-plus-extension\3.2.0\mybatis-plus-extension-3.2.0.jar;G:\maven_repository\com\baomidou\mybatis-plus-core\3.2.0\mybatis-plus-core-3.2.0.jar;G:\maven_repository\com\baomidou\mybatis-plus-annotation\3.2.0\mybatis-plus-annotation-3.2.0.jar;G:\maven_repository\com\github\jsqlparser\jsqlparser\2.1\jsqlparser-2.1.jar;G:\maven_repository\org\mybatis\mybatis\3.5.2\mybatis-3.5.2.jar;G:\maven_repository\org\mybatis\mybatis-spring\2.0.2\mybatis-spring-2.0.2.jar;G:\maven_repository\org\springframework\boot\spring-boot-autoconfigure\2.3.11.RELEASE\spring-boot-autoconfigure-2.3.11.RELEASE.jar;G:\maven_repository\org\springframework\boot\spring-boot\2.3.11.RELEASE\spring-boot-2.3.11.RELEASE.jar;G:\maven_repository\org\springframework\boot\spring-boot-starter-jdbc\2.3.11.RELEASE\spring-boot-starter-jdbc-2.3.11.RELEASE.jar;G:\maven_repository\com\zaxxer\HikariCP\3.4.5\HikariCP-3.4.5.jar;G:\maven_repository\org\springframework\spring-jdbc\5.2.15.RELEASE\spring-jdbc-5.2.15.RELEASE.jar;G:\maven_repository\org\springframework\boot\spring-boot-starter-web\2.3.11.RELEASE\spring-boot-starter-web-2.3.11.RELEASE.jar;G:\maven_repository\org\springframework\boot\spring-boot-starter\2.3.11.RELEASE\spring-boot-starter-2.3.11.RELEASE.jar;G:\maven_repository\org\springframework\boot\spring-boot-starter-logging\2.3.11.RELEASE\spring-boot-starter-logging-2.3.11.RELEASE.jar;G:\maven_repository\ch\qos\logback\logback-classic\1.2.3\logback-classic-1.2.3.jar;G:\maven_repository\ch\qos\logback\logback-core\1.2.3\logback-core-1.2.3.jar;G:\maven_repository\org\apache\logging\log4j\log4j-to-slf4j\2.13.3\log4j-to-slf4j-2.13.3.jar;G:\maven_repository\org\apache\logging\log4j\log4j-api\2.13.3\log4j-api-2.13.3.jar;G:\maven_repository\org\slf4j\jul-to-slf4j\1.7.30\jul-to-slf4j-1.7.30.jar;G:\maven_repository\jakarta\annotation\jakarta.annotation-api\1.3.5\jakarta.annotation-api-1.3.5.jar;G:\maven_repository\org\yaml\snakeyaml\1.26\snakeyaml-1.26.jar;G:\maven_repository\org\springframework\boot\spring-boot-starter-json\2.3.11.RELEASE\spring-boot-starter-json-2.3.11.RELEASE.jar;G:\maven_repository\com\fasterxml\jackson\core\jackson-databind\2.11.4\jackson-databind-2.11.4.jar;G:\maven_repository\com\fasterxml\jackson\core\jackson-annotations\2.11.4\jackson-annotations-2.11.4.jar;G:\maven_repository\com\fasterxml\jackson\core\jackson-core\2.11.4\jackson-core-2.11.4.jar;G:\maven_repository\com\fasterxml\jackson\datatype\jackson-datatype-jdk8\2.11.4\jackson-datatype-jdk8-2.11.4.jar;G:\maven_repository\com\fasterxml\jackson\datatype\jackson-datatype-jsr310\2.11.4\jackson-datatype-jsr310-2.11.4.jar;G:\maven_repository\com\fasterxml\jackson\module\jackson-module-parameter-names\2.11.4\jackson-module-parameter-names-2.11.4.jar;G:\maven_repository\org\springframework\boot\spring-boot-starter-tomcat\2.3.11.RELEASE\spring-boot-starter-tomcat-2.3.11.RELEASE.jar;G:\maven_repository\org\apache\tomcat\embed\tomcat-embed-core\9.0.46\tomcat-embed-core-9.0.46.jar;G:\maven_repository\org\glassfish\jakarta.el\3.0.3\jakarta.el-3.0.3.jar;G:\maven_repository\org\apache\tomcat\embed\tomcat-embed-websocket\9.0.46\tomcat-embed-websocket-9.0.46.jar;G:\maven_repository\org\springframework\spring-web\5.2.15.RELEASE\spring-web-5.2.15.RELEASE.jar;G:\maven_repository\org\springframework\spring-beans\5.2.15.RELEASE\spring-beans-5.2.15.RELEASE.jar;G:\maven_repository\org\springframework\spring-webmvc\5.2.15.RELEASE\spring-webmvc-5.2.15.RELEASE.jar;G:\maven_repository\org\springframework\spring-context\5.2.15.RELEASE\spring-context-5.2.15.RELEASE.jar;G:\maven_repository\org\springframework\spring-expression\5.2.15.RELEASE\spring-expression-5.2.15.RELEASE.jar;G:\maven_repository\org\springframework\boot\spring-boot-starter-aop\2.3.11.RELEASE\spring-boot-starter-aop-2.3.11.RELEASE.jar;G:\maven_repository\org\springframework\spring-aop\5.2.15.RELEASE\spring-aop-5.2.15.RELEASE.jar;G:\maven_repository\org\aspectj\aspectjweaver\1.9.6\aspectjweaver-1.9.6.jar;G:\maven_repository\org\springframework\boot\spring-boot-starter-cache\2.3.11.RELEASE\spring-boot-starter-cache-2.3.11.RELEASE.jar;G:\maven_repository\org\springframework\spring-context-support\5.2.15.RELEASE\spring-context-support-5.2.15.RELEASE.jar;G:\maven_repository\mysql\mysql-connector-java\8.0.25\mysql-connector-java-8.0.25.jar;G:\maven_repository\org\springframework\boot\spring-boot-configuration-processor\2.3.11.RELEASE\spring-boot-configuration-processor-2.3.11.RELEASE.jar;G:\maven_repository\org\projectlombok\lombok\1.18.20\lombok-1.18.20.jar;G:\maven_repository\cn\hutool\hutool-all\5.3.7\hutool-all-5.3.7.jar;G:\maven_repository\com\shiguiwu\facade\facade-spring-boot-starter-autoconfigurer\1.0.1-SNAPSHOT\facade-spring-boot-starter-autoconfigurer-1.0.1-SNAPSHOT.jar;G:\maven_repository\org\slf4j\slf4j-api\1.7.30\slf4j-api-1.7.30.jar;G:\maven_repository\org\springframework\spring-core\5.2.15.RELEASE\spring-core-5.2.15.RELEASE.jar;G:\maven_repository\org\springframework\spring-jcl\5.2.15.RELEASE\spring-jcl-5.2.15.RELEASE.jar;G:\maven_repository\org\springframework\boot\spring-boot-starter-data-redis\2.3.11.RELEASE\spring-boot-starter-data-redis-2.3.11.RELEASE.jar;G:\maven_repository\org\springframework\data\spring-data-redis\2.3.9.RELEASE\spring-data-redis-2.3.9.RELEASE.jar;G:\maven_repository\org\springframework\data\spring-data-keyvalue\2.3.9.RELEASE\spring-data-keyvalue-2.3.9.RELEASE.jar;G:\maven_repository\org\springframework\data\spring-data-commons\2.3.9.RELEASE\spring-data-commons-2.3.9.RELEASE.jar;G:\maven_repository\org\springframework\spring-tx\5.2.15.RELEASE\spring-tx-5.2.15.RELEASE.jar;G:\maven_repository\org\springframework\spring-oxm\5.2.15.RELEASE\spring-oxm-5.2.15.RELEASE.jar;G:\maven_repository\io\lettuce\lettuce-core\5.3.7.RELEASE\lettuce-core-5.3.7.RELEASE.jar;G:\maven_repository\io\netty\netty-common\4.1.65.Final\netty-common-4.1.65.Final.jar;G:\maven_repository\io\netty\netty-handler\4.1.65.Final\netty-handler-4.1.65.Final.jar;G:\maven_repository\io\netty\netty-resolver\4.1.65.Final\netty-resolver-4.1.65.Final.jar;G:\maven_repository\io\netty\netty-buffer\4.1.65.Final\netty-buffer-4.1.65.Final.jar;G:\maven_repository\io\netty\netty-codec\4.1.65.Final\netty-codec-4.1.65.Final.jar;G:\maven_repository\io\netty\netty-transport\4.1.65.Final\netty-transport-4.1.65.Final.jar;G:\maven_repository\io\projectreactor\reactor-core\3.3.17.RELEASE\reactor-core-3.3.17.RELEASE.jar;G:\maven_repository\org\reactivestreams\reactive-streams\1.0.3\reactive-streams-1.0.3.jar;G:\maven_repository\io\netty\netty-all\4.1.68.Final\netty-all-4.1.68.Final.jar;D:\JetBrains\IntelliJ IDEA 2019.3.4\lib\idea_rt.jar" com.shiguiwu.springmybatis.spring.aop.principle.AopCglibTests
Connected to the target VM, address: '127.0.0.1:57209', transport: 'socket'
class com.shiguiwu.springmybatis.spring.aop.principle.FunsService$$EnhancerBySpringCGLIB$$9637af49
com.shiguiwu.springmybatis.spring.aop.principle.FunsService
interface org.springframework.aop.SpringProxy
interface org.springframework.aop.framework.Advised
interface org.springframework.cglib.proxy.Factory
Disconnected from the target VM, address: '127.0.0.1:57209', transport: 'socket'

有接口的情况默认会通过jdk动态代理的方式生成代理,下面来看一下。

package com.shiguiwu.springmybatis.spring.aop.principle;

import org.springframework.aop.MethodBeforeAdvice;
import org.springframework.aop.framework.ProxyFactory;

import java.lang.reflect.Method;
import java.util.Arrays;

/**
 * @description: 使用jdk动态代理
 * @author: stone
 * @date: Created by 2021/6/9 15:17
 * @version: 1.0.0
 * @pakeage: com.shiguiwu.springmybatis.spring.aop.principle
 */
public class AopJdkTests {

    public static interface IService {
        void m1(int i);
    }

    public static class Service  implements IService{
      public  void m1(int i) {
            System.out.println("iiiiiiiiii==> " + i);
        }
    }

    public static void main(String[] args) {

        ProxyFactory proxyFactory = new ProxyFactory(new Service());

        proxyFactory.setInterfaces(IService.class);

        proxyFactory.addAdvice(new MethodBeforeAdvice() {

            @Override
            public void before(Method method, Object[] objects, Object o) throws Throwable {
                System.out.println("haha");

            }
        });

        Object proxy = proxyFactory.getProxy();
        IService iService = (IService) proxy;

        iService.m1(1);

        System.out.println(iService.getClass());
        Class<?> superclass = iService.getClass().getSuperclass();
        System.out.println(superclass.getName());

        Class<?>[] interfaces = iService.getClass().getInterfaces();
        Arrays.stream(interfaces).forEach(System.out::println);
    }
}

强制使用cglib代理

//强制使用cglib代理
proxyFactory.setProxyTargetClass(true);

将代理暴露在threadLocal中
目标类

package com.shiguiwu.springmybatis.spring.aop.principle;

import org.springframework.aop.framework.AopContext;

/**
 * @description: aaa
 * @author: stone
 * @date: Created by 2021/6/9 16:23
 * @version: 1.0.0
 * @pakeage: com.shiguiwu.springmybatis.spring.aop.principle
 */
public class Service {
    public int m1() {
        System.out.println("m1 .....");
//        this.m2();
        ((Service)AopContext.currentProxy()).m2();
        return 1;
    }

    public void m2() {
        System.out.println("m2 ......");
    }
}

测试代码

package com.shiguiwu.springmybatis.spring.aop.principle;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.cglib.proxy.MethodProxy;
import sun.java2d.pipe.SpanIterator;

import java.lang.reflect.Method;

/**
 * @description: 暴露到threadLocal中
 * @author: stone
 * @date: Created by 2021/6/9 16:22
 * @version: 1.0.0
 * @pakeage: com.shiguiwu.springmybatis.spring.aop.principle
 */
public class AopThreadLocalTests {

    public static void main(String[] args) {
        ProxyFactory factory = new ProxyFactory();
        Service service = new Service();
        factory.setTarget(service);

        factory.setExposeProxy(true);

        factory.addAdvice(new MethodInterceptor() {
            @Override
            public Object invoke(MethodInvocation methodInvocation) throws Throwable {

                long s = System.nanoTime();
                Object proceed = methodInvocation.proceed();
                System.out.println("执行时间是。。。。:" + (System.nanoTime() - s));
                System.out.println(proceed);
                return proceed;
            }
        });

        Service s = (Service) factory.getProxy();
        s.m1();

    }
}

如果我们不设置这两段代码,m2方法根本得不到增强

//配置代理创建时,将其暴露出去
factory.setExposeProxy(true);
//m1中调用m2的方法需要修改为下面这样
((Service)AopContext.currentProxy()).m2();

这个功能还是挺有用的,以后我估计大家是可以用到的。到此aop源码就告一段落。88

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,417评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,921评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,850评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,945评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,069评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,188评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,239评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,994评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,409评论 1 304
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,735评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,898评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,578评论 4 336
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,205评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,916评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,156评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,722评论 2 363
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,781评论 2 351

推荐阅读更多精彩内容