23.spring系列- aop原理理解-2

根据配置获取AopProxy

这个阶段对应的代码:

// 创建AopProxy使用了简单工厂模式
AopProxyFactory aopProxyFactory = new DefaultAopProxyFactory();
//通过AopProxy工厂获取AopProxy对象
AopProxy aopProxy = aopProxyFactory.createAopProxy(advisedSupport);

此阶段会根据AdvisedSupport中配置信息,判断具体是采用cglib的方式还是采用jdk动态代理的方式获取代理对象,先看一下涉及到的一些类。
在这里插入图片描述AopProxy接口

这个接口定义了一个方法,用来创建最终的代理对象,这个接口有2个实现类:

  • CglibAopProxy:采用cglib的方式创建代理对象
  • JkdDynamicAopProxy:采用jdk动态代理的方式创建代理对象
public interface AopProxy {

    /**
     * 创建一个新的代理对象
     */
    Object getProxy();

    /**
     * 创建一个新的代理对象
     */
    Object getProxy(@Nullable ClassLoader classLoader);

}

AopProxyFactory接口

通过名称就可以看出来,是一个工厂,负责创建AopProxy,使用的是简单工厂模式。

public interface AopProxyFactory {
    /**
     * 根据aop配置信息获取AopProxy对象
     */
    AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException;
}

DefaultAopProxyFactory类

AopProxyFactory接口的默认实现,代码比较简单,我们来细看一下:

/**
 * 默认AopProxyFactory实现,创建CGLIB代理或JDK动态代理。
 * 对于给定的AdvisedSupport实例,以下条件为真,则创建一个CGLIB代理:
 * optimize = true
 * proxyTargetClass = true
 * 未指定代理接口
 * 通常,指定proxyTargetClass来强制执行CGLIB代理,或者指定一个或多个接口来使用JDK动态代理。
 */
public class DefaultAopProxyFactory implements AopProxyFactory, Serializable {

    @Override
    public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
        // optimize==true || proxyTargetClass 为true || 配置中没有需要代理的接口
        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.");
            }
            //如果被代理的类为接口 或者 被代理的类是jdk动态代理创建代理类,则采用JdkDynamicAopProxy的方式,否则采用cglib代理的方式
            if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
                //采用jdk动态代理的方式
                return new JdkDynamicAopProxy(config);
            }
            //采用cglib代理的方式
            return new ObjenesisCglibAopProxy(config);
        }
        else {
            //采用jdk动态代理的方式
            return new JdkDynamicAopProxy(config);
        }
    }

    /**
     * 确定所提供的AdvisedSupport是否只指定了SpringProxy接口(或者根本没有指定代理接口)
     */
    private boolean hasNoUserSuppliedProxyInterfaces(AdvisedSupport config) {
        Class<?>[] ifcs = config.getProxiedInterfaces();
        return (ifcs.length == 0 || (ifcs.length == 1 && SpringProxy.class.isAssignableFrom(ifcs[0])));
    }

}

代理创建阶段

到目前为止我们已经根据aop配置信息得到了AopProxy对象了,下面就可以调用AopProxy.getProxy方法获取代理对象了。

AopProxy.createAopProxy方法返回的结果有2种情况:

  • JdkDynamicAopProxy:以jdk动态代理的方式创建代理
  • ObjenesisCglibAopProxy:以cglib的方式创建动态代理

JdkDynamicAopProxy类

作用:采用jdk动态代理的方式创建代理对象,并处理代理对象的所有方法调用。

