ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

SpringAOP[3]-Cglib代理流程分析

2021-11-16 05:02:31  阅读:177  来源: 互联网

标签:run1 对象 流程 Cglib advisor SpringAOP new 方法 method


原文: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...
2019-12-27 14:09:02,397 TRACE [1089] [main] [] (AbstractTraceInterceptor.java:222): Entering method 'run1' of class [com.proxy.Person]
2019-12-27 14:09:02,428 INFO [1120] [main] [] (Person.java:19): 我在跑步1...
2019-12-27 14:09:02,429 TRACE [1121] [main] [] (AbstractTraceInterceptor.java:222): Exiting method 'run1' of class [com.proxy.Person]

 

 

流程解析

1. 将advisor交由advised管理

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

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

 

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

 

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

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

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());  
    }  
    //将Advisor添加到LinkedList中
    this.advisors.add(pos, advisor);  
    //更新Advisors数组
    updateAdvisorArray();
    //清空methodCache(后文有描述)
    adviceChanged();  
}  

 

2. 创建出代理对象

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

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

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


3. 拦截方法

 

当调用代理对象的run1()方法后,实际上执行的是DynamicAdvisedInterceptor接口的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中。
@Override  
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(  
        Advised config, Method method, @Nullable Class<?> targetClass) {  
  
    //饿汉式单例,最终生成DefaultAdvisorAdapterRegistry对象。
    AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();  
    //获取所有的advisors
    Advisor[] advisors = config.getAdvisors();  
    List<Object> interceptorList = new ArrayList<>(advisors.length);  
    Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());  
    Boolean hasIntroductions = null;  
    //处理advisors,将其转换为Interceptor
    for (Advisor advisor : advisors) {  
        if (advisor instanceof PointcutAdvisor) {  
            // Add it conditionally.  
            PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;  
            //判断ClassFilter是否满足,PointcutAdvisor默认ClassFilter=true
            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);  
                }  
                //判断该方法上是否被advisor切入
                if (match) {  
                  //将advisor中的内容转化为MethodInterceptor。
                    MethodInterceptor[] interceptors = registry.getInterceptors(advisor);  
                    if (mm.isRuntime()) {  
                        // Creating a new object instance in the getInterceptors() method  
                        // isn't a problem as we normally cache created chains.  
                        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 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() {
        registerAdvisorAdapter(new MethodBeforeAdviceAdapter());
        registerAdvisorAdapter(new AfterReturningAdviceAdapter());
        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 递归执行方法

interceptorsAndDynamicMethodMatchers为上一步中解析得到该MethodMethodInterceptor的长度,即将要执行这些长度的拦截器方法。

@Override  
@Nullable  
public Object proceed() throws Throwable {  
    //(递归出口)最开始的拦截器索引下标为-1。
    if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {  
       //执行目标方法
        return invokeJoinpoint();  
    }  
    //interceptorsAndDynamicMethodMatchers为ArrayList,存储的是过滤器链
    Object interceptorOrInterceptionAdvice =  
            this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);  
    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)) {  
            return dm.interceptor.invoke(this);  
        }  
        else {  
            // Dynamic matching failed.  
            // Skip this interceptor and invoke the next in the chain.  
            return proceed();  
        }  
    }  
    else {  
        // 获取到MethodInterceptor链中的MethodInterceptor方法,开始回调。
        return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);  
    }  
}  

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

@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

public Object invoke(Object obj, Object[] args) throws Throwable {  
    try {  
        init();  
        FastClassInfo fci = fastClassInfo;  
        //f1为Proxy的FastClass类,i1为run1()方法下标,obj为目标对象
        //该代码的含义是:执行目标对象的run1()方法。
        return fci.f1.invoke(fci.i1, obj, args);  
    }  
    catch (InvocationTargetException ex) {  
        throw ex.getTargetException();  
    }  
    catch (IllegalArgumentException ex) {  
        if (fastClassInfo.i1 < 0)  
            throw new IllegalArgumentException("Protected method: " + sig1);  
        throw ex;  
    }  
} 

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(),且结束调用。

   

 

 

 

 

 

标签:run1,对象,流程,Cglib,advisor,SpringAOP,new,方法,method
来源: https://www.cnblogs.com/chenxingyang/p/15559342.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有