[Spring]AnnotationAwareAspectJAutoProxyCreator-@AspectJ的解析器

AnnotationAwareAspectJAutoProxyCreator职能

AnnotationAwareAspectJAutoProxyCreator是用来处理被@AspectJ注解标注的切面类和Spring Advisors的.
其中,Spring Advisors的处理规则遵循AbstractAdvisorAutoProxyCreator中建立的规则.

UML

UML

我们从类图可以看到,AnnotationAwareAspectJAutoProxyCreator的组成结构还是稍微复杂的。下面我们来过一下其中比较重要的接口.

  • AopInfrastructureBean: 实现该接口的类会被标记为Spring内部的基础类,Spring AOP并不会对这类型的Bean进行代理.
  • 与Aware相关的接口: 通过此类接口获取容器的BeanFactory和ClassLoader.
  • ProxyConfig: 用于创建代理的配置类,以确保所有代理创建者都具有一致的属性.内部可配置proxyTargetClassexposeProxyoptimize等属性
  • ProxyProcessorSupport: 具有代理处理器通用功能的基类,此外,还特地提供了ClassLoader的管理和evaluateProxyInterfaces方法,ProxyFactory可以通过evaluateProxyInterfaces方法获取给定bean类上的接口.
  • InstantiationAwareBeanPostProcessor: Spring AOP中会在实例化前判断是否需要创建用户自定义的代理类,进而影响Spring Bean的声明周期.
  • SmartInstantiationAwareBeanPostProcessor: 重量级方法->getEarlyBeanReference,当Spring Bean发生循环依赖的时候,决定是否要将创建代理的时机提前.
  • BeanPostProcessor: AbstractAutoProxyCreator会在postProcessAfterInitialization中来解析当前Bean是否需要代理,正常的Bean是在此处进行代理的,当执行到这步的时候,通常Spring Bean已经完成实例化、初始化了。
  • AbstractAutoProxyCreator: 继承了ProxyProcessorSupportSmartInstantiationAwareBeanPostProcessor,是Spring AOP的代理创建器,将匹配代理的地方交由子类去实现.同时,它还是getEarlyBeanReference方法的实现者.
  • AbstractAdvisorAutoProxyCreator: 提供为每个Bean选择特定的advisor进行代理的功能,提供findCandidateAdvisorsgetAdvicesAndAdvisorsForBean方法用于寻找候选的advisors和为bean匹配advisors.
  • AspectJAwareAdvisorAutoProxyCreator: 提供了对advisors进行排序的功能,同时为了兼容XML的切面配置解析,也保留了shouldSkip
  • AnnotationAwareAspectJAutoProxyCreator: Spring用于解析切面类,将需要执行的通知方法转化成Spring Advisor.

Spring Advisor

Spring中的Advisor接口是Spring AOP的基础接口,一个Advisor可以持有一个pointcut和一个AOP advice.Spring AOP正是通过将被AspectJ标注的类中的不同Advice解析成Advisor调用链来执行切面逻辑的。

Advised-操作Advisor

public interface Advised extends TargetClassAware {

    // 返回当前的advised配置是否被冻结
    boolean isFrozen();

    // 代理完整的目标类而不是指定的接口
    boolean isProxyTargetClass();

    // 返回由AOP代理代理的接口。
    // 将不包括目标类别,也可以将其作为代理。
    Class<?>[] getProxiedInterfaces();

    // 确定是否代理给定的接口
    boolean isInterfaceProxied(Class<?> intf);

    // 更改此建议对象使用的TargetSource。
    // 仅在未冻结配置的情况下有效。
    void setTargetSource(TargetSource targetSource);

    // 返回此Advised对象使用的TargetSource。
    TargetSource getTargetSource();

    // 设置代理是否应由AOP框架公开为ThreadLocal以便通过AopContext类进行检索。
    // 默认值为false,以实现最佳性能。
    void setExposeProxy(boolean exposeProxy);

    // 当前代理工厂是是否将代理类引用通过ThrealLocal管理起来.
    boolean isExposeProxy();

    // 获取当前代理的所有advisors
    Advisor[] getAdvisors();

    // 向当前proxy的advisor调用链追加一个advisor
    void addAdvisor(Advisor advisor) throws AopConfigException;

    // 向当前proxy的advisor调用链中的某个位置插入一个advisor
    void addAdvisor(int pos, Advisor advisor) throws AopConfigException;

