0
点赞
收藏
分享

微信扫一扫

SpringAOP联盟(4)—代理对象的创建和调用

路西法阁下 2021-09-28 阅读 25

上文中描述。代理对象的的创建:

  1. 完成配置,将Advisor(增强器)填充到Advised中;
  2. 使用JDK/CGLIB创建代理对象。

而本文重点描述一下代理对象的创建过程。

源码位置:org.springframework.aop.framework.ProxyCreatorSupport#createAopProxy

protected final synchronized AopProxy createAopProxy() {  
    if (!this.active) {  
        activate();  
    }  
    return getAopProxyFactory().createAopProxy(this);  
}  

可以看到ProxyCreatorSupport实际上是Advised子类。

创建AopProxy时,会将this(也就是Adviced)对象传入,即传入config(Advised)配置对象。

而后调用DefaultAopProxyFactory完成代理对象的创建
源码:org.springframework.aop.framework.DefaultAopProxyFactory#createAopProxy

@Override  
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {  
    //是Advised配置信息。
    //是否对代理进行优化 || 直接使用Cglib代理(这两者默认情况下为false)|| 没有实现接口
    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代理类
        if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {  
            return new JdkDynamicAopProxy(config);  
        }  
        return new ObjenesisCglibAopProxy(config);  
    }  
    else {  
        return new JdkDynamicAopProxy(config);  
    }  
}  

1. JDK代理对象

1.1 测试代码

JDK代理前提是:目标类需要存在接口。

//接口类
public interface IAccount {
    String say(@NotNull Integer id, @NotNull String desc);
    //接口内部定义了hashCode方法
    int hashCode();
}
//子类
@Service("accountImpl")
public class AccountImpl implements IAccount {
    @Override
    public String say(@NotNull Integer id, @NotNull String desc) {
        return "my "+id + ":" + desc;
    }
    @Override
    public int hashCode() {
        return 123;
    }
    @Override
    public boolean equals(Object obj) {
        return super.equals(obj);
    }
}

测试方法:

@Slf4j
public class proxyBean {
    public static void main(String[] args) {
        ProxyFactory proxyFactory = new ProxyFactory(new AccountImpl());
        proxyFactory.addAdvice((MethodBeforeAdvice) (method, arg1, target) -> {
            log.info("被拦截了:方法名:[{}],参数[{}]", method.getName(), Arrays.asList(arg1));
        });
        IAccount account = (IAccount) proxyFactory.getProxy();
        log.info(account.say(100, "哈哈哈"));
        log.info("hashCode方法:"+account.hashCode());
        log.info("equals方法:"+account.equals(account));
    }
}

测试结果:

12:59:13.242 [main] INFO com.tellme.Impl.proxy.proxyBean - 被拦截了:方法名:[say],参数[[100, 哈哈哈]]
12:59:13.257 [main] INFO com.tellme.Impl.proxy.proxyBean - my 100:哈哈哈
12:59:13.257 [main] INFO com.tellme.Impl.proxy.proxyBean - 被拦截了:方法名:[hashCode],参数[[]]
12:59:13.257 [main] INFO com.tellme.Impl.proxy.proxyBean - hashCode方法:123
12:59:13.258 [main] INFO com.tellme.Impl.proxy.proxyBean - equals方法:true

上述结果中可以看出,hashCode方法被拦截,而equlas方法并没有被拦截。而出现这个问题的原因是:hashCode由接口再次定义,而equals只是子类自己实现的方法。在Proxy中会进行特殊的处理。

1.2源码分析

final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable {

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

    //代理对象使用的配置类
    private final AdvisedSupport advised;

    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());
    }
    //真正创建Proxy代理的地方
    @Override
    public Object getProxy(@Nullable ClassLoader classLoader) {
        if (logger.isTraceEnabled()) {
            logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource());
        }
        //找到目标类实现的所有接口(下文有具体描述)
        Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
        findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
        //第三个参数是this,处理器就是自己,到此一个代理对象就被创建出来
        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) {
                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为其提供了基础的套件,来保证两个的执行行为是一致的。
    @Override
    @Nullable
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        MethodInvocation invocation;
        Object oldProxy = null;
        boolean setProxyContext = false;
        //进入invoke方法后,最终操作的是targetSource对象。
        //因为InvocationHandler持久化的就是targerSource,最终通过target得到目标对象
        TargetSource targetSource = this.advised.targetSource;
        Object target = null;

        try {
            //AOP“通常情况”下不会对equals、hashCode方法进行拦截。
            //若equalsDefined为false,即用户未定义equals方法,那么交由代理去比较。
            //hashCode同理
            //若接口上有equals、hashCode方法,但子类并未实现,那么不会被代理
            //若接口没有equals。hashCode方法,子类@Override实现,那么是无效的。
            if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
                // The target does not implement the equals(Object) method itself.
                return equals(args[0]);
            }
            else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
                // The target does not implement the hashCode() method itself.
                return hashCode();
            }
            //DecoratingProxy的方法和Advised接口的方法都是调用的是this.advised去执行
            else if (method.getDeclaringClass() == DecoratingProxy.class) {
                // There is only getDecoratedClass() declared -> dispatch to proxy config.
                return AopProxyUtils.ultimateTargetClass(this.advised);
            }
            else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
                    method.getDeclaringClass().isAssignableFrom(Advised.class)) {
                // Service invocations on ProxyConfig with the proxy config...
                return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
            }

            Object retVal;
            //是否暴露代理对象,默认false可配置为true,如果暴露就意味着允许在线程内共享代理对象。
            if (this.advised.exposeProxy) {
                // Make invocation available if necessary.
                oldProxy = AopContext.setCurrentProxy(proxy);
                setProxyContext = true;
            }

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

            // 获取作用在这个方法上的所有拦截器链
            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  最终是通过它,去执行前置加强、后置加强等等逻辑。
                invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
                // 此处会执行所有的过滤器链+目标方法。
                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;
            }
            //返回null,并且还不是void类型。。。抛错
            else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
                throw new AopInvocationException(
                        "Null return value from advice does not match primitive return type for: " + method);
            }
            return retVal;
        }
        finally {
            //释放
            if (target != null && !targetSource.isStatic()) {
                // Must have come from TargetSource.
                targetSource.releaseTarget(target);
            }
            if (setProxyContext) {
                // 把老的代理对象重新set进去
                AopContext.setCurrentProxy(oldProxy);
            }
        }
    }
}