final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable {

    //代理的配置信息
    private final AdvisedSupport advised;

    //需要被代理的接口中是否定义了equals方法
    private boolean equalsDefined;

    //需要被代理的接口中是否定义了hashCode方法
    private boolean hashCodeDefined;

    //通过AdvisedSupport创建实例
    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());
    }

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

    //判断需要代理的接口中是否定义了这几个方法(equals、hashCode)
    private void findDefinedEqualsAndHashCodeMethods(Class<?>[] proxiedInterfaces) {
        for (Class<?> proxiedInterface : proxiedInterfaces) {
            //获取接口中定义的方法
            Method[] methods = proxiedInterface.getDeclaredMethods();
            for (Method method : methods) {
                //是否是equals方法
                if (AopUtils.isEqualsMethod(method)) {
                    this.equalsDefined = true;
                }
                //是否是hashCode方法
                if (AopUtils.isHashCodeMethod(method)) {
                    this.hashCodeDefined = true;
                }
                //如果发现这2个方法都定义了,结束循环查找
                if (this.equalsDefined && this.hashCodeDefined) {
                    return;
                }
            }
        }
    }


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

        //下面进入代理方法的处理阶段
        try {
            // 处理equals方法:被代理的接口中没有定义equals方法 && 当前调用是equals方法
            if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
                // 直接调用当前类中的equals方法
                return equals(args[0]);
            }
            // 处理hashCode方法:被代理的接口中没有定义hashCode方法 && 当前调用是hashCode方法
            else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
                // 直接调用当前类中的hashCode方法
                return hashCode();
            }
            /**
             * 方法来源于 DecoratingProxy 接口,这个接口中定义了一个方法
             * 用来获取原始的被代理的目标类,主要是用在嵌套代理的情况下(所谓嵌套代理:代理对象又被作为目标对象进行了代理)
             */
            else if (method.getDeclaringClass() == DecoratingProxy.class) {
                // 调用AopProxyUtils工具类的方法,内部通过循环遍历的方式,找到最原始的被代理的目标类
                return AopProxyUtils.ultimateTargetClass(this.advised);
            }
            // 方法来源于 Advised 接口,代理对象默认情况下会实现 Advised 接口,可以通过代理对象来动态向代理对象中添加通知等
            else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
                    method.getDeclaringClass().isAssignableFrom(Advised.class)) {
                // this.advised是AdvisedSupport类型的,AdvisedSupport实现了Advised接口中的所有方法
                // 所以最终通过通过反射方式交给this.advised来响应当前调用
                return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
            }
            // 用来记录方法返回值
            Object retVal;

            //是否需要在threadLocal中暴露代理对象
            if (this.advised.exposeProxy) {
                // 将代理对象暴露在上线文中,即暴露在threadLocal中,那么在当前线程中可以通过静态方法
                // AopContext#currentProxy获取当前被暴露的代理对象,这个是非常有用的,稍后用案例来讲解,瞬间就会明白
                oldProxy = AopContext.setCurrentProxy(proxy);
                // 将setProxyContext标记为true
                setProxyContext = true;
            }

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

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

            // 拦截器链为空的情况下,表示这个方法上面没有找到任何增强的通知,那么会直接通过反射直接调用目标对象
            if (chain.isEmpty()) {
                // 获取方法请求的参数(有时候方法中有可变参数,所谓可变参数就是带有省略号(...)这种格式的参数,传入的参数类型和这种类型不一样的时候,会通过下面的adaptArgumentsIfNecessary方法进行转换)
                Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
                //通过反射直接调用目标方法
                retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
            }
            else {
                // 创建一个方法调用器(包含了代理对象、目标对象、调用的方法、参数、目标类型、方法拦截器链)
                MethodInvocation invocation =
                        new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
                // @2:通过拦截器链一个个调用最终到目标方法的调用
                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;
            }
            // 方法的返回值类型returnType为原始类型(即int、byte、double等这种类型的) && retVal为null,
            // 此时如果将null转换为原始类型会报错,所以此处直接抛出异常
            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中的目标对象
                targetSource.releaseTarget(target);
            }
            // setProxyContext为ture
            if (setProxyContext) {
                // 需要将旧的代理再放回到上线文中
                AopContext.setCurrentProxy(oldProxy);
            }
        }
    }

}

@0:completeProxiedInterfaces方法

@0处的代码如下,根据代理配置信息,获取需要被代理的所有接口

Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true); 

AopProxyUtils.completeProxiedInterfaces 方法源码如下:

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(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中自动给我们加上的。

@1:getInterceptorsAndDynamicInterceptionAdvice

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

public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, @Nullable Class<?> targetClass) {
    //会先尝试从还中获取,如果获取不到,会从advisorChainFactory中获取,然后将其丢到缓存中
    MethodCacheKey cacheKey = new MethodCacheKey(method);
    List<Object> cached = this.methodCache.get(cacheKey);
    if (cached == null) {
        cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(
            this, method, targetClass);
        this.methodCache.put(cacheKey, cached);
    }
    return cached;
}

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

@2:ReflectiveMethodInvocation.proceed()

这个是一次会调用拦截器链,最终会调用到目标方法,获得目标方法的返回值,里面的细节见后面的代理方法调用处理阶段

JdkDynamicAopProxy小结

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

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

CglibAopProxy类

作用:采用cglib代理的方式创建代理对象,并处理代理对象的所有方法调用。

getProxy方法为入口,通过方法一个个来解说。