    // 移除给定的advisor
    boolean removeAdvisor(Advisor advisor);

    // 移除某个位置中的advisor
    void removeAdvisor(int index) throws AopConfigException;

    // 获取当前advisor在执行链中的位置. -1代表没有任何的advisor
    int indexOf(Advisor advisor);

    // 替代某个advisor
    boolean replaceAdvisor(Advisor a, Advisor b) throws AopConfigException;

    // 向advice的拦截链中添加给定的AOP Alliance advice
    void addAdvice(Advice advice) throws AopConfigException;

    void addAdvice(int pos, Advice advice) throws AopConfigException;

    boolean removeAdvice(Advice advice);

    int indexOf(Advice advice);

    // 返回AOP代理的配置项。
    String toProxyConfigString();

}

Spring 官网对advised接口的描述

TargetSource

Spring AOP并不是直接代理目标类,而是通过代理TargetSource接口进而实现动态代理.
简单来说即: Spring AOP->TargetSource->targetObject

  • UML
targetSource

Spring官网对TargerSource的介绍

加载切面类并解析advisor

  • AbstractAutoProxyCreator#postProcessBeforeInstantiation
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
        // 从缓存中获取当前BeanClass的Class对象,在advisedBeans这个Map中,以class为key
        // 同时,该class还充当proxyTypes这个Map中的key
        Object cacheKey = getCacheKey(beanClass, beanName);

        if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
            // 如果当前类已经被动态代理了,不进行任何操作
            if (this.advisedBeans.containsKey(cacheKey)) {
                return null;
            }
            // 当前beanClass是否实现Advice、Pointcut、Advisor、AopInfrastructureBean
            // 是否需要跳过解析
            if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
                this.advisedBeans.put(cacheKey, Boolean.FALSE);
                return null;
            }
        }

        // 如果当前beanClass存在用户自定义的TargetSource,则进行代理
        // 在Spring AOP中,动态代理并不是直接代理target对象的,而是通过代理TargetSource来间接代理target对象
        TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
        if (targetSource != null) {
            if (StringUtils.hasLength(beanName)) {
                this.targetSourcedBeans.add(beanName);
            }
            // 获取当前bean的advisors
            Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
            // 创建代理类
            Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
            this.proxyTypes.put(cacheKey, proxy.getClass());
            return proxy;
        }

        return null;
    }
  1. 需要过滤已经创建过动态代理的类,advisedBeans这个Map便是缓存已经被Spring AOP处理过的BeanClass.
  2. 其中isInfrastructureClass会过滤掉Spring AOP框架内部的基类,同时会识别当前是否标注了@AspectJ与被ajc编译器所编译.
  3. 如果当前用户自定义实现了TargetSource接口,那么AbstractAutoProxyCreator会为用户自定义的TargetSource创建代理.

我们深入isInfrastructureClass这个方法看看,step into!

isInfrastructureClass-忽略Spring AOP的基础服务类

  • org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator#isInfrastructureClass
@Override
    protected boolean isInfrastructureClass(Class<?> beanClass) {
        
        return (super.isInfrastructureClass(beanClass) ||
                (this.aspectJAdvisorFactory != null && this.aspectJAdvisorFactory.isAspect(beanClass)));
    }

父类中的AbstractAutoProxyCreator调用了AnnotationAwareAspectJAutoProxyCreator中的isInfrastructureClass,这里有2个判断:

  1. 调用父类的isInfrastructureClass,返回true则直接中断.
    父类执行isInfrastructureClass的逻辑为:当前beanClass是否实现AdvicePointcutAdvisorAopInfrastructureBean.
  2. 判断当前beanClass是否为切面类.isApsect的逻辑比较简单:beanClass上是否标注了@Aspect注解并且没有被ajc编译器编译过.
  • org.springframework.aop.aspectj.annotation.AbstractAspectJAdvisorFactory#isAspect
    public boolean isAspect(Class<?> clazz) {
        // 类上是否标注@Aspect并且没有被ajc编译器编译过
        return (hasAspectAnnotation(clazz) && !compiledByAjc(clazz));
    }

shouldSkip-将切面类解析成advisor

  • org.springframework.aop.aspectj.autoproxy.AspectJAwareAdvisorAutoProxyCreator#shouldSkip
