likes
comments
collection
share

Spring AOP 代理的创建——AOP 源码解析(五)

作者站长头像
站长
· 阅读数 29

一、概述

之前讨论了动态代理的实现,那么接下来再向上一层,看看动态代理是如何创建的,总的来说是解决几个问题:

  1. 在Spring IOC的基础上,使用哪种扩展方式扩展【本文分析的重点】;
  2. 判断bean是否需要创建代理
    • 如果需要代理,需要使用哪些通知来代理;
    • 如果有多个通知,如何控制通知的顺序;
    • 。。。

第一个问题,不难猜想,应该是使用BeanPostProcessor这种方式进行扩展,在Bean对象初始化之后,判断是否需要代理,如果需要,就创建代理对象。如果使用注解@EnableAspectJAutoProxy启用AOP,这个BeanPostProcessor就是AnnotationAwareAspectJAutoProxyCreator。

二、AnnotationAwareAspectJAutoProxyCreator

AnnotationAwareAspectJAutoProxyCreator就是创建代理对象的BeanPostProcessor,他的类继承关系比较复杂

AnnotationAwareAspectJAutoProxyCreator

  • AspectJAwareAdvisorAutoProxyCreator
    • AbstractAdvisorAutoProxyCreator
      • AbstractAutoProxyCreator
        • ProxyProcessorSupport
          • ProxyConfig
          • AopInfrastructureBean
          • BeanClassLoaderAware
            • Aware
        • BeanFactoryAware
          • Aware
        • SmartInstantiationAwareBeanPostProcessor【重点】
          • InstantiationAwareBeanPostProcessor
            • BeanPostProcessor

可以看到,AnnotationAwareAspectJAutoProxyCreator实现了SmartInstantiationAwareBeanPostProcessor接口,这个接口又继承了InstantiationAwareBeanPostProcessor和BeanPostProcessor。这些接口中有大量方法需要实现,不过捋一遍源码可以发现,AnnotationAwareAspectJAutoProxyCreator主要实现了以下方法(其他基本上是空的):

  1. SmartInstantiationAwareBeanPostProcessor.getEarlyBeanReference:方法名字翻译一下,就是“提前获取bean的引用”,用于解决循环依赖问题。需要代理的bean,需要在这里提前创建代理,否则注入到其他bean的依赖,就是一个未代理对象。这也是八股文中涉及到的“三级缓存”的关键点。
  2. InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation:在bean实例化之前被调用,如果返回了实例对象,则触发postProcessAfterInitialization方法,然后bean即认为创建完成,不再执行后续流程。换句话说,如果在该方法中返回了对象,则除了postProcessAfterInitialization外,其他的bean初始化流程,都不会执行。AnnotationAwareAspectJAutoProxyCreator实现了这个方法,主要就是为实现上一章我们讨论的TargetSource扩展。
  3. BeanPostProcessor.postProcessAfterInitialization: 在bean完成初始化后执行(注意这里的英文是Initialization,不是Instantiation,前面的是初始化,后面的是实例化),在正常情况下,就是在这里判断是否需要创建AOP代理,需要,就创建代理。

实际上,以上这些方法都是在AbstractAutoProxyCreator中实现的,这是一个典型的模板模式,基础分逻辑已经在父类中实现,留出部分扩展给子类实现。

2.1 getEarlyBeanReference - 提前代理

getEarlyBeanReference是SmartInstantiationAwareBeanPostProcessor这个接口的一个方法,他是在解决循环依赖,获取提前暴露的bean的时候,被调用的扩展方法。以下是在spring解决循环依赖时,调用getEarlyBeanReference的代码片段注意,只有发生了循环依赖时,才会执行以下代码

/**
 * IOC在遇到循环依赖时,会调用该方法
 * 源码出自:org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory
 */
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
    Object exposedObject = bean;
    if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
        for (BeanPostProcessor bp : getBeanPostProcessors()) {
            if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
                SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
                exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
            }
        }
    }
    return exposedObject;
}

/**
 * AbstractAutoProxyCreator的getEarlyBeanReference实现
 */