public Object getProxy(@Nullable ClassLoader classLoader) {
    // 获取被代理的类
    Class<?> rootClass = this.advised.getTargetClass();

    // 代理对象的父类(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);
        }
    }

    // 开始cglib创建代理,这个大家对cglib比较熟悉的一看就懂
    Enhancer enhancer = createEnhancer();
    // 设置被代理的父类
    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 = getCallbacks(rootClass);
    Class<?>[] types = new Class<?>[callbacks.length];
    for (int x = 0; x < types.length; x++) {
        types[x] = callbacks[x].getClass();
    }
    // @2:设置CallbackFilter,CallbackFilter内部会判断被代理对象中的方法最终会被callbacks列表中的那个Callback来处理
    enhancer.setCallbackFilter(new ProxyCallbackFilter(
        this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));
    enhancer.setCallbackTypes(types);

    // 获取代理对象(内部会先创建代理类,然后会根据代理类生成一个代理对象)
    return createProxyClassAndInstance(enhancer, callbacks);
}

上面方法中有2个点比较难,需要说明,分别是@1:getCallbacks方法和@2:创建ProxyCallbackFilter对象

@1:getCallbacks方法

通过被代理的类来获取Callback列表,Callback是用来处理代理对象的方法调用的,代理对象中可能有很多方法,每个方法可能采用不同的处理方式,所以会有多个Callback

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 DynamicAdvisedInterceptor(this.advised);

    // 当方法上没有需要执行的拦截器的时候,会使用targetInterceptor来处理,内部会通过反射直接调用目标对象的方法
    Callback targetInterceptor;
    /**
     * 这块根据是否需要暴露代理到threadLocal中以及目标对象是否是动态的,会创建不同的Callback
     * isStatic为true的时候,同一个代理的不同方法可能都是新的目标对象,所以当代理方法执行完毕之后,需要对目标对象进行释放
     */
    if (exposeProxy) {
        targetInterceptor = (isStatic ?
                             new StaticUnadvisedExposedInterceptor(this.advised.getTargetSource().getTarget()) :
                             new DynamicUnadvisedExposedInterceptor(this.advised.getTargetSource()));
    }
    else {
        targetInterceptor = (isStatic ?
                             new StaticUnadvisedInterceptor(this.advised.getTargetSource().getTarget()) :
                             new DynamicUnadvisedInterceptor(this.advised.getTargetSource()));
    }

    // targetDispatcher会直接调用目标方法
    Callback targetDispatcher = (isStatic ?
                                 new StaticDispatcher(this.advised.getTargetSource().getTarget()) : new SerializableNoOp());

    Callback[] mainCallbacks = new Callback[] {
        aopInterceptor,  // 处理匹配到拦截器的方法
        targetInterceptor,  // 处理未匹配到拦截器的方法
        new SerializableNoOp(), 
        targetDispatcher,  // 处理未匹配到拦截器的方法,和targetInterceptor有何不同呢?目标方法如果返回值的结果是目标对象类型的,会使用 targetInterceptor 处理,内部会返回代理对象
        this.advisedDispatcher, // 处理Advised接口中定义的方法
        new EqualsInterceptor(this.advised), // 处理equals方法
        new 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 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对象

enhancer.setCallbackFilter(new ProxyCallbackFilter(
        this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));

这块重点在于ProxyCallbackFilter中的accept方法,这个方法会根据目标方法,获取目标方法最后会让callbacks列表中的哪个Callback处理,大家可以看一下源码,比较简单。

上面getCallbacks方法中涉及到了5个类如下:

  • DynamicAdvisedInterceptor
  • StaticUnadvisedExposedInterceptor
  • StaticUnadvisedInterceptor
  • DynamicUnadvisedInterceptor
  • StaticDispatcher

主要来看第一个类,基本上代理对象中的大部分自定义的方法都会进入到这个类的intercept方法中进行处理,代码如下:

DynamicAdvisedInterceptor类:

private static class DynamicAdvisedInterceptor implements MethodInterceptor, Serializable {
    //代理配置信息
    private final AdvisedSupport advised;
    //构造器,需要一个AdvisedSupport
    public DynamicAdvisedInterceptor(AdvisedSupport advised) {
        this.advised = advised;
    }

    //这个方法是关键,用来处理代理对象中方法的调用
    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
                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 CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
            }
            // 处理方法返回结果:会根据方法返回值的类型,做一些处理,比如方法返回的类型为自己,则最后需要将返回值置为代理对象
            retVal = 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来执行,调用方法的过程中,需要先获取方法上匹配的所有方法拦截器链,然后依次执行,最终会调用到目标方法。

获取方法对应的拦截器链,对应下面这段代码

org.springframework.aop.framework.AdvisedSupport#getInterceptorsAndDynamicInterceptionAdvice

AdvisorChainFactory advisorChainFactory = new DefaultAdvisorChainFactory();

public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, @Nullable Class<?> targetClass) {
    MethodCacheKey cacheKey = new MethodCacheKey(method);
    List<Object> cached = this.methodCache.get(cacheKey);
    if (cached == null) {
        cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(
            this, method, targetClass);
        this.methodCache.put(cacheKey, cached);
    }
    return cached;
}