@Override
protected boolean shouldSkip(Class<?> beanClass, String beanName) {
    // TODO: Consider optimization by caching the list of the aspect names
    // 查找候选的advisors
    List<Advisor> candidateAdvisors = findCandidateAdvisors();
    for (Advisor advisor : candidateAdvisors) {
        if (advisor instanceof AspectJPointcutAdvisor &&
                ((AspectJPointcutAdvisor) advisor).getAspectName().equals(beanName)) {
            return true;
        }
    }
    return super.shouldSkip(beanClass, beanName);
}

shouldSkip是Spring AOP构建advisor的入口,spring会在每次执行postProcessBeforeInstantiation的时候,解析每个advisor,解析完成后将advisors进行缓存,进而判断当前的beanClass和beanName是否已经解析完毕. 下面,我们来看看findCandidateAdvisors这个方法做了什么,step into.

  • org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator#findCandidateAdvisors
@Override
protected List<Advisor> findCandidateAdvisors() {
    // Add all the Spring advisors found according to superclass rules.
    // 添加根据超类规则找到的所有Spring advisors.从层级关系我们可以知道,
    // AspectJAwareAdvisorAutoProxyCreator提供对XML或者实现接口的AOP配置解析
    List<Advisor> advisors = super.findCandidateAdvisors();
    // Build Advisors for all AspectJ aspects in the bean factory.
    if (this.aspectJAdvisorsBuilder != null) {
        // 注解驱动的AOP切面解析类解析
        advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
    }
    return advisors;
}

这里面findCandidateAdvisors分成了两条线路:

  1. 调用父类AspectJAwareAdvisorAutoProxyCreator#finCandidateAdvisors提供对XML或者实现接口的AOP配置解析成advisor列表.
  2. 解析注解形式的Aspect成advisor列表.

最后,都添加进advisor列表中.

解析advisor类型的bean.
  • org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator#findCandidateAdvisors
protected List<Advisor> findCandidateAdvisors() {
Assert.state(this.advisorRetrievalHelper != null, "No BeanFactoryAdvisorRetrievalHelper available");
// BeanFactoryAdvisorRetrievalHelperAdapter#findAdvisorBeans
return this.advisorRetrievalHelper.findAdvisorBeans();
}

这里进行了一个helper的委托,真正执行者为BeanFactoryAdvisorRetrievalHelperAdapter#findAdvisorBeans.

  • org.springframework.aop.framework.autoproxy.BeanFactoryAdvisorRetrievalHelper#findAdvisorBeans
/**
 * <p>Find all eligible Advisor beans in the current bean factory,
 * ignoring FactoryBeans and excluding beans that are currently in creation.</p>
 * 在当前beanFactory中查找所有有资格的advisor.<br>
 * 对FactoryBean和正在创建中的bean不生效 <br>
 * @return the list of {@link org.springframework.aop.Advisor} beans
 * @see #isEligibleBean
 */
public List<Advisor> findAdvisorBeans() {
    // Determine list of advisor bean names, if not cached already.
    // 从缓存中获取容器中所有的advisor bean的名字数组
    String[] advisorNames = this.cachedAdvisorBeanNames;
    if (advisorNames == null) {
        // Do not initialize FactoryBeans here: We need to leave all regular beans
        // uninitialized to let the auto-proxy creator apply to them!
        // 如果缓存中没有,那么从容器中以及其父容器中分析得到所有的advisor bean的名称
        // BeanFactoryUtils.beanNamesForTypeIncludingAncestors此处是找到类型为advisor的bean
        // 注意,spring不推荐在此处实例化factoryBeans,因为spring需要保留所有未初始化的常规类
        // 以使自动代理创建者对其应用!
        advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
                this.beanFactory, Advisor.class, true, false);
        // 回种缓存
        this.cachedAdvisorBeanNames = advisorNames;
    }
    if (advisorNames.length == 0) {
        return new ArrayList<>();
    }

    List<Advisor> advisors = new ArrayList<>();
    for (String name : advisorNames) {
        // 是否为合适的bean,提供给用户自定义实现,默认返回true
        if (isEligibleBean(name)) {
            // 创建中的bean会被忽略,beanPostProcessor是每次加载bean都会触发的钩子
            // 所以在下次进来时,可能当前正在创建的bean已经被创建好了
            if (this.beanFactory.isCurrentlyInCreation(name)) {
                if (logger.isTraceEnabled()) {
                    logger.trace("Skipping currently created advisor '" + name + "'");
                }
            }
            else {
                try {
                    // 根据advisorName获取advisor实例
                    advisors.add(this.beanFactory.getBean(name, Advisor.class));
                }
                catch (BeanCreationException ex) {
                    // 省略处理异常细节
                }
            }
        }
    }
    return advisors;
}