public Object getEarlyBeanReference(Object bean, String beanName) {
    //记录一下已经被提前处理过
    Object cacheKey = getCacheKey(bean.getClass(), beanName);
    this.earlyProxyReferences.put(cacheKey, bean);
    //如果需要代理,就提前代理,具体逻辑后文在详细阐述
    return wrapIfNecessary(bean, beanName, cacheKey);
}

为什么要实现这个扩展呢?!

因为如果循环依赖了,A->B,B->A,先创建了A,因为依赖关系创建了B,B再去获取提前暴露的A,也就是调用了getEarlyBeanReference,正常情况A应该在初始化方法执行完成之后,才会被代理(也就是后面会讲的postProcessAfterInitialization方法中代理)。如果AOP不实现这个方法,那么,B中的A就是没有被代理的A,显然是有问题的。所以,AOP要实现这个扩展,提前代理A。

2.2 postProcessBeforeInstantiation

前文已经提到过,postProcessBeforeInstantiation这个方法很牛B,如果返回了对象,除postProcessAfterInitialization外,其他的bean的一系列初始化流程都不会运行。而Spring AOP主要利用这个这个方法,实现自定义TargetSource,就是上一章中提到的TargetSource。

public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
    Object cacheKey = getCacheKey(beanClass, beanName);
    // 已经处理过不再处理
    if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
        if (this.advisedBeans.containsKey(cacheKey)) {
            return null;
        }
        if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
            this.advisedBeans.put(cacheKey, Boolean.FALSE);
            return null;
        }
    }
    
    // 如果获取到了自定义的TargetSource,则需要代理
    TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
    if (targetSource != null) {
        if (StringUtils.hasLength(beanName)) {
            this.targetSourcedBeans.add(beanName);
        }
        //找到符合条件的Interceptors,并创建代理
        Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
        Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
        this.proxyTypes.put(cacheKey, proxy.getClass());
        return proxy;
    }
    return null;
}

这里的核心逻辑,就是判断当前bean是否需要被包装为TargetSource,如果需要,则在这里直接对TargetSource对象直接代理。 那我们看下getCustomTargetSource方法,看什么场景下,会创建TargetSource:

protected TargetSource getCustomTargetSource(Class<?> beanClass, String beanName) {
   // 遍历customTargetSourceCreators,判断是否可以为该bean创建TargetSource。
   if (this.customTargetSourceCreators != null &&
         this.beanFactory != null && this.beanFactory.containsBean(beanName)) {
      for (TargetSourceCreator tsc : this.customTargetSourceCreators) {
         TargetSource ts = tsc.getTargetSource(beanClass, beanName);
         if (ts != null) {
            // Found a matching TargetSource.
            if (logger.isTraceEnabled()) {
               logger.trace("TargetSourceCreator [" + tsc +
                     "] found custom TargetSource for bean with name '" + beanName + "'");
            }
            return ts;
         }
      }
   }

   // No custom TargetSource found.
   return null;
}

代码很简单,就是遍历customTargetSourceCreators这个列表,如果任意一个Creator可以为这个bean创建TargetSource,就会返回TargetSource对象。而这个customTargetSourceCreators默认就是null,也即是说,想要扩展,需要在AbstractAutoProxyCreator中,注入自定义的TargetSourceCreator。该怎么注入呢?我们留在下一章解答。

2.3 postProcessAfterInitialization

从名字就可以看出,这是一个在bean调用初始化方法后,被调用的,一般情况下,AOP代理就是在这里被创建的(非一般的情况,就是上文提到的两种场景)。简单来说,就是判断一个bean是否需要被增强,如果需要就代理增强:

@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
    if (bean != null) {
        Object cacheKey = getCacheKey(bean.getClass(), beanName);
        // 此处与循环依赖有关,如果之前已经完成代理,这里不再执行
        if (this.earlyProxyReferences.remove(cacheKey) != bean) {
            // 之前没有代理过,如果需要代理,则代理
            return wrapIfNecessary(bean, beanName, cacheKey);
        }
    }
    return bean;
}
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
    // 如果是targetSource,直接返回(不过很奇怪,如果是targetSource,应该也不会执行到这里)
    if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
        return bean;
    }
    // 无需增强,之前解析过,无需解析的,会放在advisedBeans中,值为false,看最后一行
    if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
        return bean;
    }
    // 跳过一些类似Advice/Pointcut等,还有advisors这些对象
    if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
        this.advisedBeans.put(cacheKey, Boolean.FALSE);
        return bean;
    }
    // 找出这个Bean相关的Advisor
    Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
    if (specificInterceptors != DO_NOT_PROXY) {
        // 需要代理
        this.advisedBeans.put(cacheKey, Boolean.TRUE);
        Object proxy = createProxy(
                bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
        this.proxyTypes.put(cacheKey, proxy.getClass());
        return proxy;
    }
    // 无需解析,缓存
    this.advisedBeans.put(cacheKey, Boolean.FALSE);
    return bean;
}
源码出自:org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator

这里与前文getEarlyBeanReference方法一样,都执行了wrapIfNecessary方法。从名字就可以看出来方法目的,如果需要代理,就代理它。如果忽略缓存/跳过特殊bean代码,逻辑非常简单,找到所有匹配该bean的拦截器,如果存在,就创建这个bean的代理。

2.3.1 getAdvicesAndAdvisorsForBean - 找到可以代理这个bean的Advisor(和Advice)

getAdvicesAndAdvisorsForBean是一个抽象方法,由子类实现,看下我们会用到的AbstractAdvisorAutoProxyCreator的实现:

protected Object[] getAdvicesAndAdvisorsForBean(
        Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {
    List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
    if (advisors.isEmpty()) {
        return DO_NOT_PROXY;
    }
    return advisors.toArray();
}
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
    // 找到所有的Advisor
    List<Advisor> candidateAdvisors = findCandidateAdvisors();
    // 过滤合适的Advisor
    List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
    // 扩展
    extendAdvisors(eligibleAdvisors);
    // 排序
    if (!eligibleAdvisors.isEmpty()) {
        eligibleAdvisors = sortAdvisors(eligibleAdvisors);
    }
    return eligibleAdvisors;
}
//源码出自:org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator.getAdvicesAndAdvisorsForBean

可以看到,主要逻辑在findEligibleAdvisors这个方法中,eligible是符合条件的意思,大致流程非常清晰

  • 找到所有的Advisor,Advisor可以简单理解为Advice+PointCut,比如我实现了一个@Aspect切面类,内部定义了@Before/@AfterReturning的通知方法,在这里就被封装成两个Advisor;
  • 找到合适这个bean的Advisor,也就是遍历上一步获得的Advisor
    • 使用Advisor的PointCut,匹配bean的class下的方法,有一个能匹配,就是符合条件的Advisor
  • 扩展Advisors,抽象方法,子类实现;
  • 排序,根据一定规则对Advisor进行排序,指定被代理方法执行时,各个Advice的执行顺序;

findCandidateAdvisors和findAdvisorsThatCanApply方法源码不复制出来了,较为复杂,有兴趣可以参考以下文章:

  1. Spring Aop 之 Advisor 解析
  2. Spring Aop 原理之 Advisor 过滤

2.3.2 extendAdvisors - 扩展Advisors

extendAdvisors是一个抽象方法,由子类实现,AspectJAwareAdvisorAutoProxyCreator实现了这个方法,他是AnnotationAwareAspectJAutoProxyCreator(@EnableAspectJAutoProxy引入的)的父类。从注释中就可以看出,在Advisors链的头插入一个ExposeInvocationInterceptor。具体实现在AspectJProxyUtils中——如果Advisors链部位空,且不存在ExposeInvocationInterceptor,就在链表头插入一个ExposeInvocationInterceptor。

/**
 * Adds an {@link ExposeInvocationInterceptor} to the beginning of the advice chain.
 * These additional advices are needed when using AspectJ expression pointcuts
 * and when using AspectJ-style advice.
 */

@Override
protected void extendAdvisors(List<Advisor> candidateAdvisors) {
    AspectJProxyUtils.makeAdvisorChainAspectJCapableIfNecessary(candidateAdvisors);
}
源码出自:org.springframework.aop.aspectj.autoproxy.AspectJAwareAdvisorAutoProxyCreator.extendAdvisors