会调用DefaultAdvisorChainFactory#getInterceptorsAndDynamicInterceptionAdvice方法获取方法上匹配的拦截器链。

涉及到的类
在这里插入图片描述

AdvisorChainFactory接口

拦截器链工厂接口,定义了一个方法,用来获取方法匹配的拦截器链列表


public interface AdvisorChainFactory {

    /**
     * 获取方法匹配的拦截器链列表
     * @param config:代理配置信息,里面包含了创建代理的所有信息,如:Advisor列表,此方法会从Advisor列表中找到和mehod匹配的
     * @param targetClass:目标类
     */
    List<Object> getInterceptorsAndDynamicInterceptionAdvice(Advised config, Method method, @Nullable Class<?> targetClass);
}

DefaultAdvisorChainFactory类

AdvisorChainFactory接口的默认实现。

public class DefaultAdvisorChainFactory implements AdvisorChainFactory, Serializable {

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

下面来看AdvisorAdapterRegistry这个接口。

AdvisorAdapterRegistry接口

AdvisorAdapter注册器,AdvisorAdapter可以将Advisor中的Advice适配为MethodInterceptor


public interface AdvisorAdapterRegistry {

    //将一个通知(Advice)包装为Advisor对象
    Advisor wrap(Object advice) throws UnknownAdviceTypeException;

    //根据Advisor获取方法MethodInterceptor列表
    MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException;

    //注册AdvisorAdapter,AdvisorAdapter可以将Advisor中的Advice适配为MethodInterceptor
    void registerAdvisorAdapter(AdvisorAdapter adapter);

}

DefaultAdvisorAdapterRegistry类

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

AdvisorAdapter接口

public interface AdvisorAdapter {
    //判断这个适配器支持advice这个通知么
    boolean supportsAdvice(Advice advice);

    //获取advisor对应的MethodInterceptor
    MethodInterceptor getInterceptor(Advisor advisor);
}

MethodBeforeAdviceAdapter类

适配MethodBeforeAdvice前置通知,负责将MethodBeforeAdvice类型的通知转换为MethodBeforeAdviceInterceptor类型的

MethodBeforeAdviceInterceptor类

将MethodBeforeAdvice通知适配为MethodInterceptor类型的

AfterReturningAdviceAdapter类

适配AfterReturningAdvice后置通知,负责将AfterReturningAdvice类型的通知转换为AfterReturningAdviceInterceptor类型的

AfterReturningAdviceInterceptor类

将AfterReturningAdvice通知适配为MethodInterceptor类型的

ThrowsAdviceAdapter类

适配ThrowsAdvice前置通知,负责将MethodBeforeAdvice类型的通知转换为MethodBeforeAdviceInterceptor类型的

ThrowsAdviceInterceptor类

将ThrowsAdvice通知适配为MethodInterceptor类型的

代理方法的调用过程(拦截器链的执行)

拦截器链执行过程

到目前,已经获取到代理对象,接着会开始使用这个代理对象,在代理对象上执行一些方法调用,此时会依次调用此方法上的所有MethodInterceptor,最终会调用到目标上对应的方法,执行过程如下图
在这里插入图片描述
jdk动态代理方式创建代理最终会调用ReflectiveMethodInvocation#proceed方法。

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

ProxyFactory简化代理的创建

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

