Spring AOP ProxyFactory

作者: BugPool | 来源:发表于2020-04-08 08:24 被阅读0次

    所有文章已迁移至csdn,csdn个人主页bugpool.blog.csdn.net

    Spring AOP源码目录

    Spring AOP源码01:Jdk动态代理底层源码
    Spring AOP源码02:ProxyFactory
    Spring AOP源码03:JdkDynamicAopProxy
    Spring AOP源码04:MethodInvocation 拦截器调用
    Spring AOP源码05:DefaultAdvisorAutoProxyCreator
    Spring期末考压轴题:当Spring AOP遇上循环依赖
    git注释源码地址:https://github.com/chaitou/spring-framework-master.git

    前言

    本篇将重点剖析ProxyFactory类的源码,很多人不理解为什么要将大部分精力花在讲解ProxyFactory上,毕竟没有人会使用这么底层的Spring AOP实现方式?

    ProxyFactory实现代理需要手动设置Traget(目标对象)、Interface(代理接口)、Advice(增强),然后调用getProxy生成代理对象。而使用注解形式的Spring AOP并没有想象中的复杂,不过是寻找所有@Aspect注解的类以及所有@Before等增强,再通过@Pointcut上的匹配条件进行匹配,最后获取到所有匹配的Advice(增强)进行生成代理。因此,注解形式的AOP并不深奥,只不过是帮我们自动寻找匹配增强,并在Spring Ioc创建Bean的过程中寻找合适的时机,调用getProxy生成代理,仅此而已。因此,如果我们将手动硬编码的方式(ProxyFactory)学透了,基本上也就掌握了Spring AOP了,至于注解的形式,我们只需要再探究一下Advice如何获取以及匹配就可以了

    剖去注解与Xml的配置,Spring AOP的核心就是ProxyFactory,抓住主线,才能更好的把握源码脉络,不至于被边角的细节所干扰

    ProxyFactory

    代码示例

    我们将会写一个UserService接口,定义findUser方法,同时在before跟after使用Advice(增强)对方法进行增强,最后使用ProxyFactory进行代理的生成。

    在这里有必要先大致介绍一下Advice(增强)和Advisor(切面),2个单词长的有点像,但是他们是聚合的关系。

    • 增强(Advice):常见的有Before adviceAfter returning advice,也就是在连接点进行扩展操作
    • 切点(Pointcut):也就是连接点,用于判断当前方法或者类是否需要增强
    • 切面(Advisor):可以看做的增强切点的结合。假设一个方法需要进行增强,则遍历所有切面,调用Pointcut进行判断当前切面是否适用,如果适用,则调用当前Advice进行增强

    接口:

    public interface UserService {
        public void findUser();
    }
    

    实现类:

    public class UserServiceImpl implements UserService {
        @Override
        public void findUser() {
            System.out.println("findUser...");
        }
    }
    

    2个增强:

    // 前置增强
    public class LogBeforeAdvice implements MethodBeforeAdvice {
        @Override
        public void before(Method method, Object[] args, Object target) throws Throwable {
            System.out.println("before log...");
        }
    }
    
    // 后置增强
    public class LogAfterAdvice implements AfterReturningAdvice {
        @Override
        public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
            System.out.println("after log...");
        }
    }
    

    测试:

    public class UserServiceImplImplTest {
        @Test
        public void findUser() {
    
            // 1. 创建代理工厂
            ProxyFactory factory = new ProxyFactory();
            // 2. 设置代理目标对象
            factory.setTarget(new UserServiceImpl());
            // 3. 设置接口
            factory.setInterfaces(new Class[]{UserService.class});
            // 4. 设置增强
            factory.addAdvice(new LogBeforeAdvice());
            factory.addAdvice(new LogAfterAdvice());
            // 5. 获取代理对象
            UserService userService = (UserService) factory.getProxy();
    
            userService.findUser();
        }
    }
    

    运行结果:

    before log...
    findUser...
    after log...
    
    Process finished with exit code 0
    

    ProxyFactory继承关系

    ProxyFactory

    我们重点关心一下类,忽略接口

    • ProxyConfig:用于保存Proxy的相关基础配置,比如是否使用激进模式optimize、强制开起cglib代理proxyTargetClass、是否暴露代理exposeProxy等,在xml配置中十分常见,例如<aop:aspectj-autoproxy proxy-target-class="true"/>强制开启Cglib代理
    • AdvisedSupport:AOP的配置管理类,比起ProxyConfig,其还保存了targetSource、切面的集合advisors、接口集合interfaces
    • ProxyCreatorSupport:代理工厂的基础类,提供对可配置AopProxyFactory的便捷访问

    源码分析

    1. 创建代理工厂,直接调用默认空构造器
    2. 设置代理目标对象,将target对象封装成TargetSource对象,为什么要多此一举呢?其实TargetSource的目的是为了做对象池和多例用的,也就是说每次代理都从池中获取对象。而这里我们只使用SingletonTargetSource,关于TargetSource留到后面讲解。刚刚提到这些属性都是保存在AdvisedSupport中的
        public void setTarget(Object target) {
            setTargetSource(new SingletonTargetSource(target));
        }
    
        @Override
        public void setTargetSource(@Nullable TargetSource targetSource) {
            this.targetSource = (targetSource != null ? targetSource : EMPTY_TARGET_SOURCE);
        }
    
    1. 设置接口数组,同样保存到AdvisedSupport的属性中
        public void setInterfaces(Class<?>... interfaces) {
            Assert.notNull(interfaces, "Interfaces must not be null");
            // 先清空再添加
            this.interfaces.clear();
            for (Class<?> ifc : interfaces) {
                addInterface(ifc);
            }
        }
    
        public void addInterface(Class<?> intf) {
            Assert.notNull(intf, "Interface must not be null");
            // 校验如果不是接口则抛出异常
            if (!intf.isInterface()) {
                throw new IllegalArgumentException("[" + intf.getName() + "] is not an interface");
            }
            if (!this.interfaces.contains(intf)) {
                this.interfaces.add(intf);
                adviceChanged();
            }
        }
    
    1. 设置Advice,前面我们说过Advice只是增强,因此我们要封装成Advisor切面才能加到AdvisedSupportadvisors集合中。而需要注意的是因为没有配置任何的Pointcut,因此将使用DefaultPointcutAdvisor进行创建
        @Override
        public void addAdvice(Advice advice) throws AopConfigException {
            int pos = this.advisors.size();
            addAdvice(pos, advice);
        }
    
        @Override
        public void addAdvice(int pos, Advice advice) throws AopConfigException {
            Assert.notNull(advice, "Advice must not be null");
            
            if (advice instanceof IntroductionInfo) {
                // We don't need an IntroductionAdvisor for this kind of introduction:
                // It's fully self-describing.
                // 单独处理引介增强
                addAdvisor(pos, new DefaultIntroductionAdvisor(advice, (IntroductionInfo) advice));
            }
            else if (advice instanceof DynamicIntroductionAdvice) {
                // We need an IntroductionAdvisor for this kind of introduction.
                // DynamicIntroductionAdvice只能作为IntroductionAdvisor的一部分
                throw new AopConfigException("DynamicIntroductionAdvice may only be added as part of IntroductionAdvisor");
            }
            else {
                // 普通增强
                addAdvisor(pos, new DefaultPointcutAdvisor(advice));
            }
        }
    

    DefaultPointcutAdvisor的意思就是无论什么方法都匹配,因此可以看到Pointcut使用的是Pointcut.TRUE,无论匹配什么方法都是true

    new DefaultPointcutAdvisor(advice)
    // Pointcut.TRUE
    // 也就是说该Advisor的匹配均为true,匹配任何的方法,不做任何限制!
    public DefaultPointcutAdvisor(Advice advice) {
        this(Pointcut.TRUE, advice);
    }
    
    1. 创建代理,这才是本篇的重头戏
        public Object getProxy() {
            return createAopProxy().getProxy();
        }
    

    代码就createAopProxy().getProxy()一句,在调用getProxy()之前,我们得弄清楚是什么对象调用的getProxy(),换句话说,也就是createAopProxy()到底创建了什么对象

    protected final synchronized AopProxy createAopProxy() {
        if (!this.active) {
            activate();
        }
        return getAopProxyFactory().createAopProxy(this);
    }
    ----------------------------------------------------------------
    public AopProxyFactory getAopProxyFactory() {
        // 返回的是类中的成员变量aopProxyFactory
        return this.aopProxyFactory;
    }
    ----------------------------------------------------------------
    // 成员变量的实例化则是在默认构造器中
    private AopProxyFactory aopProxyFactory;
    
    // 构造器,调用了DefaultAopProxyFactory进行实例化,因此aopProxyFactory真正的类型是DefaultAopProxyFactory
    public ProxyCreatorSupport() {
        this.aopProxyFactory = new DefaultAopProxyFactory();
    }
    

    跟踪发现createAopProxy()返回的是属性aopProxyFactory,而属性aopProxyFactory又是在ProxyCreatorSupport构造器时进行实例化的,真正的类是DefaultAopProxyFactory,因此继续跟踪DefaultAopProxyFactorycreateAopProxy方法

    public class DefaultAopProxyFactory implements AopProxyFactory, Serializable {
    
        @Override
        public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
            // isOptimize开启激进模式 || proxyTargetClass=true(强制开启cglib代理) || 接口集合为空
            if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
                Class<?> targetClass = config.getTargetClass();
                if (targetClass == null) {
                    throw new AopConfigException("TargetSource cannot determine target class: " +
                            "Either an interface or a target is required for proxy creation.");
                }
                // 目标对象为接口,一般不会发生
                if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
                    return new JdkDynamicAopProxy(config);
                }
                // 没有接口,只能选择cglib代理
                return new ObjenesisCglibAopProxy(config);
            }
            else {
                // 使用JDK代理
                return new JdkDynamicAopProxy(config);
            }
        }
      ...
    }
    

    可以看到,当config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)为真时才会使用Cglib代理,而当代理对象有实现接口,并且没有强制开启cglib代理时默认使用的是JDK代理,也就是JdkDynamicAopProxy类。

    也就是说,最后将调用的其实是new JdkDynamicAopProxy(config).getProxy(),结合Jdk动态代理底层源码的内容,可以预想到有2个需要特别关注的方法。getProxyinvoke方法

    // JdkDynamicAopProxy.java
        @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);
            // 判断接口是否又hashCode和equals方法
            findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
            // 使用JDK代理(classLoader, 接口, 当前JdkDynamicAopProxy对象:用于回调invoke和target对象方法)
            return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
        }
    
    // 上述代码
    Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
    
    // 第一篇[Jdk动态代理底层源码]中学习的代码是一模一样的
    return Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), this);
    

    可以看出,其实每个知识点都是关联在一起的,ProxyFactory作为Spring AOP的核心,使用的也是我们学习过的Jdk动态代理来实现的。结合第一篇Jdk动态代理底层源码的内容,最最重要的便是getProxyinvoke方法,下一节我们将进行JdkDynamicAopProxygetProxyinvoke方法的源码剖析

    相关文章

      网友评论

        本文标题:Spring AOP ProxyFactory

        本文链接:https://www.haomeiwen.com/subject/pqhhshtx.html