public static boolean makeAdvisorChainAspectJCapableIfNecessary(List<Advisor> advisors) {
    // Don't add advisors to an empty list; may indicate that proxying is just not required
    if (!advisors.isEmpty()) {
        boolean foundAspectJAdvice = false;
        for (Advisor advisor : advisors) {
            // Be careful not to get the Advice without a guard, as this might eagerly
            // instantiate a non-singleton AspectJ aspect...
            if (isAspectJAdvice(advisor)) {
                foundAspectJAdvice = true;
                break;
            }
        }
        if (foundAspectJAdvice && !advisors.contains(ExposeInvocationInterceptor.ADVISOR)) {
            advisors.add(0, ExposeInvocationInterceptor.ADVISOR);
            return true;
        }
    }
    return false;
}
// 源码出自org.springframework.aop.aspectj.AspectJProxyUtils.makeAdvisorChainAspectJCapableIfNecessary

那么ExposeInvocationInterceptor是什么呢?为什么要放在开头呢?

ExposeInvocationInterceptor会把MethodInvocation放到线程变量中,作为上线文,供后续的Advice使用。它的invoke方法:

@Override
public Object invoke(MethodInvocation mi) throws Throwable {
    MethodInvocation oldInvocation = invocation.get();
    invocation.set(mi);
    try {
        return mi.proceed();
    }
    finally {
        invocation.set(oldInvocation);
    }
}

同时,并提供了一个从当前线程变量中,获取MethodInvocation的方法:

public static MethodInvocation currentInvocation() throws IllegalStateException {
   MethodInvocation mi = invocation.get();
   if (mi == null) {
      //省略抛出异常的代码
   }
   return mi;
}

后续的其他通知,可以通过currentInvocation获取MethodInvocation,也就是JoinPoint(还记得MethodInvocation实现了JoinPoint接口么)。让我们回顾一下通知是如何实现的,以AspectJAfterThrowingAdvice为例,在抛出异常后,调用父类的invokeAdviceMethod方法。而这里获取JoinPoint的参数的getJoinPointMatch方法,就是通过ExposeInvocationInterceptor.currentInvocation()方法实现的。

public Object invoke(MethodInvocation mi) throws Throwable {
   try {
      return mi.proceed();
   }
   catch (Throwable ex) {
      if (shouldInvokeOnThrowing(ex)) {
         invokeAdviceMethod(getJoinPointMatch(), null, ex);
      }
      throw ex;
   }
}
//源码出自:org.springframework.aop.aspectj.AspectJAfterThrowingAdvice

@Nullable
protected JoinPointMatch getJoinPointMatch() {
   MethodInvocation mi = ExposeInvocationInterceptor.currentInvocation();
   if (!(mi instanceof ProxyMethodInvocation)) {
      throw new IllegalStateException("MethodInvocation is not a Spring ProxyMethodInvocation: " + mi);
   }
   return getJoinPointMatch((ProxyMethodInvocation) mi);
}
//源码出自:org.springframework.aop.aspectj.AbstractAspectJAdvice

2.3.3 sortAdvisors - 对Advisors排序

如果一个bean被多个切面切了,该如何排序呢,我们又该如何指定顺序呢。可以使用@Order指定顺序,也可以实现Ordered/PriorityOrdered接口,那在一个切面类内定义的不同通知,又该如何排序呢。我们探究一下:

AspectJAwareAdvisorAutoProxyCreator复写了sortAdvisors排序。

@Override
protected List<Advisor> sortAdvisors(List<Advisor> advisors) {
   List<PartiallyComparableAdvisorHolder> partiallyComparableAdvisors = new ArrayList<>(advisors.size());
   for (Advisor advisor : advisors) {
      partiallyComparableAdvisors.add(
            new PartiallyComparableAdvisorHolder(advisor, DEFAULT_PRECEDENCE_COMPARATOR));
   }
   List<PartiallyComparableAdvisorHolder> sorted = PartialOrder.sort(partiallyComparableAdvisors);
   if (sorted != null) {
      List<Advisor> result = new ArrayList<>(advisors.size());
      for (PartiallyComparableAdvisorHolder pcAdvisor : sorted) {
         result.add(pcAdvisor.getAdvisor());
      }
      return result;
   }
   else {
      return super.sortAdvisors(advisors);
   }
}