首先,会尝试从缓存中获取advisorNames数组,里面存储了容器中所有的advisor bean的名字.如果无法从缓存中获取,那么重新加载符合条件的advisorNames数组,回种缓存.这里要注意: BeanFactoryUtils.beanNamesForTypeIncludingAncestors( this.beanFactory, Advisor.class, true, false);中,传入的是Advisor类型.,也就是寻找类型为Advisor的beanName,并非所有beanName.

遍历advisorNames数组,对符合条件的advisor进行getBean操作,然后添加进advisors集合返回.

buildAspectJAdvisors-解析被@Aspect注解标记的类

/**
 * Look for AspectJ-annotated aspect beans in the current bean factory,
 * and return to a list of Spring AOP Advisors representing them.
 * <p>Creates a Spring Advisor for each AspectJ advice method.<br>
 * 1. 从容器获取所有的beanName集合 <br>
 * 2. 找到其中被@AspectJ标注的类 <br>
 * 3. 解析Aspect类,将其转化成advisors <br>
 * 4. 将result加入cache中 <br>
 * @return the list of {@link org.springframework.aop.Advisor} beans
 * @see #isEligibleBean
 */
public List<Advisor> buildAspectJAdvisors() {
    // 获取所有aspect类的beanName
    List<String> aspectNames = this.aspectBeanNames;
    // 如果aspectNames为空,那么进行加载
    if (aspectNames == null) {
        // 双重检查锁,防止多线程之间产生并发访问
        synchronized (this) {
            aspectNames = this.aspectBeanNames;
            if (aspectNames == null) {
                List<Advisor> advisors = new ArrayList<>();
                // 保存切面名称的集合
                aspectNames = new ArrayList<>();
                // 获取所有的beanName
                // BeanFactoryUtils.beanNamesForTypeIncludingAncestors传入的type为Object
                // 也就说查找所有的bean,spring在这里使用了缓存,避免每次加载消耗性能
                String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
                        this.beanFactory, Object.class, true, false);
                // 遍历所有的beanName
                for (String beanName : beanNames) {
                    if (!isEligibleBean(beanName)) {
                        continue;
                    }
                    // We must be careful not to instantiate beans eagerly as in this case they
                    // would be cached by the Spring container but would not have been weaved.
                    // 必须小心,不要急于实例化bean,因为在这种情况下,它们将由Spring容器缓存,但不会被编织。
                    // 获取bean的类型
                    Class<?> beanType = this.beanFactory.getType(beanName);
                    if (beanType == null) {
                        continue;
                    }
                    // org.springframework.aop.aspectj.annotation.AbstractAspectJAdvisorFactory.isAspect
                    // 筛选出当前class是否标记了@Apsect注解
                    if (this.advisorFactory.isAspect(beanType)) {
                        // 将当前的beanName加入到aspectNames这个缓存中
                        aspectNames.add(beanName);
                        // 获取当前beanClass的aspect元数据
                        // AjType中包含了切面的详细数据
                        AspectMetadata amd = new AspectMetadata(beanType, beanName);
                        // 获取切面的种类,通常为singleton
                        if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
                            MetadataAwareAspectInstanceFactory factory =
                                    new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
                            // Aspect中的advice+pointcut可以组成一个个advisor
                            // 举个例子,before、after、around每个都会搭配pointcut组成advisor
                            List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
                            if (this.beanFactory.isSingleton(beanName)) {
                                // 如果bean是单例,存到单例缓存中
                                this.advisorsCache.put(beanName, classAdvisors);
                            }
                            else {
                                // 否则将工厂和beanName缓存
                                this.aspectFactoryCache.put(beanName, factory);
                            }
                            advisors.addAll(classAdvisors);
                        }
                        else {
                            // Per target or per this.
                            if (this.beanFactory.isSingleton(beanName)) {
                                throw new IllegalArgumentException("Bean with name '" + beanName +
                                        "' is a singleton, but aspect instantiation model is not singleton");
                            }
                            MetadataAwareAspectInstanceFactory factory =
                                    new PrototypeAspectInstanceFactory(this.beanFactory, beanName);
                            this.aspectFactoryCache.put(beanName, factory);
                            advisors.addAll(this.advisorFactory.getAdvisors(factory));
                        }
                    }
                }
                this.aspectBeanNames = aspectNames;
                return advisors;
            }
        }
    }

    if (aspectNames.isEmpty()) {
        return Collections.emptyList();
    }
    List<Advisor> advisors = new ArrayList<>();
    for (String aspectName : aspectNames) {
        List<Advisor> cachedAdvisors = this.advisorsCache.get(aspectName);
        if (cachedAdvisors != null) {
            advisors.addAll(cachedAdvisors);
        }
        else {
            MetadataAwareAspectInstanceFactory factory = this.aspectFactoryCache.get(aspectName);
            advisors.addAll(this.advisorFactory.getAdvisors(factory));
        }
    }
    return advisors;
}

