• AOP原理分析《五》- 增强器的获取细节补充


    获取增强器细节补充

    先介绍下几个核心类
    接口功能说明
    AspectJAdvisorFactory用来创建增强方法的工厂一般实现类是:ReflectiveAspectJAdvisorFactory
    AspectJExpressionPointcut封装了切入点即@PointCut注解的信息
    InstantiationModelAwarePointcutAdvisorImpl封装了增强器信息封装思想
    Advice增强器增强器是有多种类型的,关于增强器的介绍见下表
    再介绍不同类型的增强器(Advice):
    类型功能说明
    AspectJAroundAdvice环绕增强对应@Around注解
    AspectJMethodBeforeAdvice前置增强对应@Before注解
    AspectJAfterAdvice后置增强(要求无异常)对应@After注解
    AspectJAfterReturningAdvice返回增强对应@AfterReturning注解
    AspectJAfterThrowingAdvice异常增强对应@AfterThrowing注解
    说明上文为何在源码没有看到@Before注解等

    @Before注解的解析必然在处理候选增强器的某个步骤遗漏了。
    重看查找候选增强器的方法

    protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
        // 查找"候选的"增强方法
        List<Advisor> candidateAdvisors = findCandidateAdvisors();
    
        // 查找适应当前bean的增强方法
        List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
    
        // 拓展advisors
        extendAdvisors(eligibleAdvisors);
        if (!eligibleAdvisors.isEmpty()) {
            // 排序
            eligibleAdvisors = sortAdvisors(eligibleAdvisors);
        }
        return eligibleAdvisors;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    查看findCandidateAdvisors的实现发现有2个,但是我们是从AnnotationAwareAspectJAutoProxyCreator调用过来的,
    所以这里是调用的子类的findCandidateAdvisors方法。继续看子类的findCandidateAdvisors方法。

    protected List<Advisor> findCandidateAdvisors() {
        // Add all the Spring advisors found according to superclass rules.
        // 添加所有的Spring的advisors(根据父类规则找到的。直白一点就是处理xml和实现Advisor接口的)
        List<Advisor> advisors = super.findCandidateAdvisors();
        // Build Advisors for all AspectJ aspects in the bean factory.
        // 直白一点就是处理 @Aspect 注解的
        if (this.aspectJAdvisorsBuilder != null) {
            advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
        }
        return advisors;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    在该方法中,先调用父类的findCandidateAdvisors得到一批候选增强器,其实就是通过实现Advisor接口来增强的方法(上文已经分析了);
    而在buildAspectJAdvisors也得到一批增强器,其实就是通过@AspectJ注解来增强的方法。继续看buildAspectJAdvisors方法。

    // 查找AspectJ注解的bean在当前容器中,并返回AOP Advisors来表示它们
    public List<Advisor> buildAspectJAdvisors() {
        List<String> aspectNames = this.aspectBeanNames;
    
        // 1、第一次调用代码时才会进入(因为只有初始化时才会为null,执行过一次后就会是一个集合)
        if (aspectNames == null) {
            synchronized (this) {
                aspectNames = this.aspectBeanNames;
                if (aspectNames == null) {
                    List<Advisor> advisors = new ArrayList<>();
                    aspectNames = new ArrayList<>();
                    // 2、获取容器中所有对象名称(不像父类一样只获取Advisor接口的bean名称)
                    String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
                            this.beanFactory, Object.class, true, false);
                    // 3、遍历
                    for (String beanName : beanNames) {
                        // 4、判断beanType是否是一个切面(是不是有@Aspect注解)
                        if (this.advisorFactory.isAspect(beanType)) {
                            aspectNames.add(beanName);
                            AspectMetadata amd = new AspectMetadata(beanType, beanName);
                            if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
                                MetadataAwareAspectInstanceFactory factory =
                                        new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
    
                                // -------------核心方法------------
                                // 5、获取切切面的"增强(advisor)"
                                List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
                                if (this.beanFactory.isSingleton(beanName)) {
                                    this.advisorsCache.put(beanName, classAdvisors);
                                }
                                else {
                                    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;
                }
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53

    重点看下获取切面增强的核心方法

    List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
    
    • 1

    遍历该类的每个方法,查找增强:

    	public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {
    		List<Advisor> advisors = new ArrayList<>();
    		// 查找切面类的Advisors方法
    		for (Method method : getAdvisorMethods(aspectClass)) {
    			Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, advisors.size(), aspectName);
    			if (advisor != null) {
    				advisors.add(advisor);
    			}
    		}
    		return advisors;
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    查看方法是否配置了@Before等切面注解,随后把切面方法初始化为一个Advisor增强。

    public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory,
        int declarationOrderInAspect, String aspectName) {
    
        validate(aspectInstanceFactory.getAspectMetadata().getAspectClass());
    
        // 返回封装了注解、表达式等AspectJ计算规则的类
        AspectJExpressionPointcut expressionPointcut = getPointcut(
        candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass());
        if (expressionPointcut == null) {
            return null;
        }
    
    	// 针对method创建增强,并封装为InstantiationModelAwarePointcutAdvisorImpl对象
        return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,
        this, aspectInstanceFactory, declarationOrderInAspect, aspectName);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    实例化增强方法:

    this.instantiatedAdvice = instantiateAdvice(this.declaredPointcut);
    
    • 1

    实例化增强方法的具体实现:

    	@Nullable
    	public Advice getAdvice(Method candidateAdviceMethod, AspectJExpressionPointcut expressionPointcut,
    			MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {
    
    		// 是诸如 @Before 等的注解
    		AspectJAnnotation<?> aspectJAnnotation =
    				AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
    		if (aspectJAnnotation == null) {
    			return null;
    		}
    
    		AbstractAspectJAdvice springAdvice;
    
    		// 判断注解的类型
    		switch (aspectJAnnotation.getAnnotationType()) {
    			case AtPointcut:
    				if (logger.isDebugEnabled()) {
    					logger.debug("Processing pointcut '" + candidateAdviceMethod.getName() + "'");
    				}
    				return null;
    			case AtAround:
    				springAdvice = new AspectJAroundAdvice(
    						candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
    				break;
    			case AtBefore:
    				springAdvice = new AspectJMethodBeforeAdvice(
    						candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
    				break;
    			case AtAfter:
    				springAdvice = new AspectJAfterAdvice(
    						candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
    				break;
    			case AtAfterReturning:
    				springAdvice = new AspectJAfterReturningAdvice(
    						candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
    				AfterReturning afterReturningAnnotation = (AfterReturning) aspectJAnnotation.getAnnotation();
    				if (StringUtils.hasText(afterReturningAnnotation.returning())) {
    					springAdvice.setReturningName(afterReturningAnnotation.returning());
    				}
    				break;
    			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);
    		}
    		return springAdvice;
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54

    经过了一层层的剥洋葱似的源码分析,终于找到了@Before等注解的处理的地方,不同的注解类型被实例化为不同类型的Advice对象,
    不同类型的Advice对象被封装成了Advisor对象(实现类是:InstantiationModelAwarePointcutAdvisorImpl),
    所以Advice或Advisor名字不同但其实表达的意思基本是一样的。

    补充说明一下增强器的分类

    在疑问中提出了这个问题,从代码上看是分IntroductionAdvisorPointcutAdvisor两类的。
    而我们通过@AspectJ注解方法的都是封装成了InstantiationModelAwarePointcutAdvisorImpl类,而它就是PointcutAdvisor,
    所以一般关注PointcutAdvisor类型就够了

    总结获取增强器

    1、获取候选增强器基本可以等同为吧标注了特殊注解的方法信息等封装为InstantiationModelAwarePointcutAdvisorImpl实例返回,
    这个实例就代表了Advisor增强
    2、适配当前bean的增强器,本质就是通过matches方法比较method是不是符合切入点表达式的规则。
    本质上是一个表达式语言的解析。

    传送门:保姆式Spring5源码解析

    欢迎与作者一起交流技术和工作生活

    联系作者

  • 相关阅读:
    P1162 填涂颜色(bfs)
    访问者模式(大话设计模式)C/C++版本
    python使用pip install安装django报错
    数据结构-01 数据结构基本概念,算法时间复杂度,空间复杂度
    mysq基础语句+高级操作(学这篇就够了)
    leetcode 560.和为K的子数组 前缀和+哈希表优化
    moviepy 视频剪切,拼接,音频处理
    linux安装mysql
    操作系统-《王道 操作系统》
    基于Docker和MongoDB部署NodeBB论坛系统
  • 原文地址:https://blog.csdn.net/yuchangyuan5237/article/details/126816034