这里代码进行深入的debug后,整个人都麻了,头发都快薅光了,这个排序甚至还搞了一个图。 先看下注释,看他想实现什么效果。

Sort the supplied Advisor instances according to AspectJ precedence. If two pieces of advice come from the same aspect, they will have the same order. Advice from the same aspect is then further ordered according to the following rules: If either of the pair is after advice, then the advice declared last gets highest precedence (i.e., runs last). Otherwise the advice declared first gets highest precedence (i.e., runs first).

概括一下,就是说,两个Advisor先通过所属切面上声明的优先级排序,如果优先级相同,则

  • 如果有一个是after类型的通知,则与通知声明的顺序相反;
  • 否则按照通知声明的顺序排序。

切面的顺序,很容易理解,就是Order注解或者实现Ordered/PriorityOrdered接口,所指定的顺序。那通知声明顺序到底是个啥呢?

  • 如果使用注解方式定义,那就没有所谓的“通知声明的顺序”。
  • 如果使用xml方式定义,那就是通知声明的先后顺序。

需要说明的是,所谓after通知,是在方法后执行的通知,包括After、AfterReturning和AfterThrowing通知。

emmm,有没有感觉哪里很奇怪,如果我们这样在xml中定义通知

<aop:config>
    <aop:pointcut expression="execution (* com.hellohu.spring.aop.*.*(..))" id="pointcut" />
    <aop:aspect ref="logAdvice" order="1">
        <aop:before method="before" pointcut-ref="pointcut" />
        <aop:after method="after" pointcut-ref="pointcut" />
        <aop:around method="around" pointcut-ref="pointcut" />
    </aop:aspect>
</aop:config>

那么,他们的声明顺序是:

  1. before
  2. after
  3. around

那么按照排序规则有,他们的优先级为

  • before与after:after在before前面( 存在after,所以与声明顺序相反);
  • before与around:before在around前面(没有after,所以与声明顺序相同);
  • after与around:after在around后面(存在after,所以与声明顺序相反);

那么就变成了: after -> before -> around -> after

哈哈,套圈了?!如果出现了这种套圈的场景,就会退回到使用切面排序,相同切面按照原来顺序不变。哎,脑壳疼,不去仔细分析这里排序的源码了,详情可以参考:搞懂AOP之三,偏序排序

也不知道Spring AOP为什么会有这种对after通知的奇怪排序规则,不过不重要,现在一般也不会使用xml的方式配置了,不过,如果你用xml配置,要注意这个奇怪的规则。

假设我们忽略这个规则,那么Spring AOP排序的规则为:

  1. 复用了AnnotationAwareOrderComparator,也就是我们熟知的Spring的@Order和Order接口的排序规则:
    1. 实现PriorityOrdered接口的优先级,高于没有实现该接口的优先级。
    2. 获取PriorityOrdered/Ordered/@Order上的顺序,并进行比较,数字越低优先级越高。
    3. 没有通过任何方式指定顺序,则优先级最低。
  2. 否则,按照原来顺序排序

那么原来的顺序是啥呢,其实就是findCandidateAdvisors方法返回的Advisors的顺序

  • xml配置的方式,就是定义的顺序
  • 注解配置的方式
    • 不同类型,按照Around, Before, After, AfterReturning, AfterThrowing方式排序
    • 相同类型,按照名字排序

看下注解的排序方式,这个还挺有趣的,在ReflectiveAspectJAdvisorFactory#adviceMethodComparator有兴趣的可以研究一下:

private static final Comparator<Method> adviceMethodComparator;

