美文网首页Springspring framework
[Spring]AnnotationAwareAspectJAu

[Spring]AnnotationAwareAspectJAu

作者: AbstractCulture | 来源:发表于2021-04-24 17:03 被阅读0次

    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为例)

    相关文章

      网友评论

        本文标题:[Spring]AnnotationAwareAspectJAu

        本文链接:https://www.haomeiwen.com/subject/qedlrltx.html