方法比较长,但是总体的脉络我们还是可以总结一下:

  1. 尝试从缓存获取所有的aspectNames集合.如果缓存找不到,重新加载.执行的方法又是BeanFactoryUtils.beanNamesForTypeIncludingAncestors,只不过这次传入的类型是Object.class,也就是说,获取的是所有的beanNames.
  2. 遍历beanNames数组,通过name获取type,然后判断当前类是否为Aspect.也就是被@Aspect注解所标记.
  3. 如果是Aspect,构建AspectMetadata,AspectMetadata中保存了AjType,这是AspectJ框架的产物,通过它可以快速获取当前类的pointcutadvice等.Spring AOP正是借助AspectJ来获取切面类的信息的.此外,AspectJ还提供了很多切面模型种类,通常,我们的切面类都是为singleton-单例.
  4. 调用ReflectiveAspectJAdvisorFactory#getAdvisors来解析Aspect类,进而解析出List<Advisor>.
  • org.springframework.aop.aspectj.annotation.ReflectiveAspectJAdvisorFactory#getAdvisors
@Override
public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {
    // 获取Aspect类的class
    Class<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
    // 获取Aspect的类名
    String aspectName = aspectInstanceFactory.getAspectMetadata().getAspectName();
    // 校验切面类,不可以为抽象类,需标记@Aspect
    // spring aop 不支持percflow、percflowbelow种类的aspect
    validate(aspectClass);

    // We need to wrap the MetadataAwareAspectInstanceFactory with a decorator
    // so that it will only instantiate once.
    // 使用装饰器模式包装MetadataAwareAspectInstanceFactory
    // 包装器类重写了getAspectInstance方法,并且保证当前的factory在使用时才进行加载(缓存)
    // 正如名字的意义一般 lazy singleton instance
    MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory =
            new LazySingletonAspectInstanceFactoryDecorator(aspectInstanceFactory);

    List<Advisor> advisors = new ArrayList<>();
    // 获取aspect切面类中的所有方法,会过滤掉被@Pointcut标记的方法
    // 获取到的List<Method>按照Around, Before, After, AfterReturning, AfterThrowing的顺序排序
    for (Method method : getAdvisorMethods(aspectClass)) {
        // 将方法解析成advisor
        Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, advisors.size(), aspectName);
        if (advisor != null) {
            advisors.add(advisor);
        }
    }

    // If it's a per target aspect, emit the dummy instantiating aspect.
    if (!advisors.isEmpty() && lazySingletonAspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
        Advisor instantiationAdvisor = new SyntheticInstantiationAdvisor(lazySingletonAspectInstanceFactory);
        advisors.add(0, instantiationAdvisor);
    }

    // Find introduction fields.
    for (Field field : aspectClass.getDeclaredFields()) {
        Advisor advisor = getDeclareParentsAdvisor(field);
        if (advisor != null) {
            advisors.add(advisor);
        }
    }

    return advisors;
}

getAdvisors就是我们关注的注解切面类解析逻辑了:

  1. 首先从aspectInstanceFactory中获取元数据进而获取切面类型和切面名称,随后对切面类进行校验-切面类不可以为抽象类,需标记@Aspect,同时,spring aop 不支持percflow、percflowbelow种类的aspect.
  2. 使用装饰器模式包装MetadataAwareAspectInstanceFactory来懒加载切面类实例.
  3. 获取当前类中标记@Pointcut注解外所有的Method集合,获取到的List<Method>按照Around, Before, After, AfterReturning, AfterThrowing的顺序排序.
  4. 遍历每一个Method,将符合条件的方法解析成advisor实例.
  5. 检查是否有属于introduction的成员,如果有便进行解析(@DeclareParents).
  6. 将解析完成的每一个advisor添加到返回的结果集中.
  • org.springframework.aop.aspectj.annotation.ReflectiveAspectJAdvisorFactory#getAdvisor