static {
   // Note: although @After is ordered before @AfterReturning and @AfterThrowing,
   // an @After advice method will actually be invoked after @AfterReturning and
   // @AfterThrowing methods due to the fact that AspectJAfterAdvice.invoke(MethodInvocation)
   // invokes proceed() in a `try` block and only invokes the @After advice method
   // in a corresponding `finally` block.
   Comparator<Method> adviceKindComparator = new ConvertingComparator<>(
         new InstanceComparator<>(
               Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class),
         (Converter<Method, Annotation>) method -> {
            AspectJAnnotation<?> ann = AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(method);
            return (ann != null ? ann.getAnnotation() : null);
         });
   Comparator<Method> methodNameComparator = new ConvertingComparator<>(Method::getName);
   adviceMethodComparator = adviceKindComparator.thenComparing(methodNameComparator);
}

汇总一下排序规则就是:

  1. 复用了AnnotationAwareOrderComparator,也就是我们熟知的Spring的@Order和Order接口的排序规则:
    1. 实现PriorityOrdered接口的优先级,高于没有实现该接口的优先级。
    2. 获取PriorityOrdered/Ordered/@Order上的顺序,并进行比较,数字越低优先级越高。
    3. 没有通过任何方式指定顺序,则优先级最低。
  2. 定义在了一个切面中的通知
    • xml配置的方式,就是定义的顺序
    • 注解配置的方式:
      • 不同类型,按照Around, Before, After, AfterReturning, AfterThrowing方式排序
      • 相同类型,按照名字排序

值得注意的一点是,排序的顺序,与执行的顺序,不一定相同,因为具体的方法,在被代理对象方法执行前后,是不同的,按照之前我们对通知代码的分析,可以推断出来,假如所有的通知定义在一个切面类内,且切点相同执行的顺序大概是这样的(如果Around通知确实调用了proceed方法):

Around {
    //Before
    try {
        //执行真正的方法
        //AfterReturning
    } catch (Throwable ex) {
        //AfterThrowing,如果在Before或者Around中抛出异常,是无法执行AfterThrowing的
        throw ex;
    } finally {
        //After
    }
}

所以,如果希望通知执行的顺序,与上面的不同,那么不要定义在一个切面类内,定义在多个中,然后使用@Order等方式,指定切面的顺序。

2.3.4 createProxy - 创建代理对象

createProxy就是创建代理对象,使用specificInterceptors等参数创建代理工厂,使用工厂的getProxy创建代理对象。最终调用了DefaultAopProxyFactory.createAopProxy方法创建代理对象,也就是上一章所讲的,简单工厂,选择JDK还是CGLIB来创建代理对象。这些代码都比较简单,不再贴出代码分析。

2.3.5 小结

以上就是创建bean代理对象的具体流程,主要是在postProcessBeforeInstantiation中代理,最重要的方法是wrapIfNecessary——就是这个方法,解决了bean是否需要代理,需要哪些通知代理。再把上面的分析,复制一下:

  • 找到所有的Advisor,Advisor就是Advice+PointCut,比如我实现了一个@Aspect的类,内部定义了@Before/@AfterReturning的通知方法,在这里就被封装成两个Advisor;
  • 找到合适这个bean的Advisor,也就是遍历上一步获得的Advisor
    • 使用Advisor的PointCut,匹配bean的class下的方法,有一个能匹配,就是符合条件的Advisor
  • 扩展Advisors,这里增加了ExposeInvocationInterceptor,插入在了Advisor链的头部,用于把MethodInvocation放在线程变量内,用于后续的通知使用。
  • 排序,根据一定规则对Advisor进行排序,指定被代理方法执行时,各个Advice的执行顺序;
    1. 复用了AnnotationAwareOrderComparator,也就是我们熟知的Spring的@Order和Order接口的排序规则:
      • 实现PriorityOrdered接口的优先级,高于没有实现该接口的优先级。
      • 获取PriorityOrdered/Ordered/@Order上的顺序,并进行比较,数字越低优先级越高。
      • 没有通过任何方式指定顺序,则优先级最低。
    2. 定义在了一个切面中的通知
      • xml配置的方式,就是定义的顺序
      • 注解配置的方式:
        • 不同类型,按照Around, Before, After, AfterReturning, AfterThrowing方式排序
        • 相同类型,按照名字排序

系列所有文章

转载自:https://juejin.cn/post/7367631026250334247
评论
请登录