  • ProxyCreatorSupport
  • ProxyFactory

ProxyCreatorSupport用来对代理的创建提供支持,内部添加了AopProxyFactory对象的引用,将代理的创建过程给简化了。

ProxyFactory类继承了ProxyCreatorSupport,让创建代理的过程更简单了,如果采用硬编码的方式,通常我们会使用ProxyFactory来创建代理对象,代码只需要下面几行了

//通过spring提供的代理创建工厂来创建代理
ProxyFactory proxyFactory = new ProxyFactory();
//ProxyFactory继承了AdvisedSupport类,所以可以直接可以通过ProxyFactory来设置创建代理需要的参数
//为工厂指定目标对象
proxyFactory.setTarget(target);
//添加顾问
proxyFactory.addAdvisor(advisor);
//调用proxyFactory.getProxy();创建代理
Object proxy = proxyFactory.getProxy();

案例

案例1

这个案例主要看一下生成的代理对象的一些信息。

@Test
    public void testAop6(){
        ProxyFactory proxyFactory = new ProxyFactory(new FundsService());
        proxyFactory.addAdvisor(new DefaultPointcutAdvisor(new MethodBeforeAdvice() {
            @Override
            public void before(Method method, Object[] args, Object target) throws Throwable {
                System.out.println(method);
            }
        }));
        //创建代理对象
        Object proxy = proxyFactory.getProxy();
        System.out.println("代理对象的类型:" + proxy.getClass());
        System.out.println("代理对象的父类:" + proxy.getClass().getSuperclass());
        System.out.println("代理对象实现的接口列表");
        for (Class<?> cf : proxy.getClass().getInterfaces()) {
            System.out.println(cf);
        }
    }

运行结果:

代理对象的类型:class com.spring.beanAOP1.FundsService$$EnhancerBySpringCGLIB$$d0bfcf3
代理对象的父类:class com.spring.beanAOP1.FundsService
代理对象实现的接口列表
interface org.springframework.aop.SpringProxy
interface org.springframework.aop.framework.Advised
interface org.springframework.cglib.proxy.Factory

案例2

有接口的情况默认会通过jdk动态代理的方式生成代理


public interface IService {

    void say();
}
public class ServiceImpl implements IService {
    @Override
    public void say() {
        System.out.println("say...");
    }
}
@Test
    public void testAop7() {
        ServiceImpl impl = new ServiceImpl();
        ProxyFactory proxyFactory = new ProxyFactory();
        proxyFactory.setTarget(impl);
        //设置接口
        proxyFactory.setInterfaces(IService.class);
        proxyFactory.addAdvice(new MethodBeforeAdvice() {
            @Override
            public void before(Method method, Object[] args, Object target) throws Throwable {
                System.out.println(method);
            }
        });
        IService proxy = (IService) proxyFactory.getProxy();
        System.out.println("代理对象的类型:" + proxy.getClass());
        System.out.println("代理对象的父类:" + proxy.getClass().getSuperclass());
        System.out.println("代理对象实现的接口列表");
        for (Class<?> cf : proxy.getClass().getInterfaces()) {
            System.out.println(cf);
        }
        //调用代理的方法
        System.out.println("\n调用代理的方法");
        proxy.say();
    }

运行结果:

代理对象的类型:class com.sun.proxy.$Proxy4
代理对象的父类:class java.lang.reflect.Proxy
代理对象实现的接口列表
interface com.spring.beanAOP2.IService
interface org.springframework.aop.SpringProxy
interface org.springframework.aop.framework.Advised
interface org.springframework.core.DecoratingProxy

调用代理的方法
public abstract void com.spring.beanAOP2.IService.say()
say...

案例3:强制使用cglib代理

在案例2中加入下面代码,设置proxyTargetClass为true,会强制使用cglib代理

proxyFactory.setProxyTargetClass(true);

案例4:将代理暴露在threadLocal中

先来看一段代码:

public class Service1 {

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

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

测试:

@Test
    public void testAop8(){
        ProxyFactory proxyFactory = new ProxyFactory();
        proxyFactory.setTarget(new Service1());
        proxyFactory.addAdvice(new MethodInterceptor() {
            @Override
            public Object invoke(MethodInvocation invocation) throws Throwable {
                System.out.println(String.format("进入%s方法",invocation.getMethod().getName()));
                long startTime = System.nanoTime();
                Object proceed = invocation.proceed();
                long endTime = System.nanoTime();
                System.out.println(endTime - startTime);
                return proceed;
            }
        });
        Service1 proxy = (Service1)proxyFactory.getProxy();
        proxy.m1();
    }

运行:

进入m1方法
m1
m2
6756129701

我们发现没有统计m2方法的耗时,为什么呢?

原因:m2方法是在m1方法中通过this的方式来调用的,this实际上指向的是上面代码中的new Service1()对象。

那么我们如何能让此处的m2也能被增强,你需要通过代理来调用m2方法才可以,可以将代理对象暴露在threadLocal中,然后在m1方法中获取到threadLoca中的代理对象,通过代理对象来调用m2就可以了

然后进行修改:

  1. 配置代理创建时,将其暴露出去proxyFactory.setExposeProxy(true);
  2. m1中调用m2的方法需要修改为((Service1)AopContext.currentProxy()).m2();

运行结果:

进入m1方法
m1
进入m2方法
m2
方法m2耗时314700
方法m1耗时31416600

下一篇文章将深入详解介绍spring中如何将aop搞成自动化的

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值