@Override
@Nullable
public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory,
        int declarationOrderInAspect, String aspectName) {
    // 验证aspectClass的合法性
    validate(aspectInstanceFactory.getAspectMetadata().getAspectClass());
    // 在切面的方法上构建pointcut表达式
    AspectJExpressionPointcut expressionPointcut = getPointcut(
            candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass());
    if (expressionPointcut == null) {
        return null;
    }
    // 实例化切面中的advice对象
    return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,
            this, aspectInstanceFactory, declarationOrderInAspect, aspectName);
}
  1. 校验aspectClass的合法性,这个validate是复用的,跟上述的方法一致,逻辑就不重复讲了.
  2. 根据当前的adviceMethod与aspectClass构建出AspectJExpressionPointcut实例.它是一个pointcut表达式的实例.里面对AspectJ框架的表达式原语进行了部分的支持(11种).
  3. 通过getPointcut()获取到切点表达式之后,接下来就可以实例化adivce然后构建出advisor了,因为一个advisor = pointcut+advice.我们接着看InstantiationModelAwarePointcutAdvisorImpl这个方法是如何实例化advice的.
  • org.springframework.aop.aspectj.annotation.InstantiationModelAwarePointcutAdvisorImpl#InstantiationModelAwarePointcutAdvisorImpl
