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...
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(代理对象的配置)对象。

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

 

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

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

 

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

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

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

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


3. 拦截方法

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

 

当调用代理对象的run1()方法后,实际上执行的是DynamicAdvisedInterceptor接口的intercept()方法。 SpringAOP[3]-Cglib代理流程分析

(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接口实现的。

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

 

该方法作用有两个,

  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对象。 SpringAOP[3]-Cglib代理流程分析
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();  
}  

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

 

递归出口——执行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()方法。 SpringAOP[3]-Cglib代理流程分析

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

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

   

 

 

 

 

 

上一篇:这才是Springboot事务创建流程的正确打开方式(附源码分析)


下一篇:代理模式