zoukankan      html  css  js  c++  java
  • SpringAOP[3]Cglib代理流程分析

    原文:SpringAOP联盟(2)— Cglib代理流程分析 - 简书 (jianshu.com)

    1. 在resources目录下加入logback-test.xml的配置文件

    <?xml version="1.0" encoding="UTF-8"?>
    <configuration>
        <springProperty scope="context" name="logPath" source="log.out.path" defalutValue="/app/test.log"/>
        <!-- %m输出的信息,%p日志级别,%t线程名,%d日期,%c类的全名,%i索引【从数字0开始递增】,,, -->
        <!-- appender是configuration的子节点,是负责写日志的组件。 -->
        <!-- ConsoleAppender:把日志输出到控制台 -->
        <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
            <encoder>
                <pattern>%d %p [%r] [%t] [%X{traceRootId}] (%file:%line\): %m%n</pattern>
                <!-- 控制台也要使用UTF-8,不要使用GBK,否则会中文乱码 -->
                <charset>UTF-8</charset>
            </encoder>
        </appender>
        <!-- 控制台输出日志级别 -->
        <root level="TRACE">
            <appender-ref ref="STDOUT"/>
        </root>
        <!-- 指定项目中某个包,当有日志操作行为时的日志记录级别 -->
        <!-- 级别依次为【从高到低】:FATAL > ERROR > WARN > INFO > DEBUG > TRACE  -->
    </configuration>
    @Slf4j
    public class Person {
        public void run1() {
            log.info("我在跑步1...");
        }
        public void run2() {
            log.info("我在跑步2...");
        }
    }

    2. 测试源码:

    @Test  
     public void testProxyFactory() {  
         Person person = new Person();  
         //被建议的类,即面向目标类生成代理类  
         ProxyFactory proxyFactory = new ProxyFactory(person);  
         NameMatchMethodPointcut nameMatchMethodPointcut = new NameMatchMethodPointcut();  
         nameMatchMethodPointcut.addMethodName("run1");  
         //通知+切点=advisor  
         DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor();  
         advisor.setPointcut(nameMatchMethodPointcut);  
         advisor.setAdvice(new MethodBeforeAdvice() {  
             @Override  
             public void before(Method method, Object[] args, Object target) throws Throwable {  
                 System.out.println("before Advice...");  
             }  
         });  
         //加入第二个adsivor  
         NameMatchMethodPointcutAdvisor nameMatchMethodPointcutAdvisor= new NameMatchMethodPointcutAdvisor();  
         nameMatchMethodPointcutAdvisor.addMethodName("run1");  
         nameMatchMethodPointcutAdvisor.setAdvice(new SimpleTraceInterceptor());  
         //第三个advisor  
         NameMatchMethodPointcutAdvisor advisor3= new NameMatchMethodPointcutAdvisor();  
         advisor3.addMethodName("run2");  
         advisor3.setAdvice(new DebugInterceptor());  
         //advisor放入到adviced  
         proxyFactory.addAdvisor(advisor);  
         proxyFactory.addAdvisor(advisor3);  
         proxyFactory.addAdvisor(nameMatchMethodPointcutAdvisor);  
         //最后经过代理生成代理对象  
         Person proxy = (Person) proxyFactory.getProxy();  
         //执行方法  
         proxy.run1();  
     }  

    3. 测试结果

    before Advice...
    2021-11-16 11:34:59.859 [main] TRACE o.s.aop.interceptor.SimpleTraceInterceptor - Entering method 'run1' of class [cn.lemon.spring.demo.pojo.Person]
    2021-11-16 11:34:59.865 [main] INFO cn.lemon.spring.demo.pojo.Person - 我在跑步1...
    2021-11-16 11:34:59.865 [main] TRACE o.s.aop.interceptor.SimpleTraceInterceptor - Exiting method 'run1' of class [cn.lemon.spring.demo.pojo.Person]

    流程解析

    1. 将advisor交由advised管理

    • advisor:增强器(由advice和pointcut组成)
    • advised:代理对象配置类(代理对象的配置以及所有的advisor)

    继承AdvisedSupportProxyFactory负责创建代理对象,创建出来的代理对象不仅保存了target对象,也保存了Advised所有Advisor)对象、ProxyConfig(代理对象的配置)对象。

     

    AdvisedSupport实现了Advised接口大部分的方法。

     

    AdvisorAdvice+Pointcut组成(通知 + 切入点),可以称为一个增强器,而ProxyFactory管理着所有的Advisor,根据Pointcut(切入点)配置决定为目标对象的方法增加拦截。

    调用ProxyFactoryaddAdvisor实际上的是AdvisedSupport实现的addAdvisor

     使用List存储所有Advisor

    public class AdvisedSupport extends ProxyConfig implements Advised {
        // 实现的 Advised 接口的方法, 添加一个 Advisor
        @Override
        public void addAdvice(Advice advice) throws AopConfigException {
            int pos = this.advisors.size();
            addAdvice(pos, advice);
        }
        
        // ?
        public void addAdvice(int pos, Advice advice) throws AopConfigException {
            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.
                throw new AopConfigException("DynamicIntroductionAdvice may only be added as part of IntroductionAdvisor");
            }
            else {
                addAdvisor(pos, new DefaultPointcutAdvisor(advice));
            }
        }
        /**
         * 添加一个 Advisor
         * @param pos 在 chain 中的位置, 0 为头部 head position in chain (0 is head). Must be valid.
         */
        @Override
        public void addAdvisor(int pos, Advisor advisor) throws AopConfigException {
            if (advisor instanceof IntroductionAdvisor) {
                validateIntroductionAdvisor((IntroductionAdvisor) advisor);
            }
            addAdvisorInternal(pos, advisor);
        }
        
        private void addAdvisorInternal(int pos, Advisor advisor) throws AopConfigException {
            Assert.notNull(advisor, "Advisor must not be null");
            // 配置不能再改变了
            if (isFrozen()) {
                throw new AopConfigException("Cannot add advisor: Configuration is frozen.");
            }
            if (pos > this.advisors.size()) {
                throw new IllegalArgumentException(
                        "Illegal position " + pos + " in advisor list with size " + this.advisors.size());
            }
            // List<Advisor> advisors, 链表
            this.advisors.add(pos, advisor);
            // this.methodCache.clear() 缓存清空
            adviceChanged();
        }
    }

    2. 创建出代理对象

    源码位置:org.springframework.aop.framework.CglibAopProxy#getProxy

    由上图所知,即使不存在advisorgetProxy()依旧生成了一个代理对象。

    ProxyFactory的作用是将targetadviced中的所有advisors整合在一起,生成proxy对象。待执行具体方法进行拦截。


    3. 拦截方法

     

    当调用代理对象的run1()方法后,实际上执行的是DynamicAdvisedInterceptor接口(CglibAopProxy内部类)的intercept()方法。

    (1)首先获取到对应Method方法上的chain(拦截器链)。

    (2)递归执行拦截方法+目标方法。

    代理对象的运行:

    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 {  
            //若是设置了exposeProxy=true属性,便可以在同一线程中获取代理对象
            if (this.advised.exposeProxy) {  
                oldProxy = AopContext.setCurrentProxy(proxy);  
                setProxyContext = true;  
            }  
            //获取到目标对象
            target = targetSource.getTarget();  
            Class<?> targetClass = (target != null ? target.getClass() : null);  
            //(重点关注)1. 获取advised的该方法上的过滤器链
            List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);  
            Object retVal;  
            if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {  
                Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);  
                retVal = methodProxy.invoke(target, argsToUse);  
            }  
            else {  
               //(重点关注)2. 开始执行方法的回调
                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);  
            }  
        }  
    }  

    3.1 获取过滤器链

    依旧是AdvicedSupport,代理对象配置类的方法,作用是获取方法上的拦截器链。

    addAdvisorInternal方法中,最后执行的adviceChanged()方法,实际上是调用methodCache.clear()方法,即清空拦截器缓存List。

    注意:MethodCacheKey是由Method实例 + method.hashCode()组成,确保key的唯一性。

    public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, @Nullable Class<?> targetClass) {  
        MethodCacheKey cacheKey = new MethodCacheKey(method);  
        //每次加入advisor后均清空methodCache,于是需要重新的生成cached
        List<Object> cached = this.methodCache.get(cacheKey);  
        if (cached == null) {  
            cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(  
                    this, method, targetClass);  
            this.methodCache.put(cacheKey, cached);  
        }  
        return cached;  
    }  

    而实际上获取AdvisorChain的方法是AdvisorChainFactory接口实现的。

     

    该方法作用有两个,

    1. 遍历所有的Advisor,若可以切入该方法(根据Pointcut配置决定),执行步骤2;
    2. Advisor解析为MethodInterceptor[]对象,并加入到List<Object> interceptorList

    注:MethodInterceptor 接口就一个 invoke 方法,入参类型 MethodInvocation,MethodInvocation 接口则有getMethod 、 getArguments 、getThis、procced 等方法

    public class DefaultAdvisorChainFactory implements AdvisorChainFactory, Serializable {
    
        @Override
        public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
                Advised config, Method method, @Nullable Class<?> targetClass) {
    
            // This is somewhat tricky... We have to process introductions first,
            // but we need to preserve order in the ultimate list.
            // 饿汉式单例,最终生成DefaultAdvisorAdapterRegistry对象
            AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
            // 入参配置中获取所有 Advisor 
            Advisor[] advisors = config.getAdvisors();
            List<Object> interceptorList = new ArrayList<>(advisors.length);
            // 获取声明 method 的实际类型, 也就是目标对象的类型
            Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
            Boolean hasIntroductions = null;
    
            for (Advisor advisor : advisors) {
                // 两种 Advisor, PointcutAdvisor 和 IntroductionAdvisor
                // PointcutAdvisor#getPointcut 直接能获得切入点[AspectJPointcutAdvisor]
                // IntroductionAdvisor#getClassFilter[DefaultIntroductionAdvisor]
                if (advisor instanceof PointcutAdvisor) {
                    PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
                    // ? || Class是否满足被拦截条件
                    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) {
                            // 将advisor中的内容转化为MethodInterceptor
                            MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
                            // MethodMatcher 是否为动态的, 也就是在运行期间是否匹配可能改变, 那么就需要每次invoke运行时再判断一次是否匹配
                            if (mm.isRuntime()) {
                                for (MethodInterceptor interceptor : interceptors) {
                                    // MethodInterceptors 和 MethodMatcher 的封装, DynamicMethodMatcher - 动态方法匹配
                                    interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));
                                }
                            }
                            else {
                                // 直接添加
                                interceptorList.addAll(Arrays.asList(interceptors));
                            }
                        }
                    }
                }
                else if (advisor instanceof IntroductionAdvisor) {
                    IntroductionAdvisor ia = (IntroductionAdvisor) advisor;
                    // Class 匹配即可?
                    if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) {
                        // 将advisor中的内容转化为MethodInterceptor
                        Interceptor[] interceptors = registry.getInterceptors(advisor);
                        // 直接添加, 没有动态的判断
                        interceptorList.addAll(Arrays.asList(interceptors));
                    }
                }
                else {
                    Interceptor[] interceptors = registry.getInterceptors(advisor);
                    interceptorList.addAll(Arrays.asList(interceptors));
                }
            }
    
            return interceptorList;
        }
    }
    AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();生成的注册器。该类的主要作用是将通知Advice解析为MethodInterceptor对象。
    通知:什么时候通知 + 在哪通知
    public class DefaultAdvisorAdapterRegistry implements AdvisorAdapterRegistry, Serializable {
        private final List<AdvisorAdapter> adapters = new ArrayList<>(3);
        /**
         * Create a new DefaultAdvisorAdapterRegistry, registering well-known adapters.
         */
        public DefaultAdvisorAdapterRegistry() {
            // 支持 MethodBeforeAdvice 类型的通知(Advice)
            registerAdvisorAdapter(new MethodBeforeAdviceAdapter());
            // 支持 AfterReturningAdvice 类型通知, 封装为 AfterReturningAdviceInterceptor
            registerAdvisorAdapter(new AfterReturningAdviceAdapter());
            // 支持 ThrowsAdvice 类型通知
            registerAdvisorAdapter(new ThrowsAdviceAdapter());
        }
        @Override
        public MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException {
            List<MethodInterceptor> interceptors = new ArrayList<>(3);
            Advice advice = advisor.getAdvice();
            //若是Advice实现了MethodInterceptor接口,直接加入到List中
            if (advice instanceof MethodInterceptor) {
                interceptors.add((MethodInterceptor) advice);
            }
            for (AdvisorAdapter adapter : this.adapters) {
              //若是advice实现了MethodBeforeAdvice等类型,则转换为MethodInterceptor,注意这些方法由子类实现。
                if (adapter.supportsAdvice(advice)) {
                    interceptors.add(adapter.getInterceptor(advisor));
                }
            }
            if (interceptors.isEmpty()) {
                throw new UnknownAdviceTypeException(advisor.getAdvice());
            }
            return interceptors.toArray(new MethodInterceptor[0]);
        }
    }

    3.2 递归执行方法

    retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
    注意在这里每次调用都new,意味着下面的 ReflectiveMethodInvocation 每次状态都是重置的(currentInterceptorIndex)
    也要注意到 ReflectiveMethodInvocation 类就是 ProxyMethodInvocation(MethodInvocation),而通知封装为 MethodInterceptor 的 invoke 参数类型就是 MethodInvocation,这里传入了 this,
    那么 MethodInterceptor 实现只要调用参数 MethodInvocation#procced 就能够回调 ReflectionMethodInvocation 的方法实现下一个拦截器的调用
    class CglibAopProxy implements AopProxy, Serializable {
        private static class CglibMethodInvocation extends ReflectiveMethodInvocation {
            public Object proceed() throws Throwable {
                try {
                    return super.proceed();
                }
            }
        }
    }
    
    public class ReflectiveMethodInvocation implements ProxyMethodInvocation, Cloneable {
        // Joinpoint 接口实现, 连接点
        @Override
        @Nullable
        public Object proceed() throws Throwable {
            // We start with an index of -1 and increment early.
            // 默认-1, 后者实际是 List<Object>, 不要被名称迷惑了
            if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
                // 所有拦截器已经调用完毕了, 则反射调用其 target 的方法
                return invokeJoinpoint();
            }
            
            // 获取第一个拦截器
            Object interceptorOrInterceptionAdvice =
                    this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
            // 动态 Matcher 则再次判断是否匹配
            if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
                // Evaluate dynamic method matcher here: static part will already have
                // been evaluated and found to match.
                InterceptorAndDynamicMethodMatcher dm =
                        (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
                Class<?> targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass());
                if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) {
                    // 匹配则调用拦截, 注意传入了this(参数声明类型 MethodInvocation)
                    // this 也是一个 ProxyMethodInvocation(MethodInvocation), 每个 interceptor 都会调用 MethodInvocation#proceed, 类似递归调用
                    return dm.interceptor.invoke(this);
                }
                else {
                    // Dynamic matching failed.
                    // Skip this interceptor and invoke the next in the chain.
                    // 不匹配则递归调用, 执行下一个拦截点
                    return proceed();
                }
            }
            else {
                // It's an interceptor, so we just invoke it: The pointcut will have
                // been evaluated statically before this object was constructed.
                // 其他的直接调用, 注意传入了this(参数声明类型 MethodInvocation)
                return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
            }
        }
    }

    拦截器回调方法:org.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor#invoke

    如何实现前置通知:下一个拦截器/target方法执行前执行增强逻辑

    如何实现后置通知:下一个拦截器/target方法执行后执行增强逻辑

    这也是对不同 Advice 封装为 MethodInvocation 的具体 MethodInvocation 的实现逻辑

    @Override  
    public Object invoke(MethodInvocation mi) throws Throwable {  
        //因为Advice被转换成为了MethodInterceptor对象,包装了invoke方法
        this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());  
        //继续执行(JoinPoint)后续的方法,即递归调用。
        return mi.proceed();  
    }  

     

    递归出口——执行Joinpoint方法:org.springframework.aop.framework.CglibAopProxy.CglibMethodInvocation#invokeJoinpoint
    @Override  
    protected Object invokeJoinpoint() throws Throwable {  
        if (this.methodProxy != null) {  
            //回调方法
            return this.methodProxy.invoke(this.target, this.arguments);  
        }  
        else {  
            return super.invokeJoinpoint();  
        }  
    }  

    实际上执行的是:org.springframework.cglib.proxy.MethodProxy#invoke

    class CglibAopProxy implements AopProxy, Serializable {
        private static class CglibMethodInvocation extends ReflectiveMethodInvocation {
            @Override
            protected Object invokeJoinpoint() throws Throwable {
                if (this.methodProxy != null) {
                    //  一般是这个
                    return this.methodProxy.invoke(this.target, this.arguments);
                }
                else {
                    // 父类就是直接反射调用 target 的方法
                    return super.invokeJoinpoint();
                }
            }
        }
    }
    
    public class MethodProxy {
        public Object invoke(Object obj, Object[] args) throws Throwable {
            try {
                // 初始化 FastClass 封装便于快速调用
                init();
                FastClassInfo fci = fastClassInfo;
                // 上面init初始化的, f1是target类, f2是proxy类型, i1是target的方法, i2是proxy代理后方法, obj 为 target 实例
                // 这里的 Cglib 有一个 FastClass 的概念, 就是将要调用的方法映射为int型值, 然后invoke传入int型值, 内部switch-case, 每个case直接target.method调用指定的方法, 避免了使用 method.invoke(target)反射调用
                return fci.f1.invoke(fci.i1, obj, args);
            }
        }
    }

    Cglib详解...指出了生成一个Cglib的Proxy对象,实际上会生成3个文件,在Java代码中表示:

    • f1表示的是代理类的FastClass对象;
    • f2表示目标类的FastClass对象
    • i1表示run1()方法的下标(代理对象run1()会经过拦截)。
    • i2表示CGLIB$run1$0方法的下标(代理对象中该方法是super.run1())。
    会有上述特点的原因是:(1)Cglib采用FastClass方法回调方法。(2)Cglib代理对象是目标对象的子类,故super.run1()执行的是目标对象的run1()方法。

    fci.f1.invoke(fci.i1, obj, args)含义是,在代理类的FastClass对象中执行run1()方法,而参数obj对象去执行run1()方法。而此处obj对象是target对象。

    即递归出口中最终执行的是targetrun1(),且结束调用。

     
     

     

  • 相关阅读:
    并发编程学习笔记之Java存储模型(十三)
    并发编程学习笔记之原子变量与非阻塞同步机制(十二)
    并发编程学习笔记之构建自定义的同步工具(十一)
    并发编程学习笔记之显示锁(十)
    并发编程学习笔记之可伸缩性(九)
    并发编程学习笔记之死锁(八)
    并发编程学习笔记之自定义配置线程池(七)
    并发编程学习笔记之取消和关闭(六)
    并发编程学习笔记之线程池(五)
    并发编程学习笔记之并发工具类(四)
  • 原文地址:https://www.cnblogs.com/chenxingyang/p/15559342.html
Copyright © 2011-2022 走看看