public InstantiationModelAwarePointcutAdvisorImpl(AspectJExpressionPointcut declaredPointcut,
        Method aspectJAdviceMethod, AspectJAdvisorFactory aspectJAdvisorFactory,
        MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {
    // 当前的pointcut表达式
    this.declaredPointcut = declaredPointcut;
    // 切面Class
    this.declaringClass = aspectJAdviceMethod.getDeclaringClass();
    // advice方法名称
    this.methodName = aspectJAdviceMethod.getName();
    // 方法参数类型
    this.parameterTypes = aspectJAdviceMethod.getParameterTypes();
    // 方法实例
    this.aspectJAdviceMethod = aspectJAdviceMethod;
    // aspectJ的advisor工厂
    this.aspectJAdvisorFactory = aspectJAdvisorFactory;
    // aspectJ实例工厂
    this.aspectInstanceFactory = aspectInstanceFactory;
    // 切面顺序
    this.declarationOrder = declarationOrder;
    // 切面类名称
    this.aspectName = aspectName;
    // 是否需要延时加载
    if (aspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
        // Static part of the pointcut is a lazy type.
        Pointcut preInstantiationPointcut = Pointcuts.union(
                aspectInstanceFactory.getAspectMetadata().getPerClausePointcut(), this.declaredPointcut);

        // Make it dynamic: must mutate from pre-instantiation to post-instantiation state.
        // If it's not a dynamic pointcut, it may be optimized out
        // by the Spring AOP infrastructure after the first evaluation.
        this.pointcut = new PerTargetInstantiationModelPointcut(
                this.declaredPointcut, preInstantiationPointcut, aspectInstanceFactory);
        this.lazy = true;
    }
    else {
        // A singleton aspect.
        // singleton模型的aspect
        this.pointcut = this.declaredPointcut;
        this.lazy = false;
        // 将切面中的advice进行实例化
        this.instantiatedAdvice = instantiateAdvice(this.declaredPointcut);
    }
}
  1. InstantiationModelAwarePointcutAdvisorImpl是advisor的子类.在这个构造函数内对传入的属性进行了设置,然后根据当前的切面模型决定是否需要延迟加载.
  2. 通常我们的切面类都是singleton的,所有会直接执行instantiateAdvice.
  • org.springframework.aop.aspectj.annotation.InstantiationModelAwarePointcutAdvisorImpl#instantiateAdvice
private Advice instantiateAdvice(AspectJExpressionPointcut pointcut) {
    Advice advice = this.aspectJAdvisorFactory.getAdvice(this.aspectJAdviceMethod, pointcut,
            this.aspectInstanceFactory, this.declarationOrder, this.aspectName);
    return (advice != null ? advice : EMPTY_ADVICE);
}

这里直接转发给了this.aspectJAdvisorFactory.getAdvice这个方法.继续跟踪.

  • org.springframework.aop.aspectj.annotation.ReflectiveAspectJAdvisorFactory#getAdvice
public Advice getAdvice(Method candidateAdviceMethod, AspectJExpressionPointcut expressionPointcut,
        MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {
    // 获取切面类Class
    Class<?> candidateAspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
    // 校验合法性
    validate(candidateAspectClass);
    // 获取切面方法上的注解
    AspectJAnnotation<?> aspectJAnnotation =
            AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
    if (aspectJAnnotation == null) {
        return null;
    }

    // If we get here, we know we have an AspectJ method.
    // Check that it's an AspectJ-annotated class
    if (!isAspect(candidateAspectClass)) {
        throw new AopConfigException("Advice must be declared inside an aspect type: " +
                "Offending method '" + candidateAdviceMethod + "' in class [" +
                candidateAspectClass.getName() + "]");
    }

    if (logger.isDebugEnabled()) {
        logger.debug("Found AspectJ method: " + candidateAdviceMethod);
    }

    AbstractAspectJAdvice springAdvice;
    // 使用switch来判断当前advice类型
    switch (aspectJAnnotation.getAnnotationType()) {
        // pointcut不解析
        case AtPointcut:
            if (logger.isDebugEnabled()) {
                logger.debug("Processing pointcut '" + candidateAdviceMethod.getName() + "'");
            }
            return null;
        // around类型的Advice
        case AtAround:
            springAdvice = new AspectJAroundAdvice(
                    candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
            break;
        // before类型的Advice
        case AtBefore:
            springAdvice = new AspectJMethodBeforeAdvice(
                    candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
            break;
        // after类型的Advice
        case AtAfter:
            springAdvice = new AspectJAfterAdvice(
                    candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
            break;
        // afterReturning类型的Advice
        case AtAfterReturning:
            springAdvice = new AspectJAfterReturningAdvice(
                    candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
            AfterReturning afterReturningAnnotation = (AfterReturning) aspectJAnnotation.getAnnotation();
            if (StringUtils.hasText(afterReturningAnnotation.returning())) {
                springAdvice.setReturningName(afterReturningAnnotation.returning());
            }
            break;
        // afterThrowing类型的Advice
        case AtAfterThrowing:
            springAdvice = new AspectJAfterThrowingAdvice(
                    candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
            AfterThrowing afterThrowingAnnotation = (AfterThrowing) aspectJAnnotation.getAnnotation();
            if (StringUtils.hasText(afterThrowingAnnotation.throwing())) {
                springAdvice.setThrowingName(afterThrowingAnnotation.throwing());
            }
            break;
        default:
            throw new UnsupportedOperationException(
                    "Unsupported advice type on method: " + candidateAdviceMethod);
    }

    // Now to configure the advice...
    // 设置AspectName、DeclarationOrder,为后期执行调用链的时候做准备
    springAdvice.setAspectName(aspectName);
    springAdvice.setDeclarationOrder(declarationOrder);
    String[] argNames = this.parameterNameDiscoverer.getParameterNames(candidateAdviceMethod);
    if (argNames != null) {
        springAdvice.setArgumentNamesFromStringArray(argNames);
    }
    springAdvice.calculateArgumentBindings();

    return springAdvice;
}
  1. 解析Advice之前,Spring又又又对切面类进行了一次校验.
  2. 解析Advice,根据当前方法上的注解匹配对应的advice.例如:around、before、after、afterReturning、afterThrowing.
  3. 为advice实例配置切面名称、参数名称、声明顺序等.

OK,至此,Advice实例就被解析成功了.此时的InstantiationModelAwarePointcutAdvisorImpl成员属性中携带了pointcut+advice.

梳理加载Advisors的整体流程.

流程图

扩展阅读

【小家Spring】Spring AOP中@Pointcut切入点表达式最全面使用介绍
【小家Spring】Spring AOP核心类Pointcut解析,对PointcutExpression切点表达式解析原理分析(以AspectJExpressionPointcut为例)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 160,165评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,720评论 1 298
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,849评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,245评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,596评论 3 288
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,747评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,977评论 2 315
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,708评论 0 204
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,448评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,657评论 2 249
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,141评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,493评论 3 258
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,153评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,108评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,890评论 0 198
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,799评论 2 277
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,685评论 2 272

推荐阅读更多精彩内容