比较重要的方法就是AopProxyUtils.completeProxiedInterfaces(),该方法返回的接口实际上就是JDK代理所需要的接口。

在选择具体代理实现时,若选用JDK代理,要么实现过接口,要么本身就是一个接口,或者已经被JDK代理实现过。那么在completeProxiedInterfaces方法中。

  1. 获取到目标类实现的所有接口;
  2. 为目标类添加一些其他接口:
    2.1 SpringProxy:若未实现,则添加;
    2.2 Advised:若配置isOpaque为false,且未实现过,则添加;
    2.3 DecoratingProxy:传入的decoratingProxy为true,且未实现过,则添加;

综上所述,最终返回的接口列表:目标对象所有接口+上面提供的三个接口;

static Class<?>[] completeProxiedInterfaces(AdvisedSupport advised, boolean decoratingProxy) {  
    //获取所有的接口
    Class<?>[] specifiedInterfaces = advised.getProxiedInterfaces();  
    //若没有实现接口
    if (specifiedInterfaces.length == 0) {  
        // No user-specified interfaces: check whether target class is an interface.  
        Class<?> targetClass = advised.getTargetClass();  
        if (targetClass != null) {  
            if (targetClass.isInterface()) {  
                advised.setInterfaces(targetClass);  
            }  
            else if (Proxy.isProxyClass(targetClass)) {  
                advised.setInterfaces(targetClass.getInterfaces());  
            }  
            specifiedInterfaces = advised.getProxiedInterfaces();  
        }  
    }  
    boolean addSpringProxy = !advised.isInterfaceProxied(SpringProxy.class);  
    boolean addAdvised = !advised.isOpaque() && !advised.isInterfaceProxied(Advised.class);  
    boolean addDecoratingProxy = (decoratingProxy && !advised.isInterfaceProxied(DecoratingProxy.class));  
    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;  
}  

2. CGLIB代理

class CglibAopProxy implements AopProxy, Serializable {
      //创建代理,就是使用CGLIB的方式,利用Enhancer创建了一个代理类
    @Override
    public Object getProxy() {
        return getProxy(null);
    }
      //CGLIB重写了这两个方法
    @Override
    public boolean equals(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();
    }
    //该类相当于JDK的invoke方法,所有被代理的类方法的调用,都会执行intercept方法。
    //该类实现了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) {
                    // Make invocation available if necessary.
                    oldProxy = AopContext.setCurrentProxy(proxy);
                    setProxyContext = true;
                }
                // Get as late as possible to minimize the time we "own" the target, in case it comes from a pool...
                target = targetSource.getTarget();
                Class<?> targetClass = (target != null ? target.getClass() : null);
                //拿到该方法匹配的所有的增强器
                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 {
                    //`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) {
                    // Restore old proxy.
                    AopContext.setCurrentProxy(oldProxy);
                }
            }
        }

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

        /**
         * CGLIB uses this to drive proxy creation.
         */
        @Override
        public int hashCode() {
            return this.advised.hashCode();
        }
    }
}
  • 和JDK代理一样,Object的方法,只有toString会被代理;
  • 生成出来的代理对象,Spring会默认实现SpringProxy、DecoratingProxy、Advised接口;
  • 和JDK代理不同的是,若是equals、hashCode方法不会进入Intercept方法,而是在getCallBack那么就进行了特殊处理。
  1. JdkDynamicAopProxy入口方法时动态代理的invoke()方法,而cglib使用的是DynamicAdvisedInterceptor.intercept()方法。

  2. JdkDynamicAopProxy使用ReflectiveMethodInvocation执行过滤器链+目标方法。
    CglibAopProxy使用CglibMethodInvocation去执行过滤器链+目标方法。
    但是它们都是ProxyMethodInvocation的实现类。关系如下图所示:

即JDK代理和CGLIB代理都是通过ReflectiveMethodInvocation#proceed()方法去执行目标方法。

文章推荐

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

举报

相关推荐

0 条评论