Spring 源码阅读 53:查找注解配置的切面增强逻辑(3)- 创建 Advisor

简介: 本文分析了 Spring 查找注解配置的 AOP 切面信息的最后一部分,Spring 会将查找到的所有增强类中的方法进行筛选,找到所有的增强方法,并将其封装成对应的 Advisor。

基于 Spring Framework v5.2.6.RELEASE

接上篇:Spring 源码阅读 52:查找注解配置的切面增强逻辑(2)- 查找增强方法

概述

查找基于注解的切面配置增强逻辑的源码分析,总共分三篇,这是第三篇,强烈建议按顺序阅读。

前面我们分析了 Spring 如何从容器中找到切面配置类对应的 Bean,以及从中找到配置增强逻辑的方法,本文将分析最后一个关键的步骤,就是如何将找到的增强方法封装成 Advisor。

创建 Advisor

作为上一篇的后续,本文的分析从 ReflectiveAspectJAdvisorFactory 的getAdvisor方法入手。

// org.springframework.aop.aspectj.annotation.ReflectiveAspectJAdvisorFactory#getAdvisor@Override@NullablepublicAdvisorgetAdvisor(MethodcandidateAdviceMethod, MetadataAwareAspectInstanceFactoryaspectInstanceFactory,
intdeclarationOrderInAspect, StringaspectName) {
validate(aspectInstanceFactory.getAspectMetadata().getAspectClass());
AspectJExpressionPointcutexpressionPointcut=getPointcut(
candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass());
if (expressionPointcut==null) {
returnnull;
   }
returnnewInstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,
this, aspectInstanceFactory, declarationOrderInAspect, aspectName);
}

首先对增强方法所在的切面配置类进行验证,然后通过getPointcut获取增强方法对应的切入点信息。之后,在确保能够获取到切入点信息的情况下,通过构造方法创建 Advisor 对象,这里的 Advisor 对象类型是 InstantiationModelAwarePointcutAdvisorImpl 类型,其中包含了切入点信息、增强方法、切面配置类的 Bean 名称等重要信息。

因此,这里的重点有两个,一个是通过getPointcut方法获取切入点信息,另一个就是 Advisor 的创建,我们分别来看。

获取切入点信息

我们先进入getPointcut方法。

// org.springframework.aop.aspectj.annotation.ReflectiveAspectJAdvisorFactory#getPointcut@NullableprivateAspectJExpressionPointcutgetPointcut(MethodcandidateAdviceMethod, Class<?>candidateAspectClass) {
AspectJAnnotation<?>aspectJAnnotation=AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
if (aspectJAnnotation==null) {
returnnull;
   }
AspectJExpressionPointcutajexp=newAspectJExpressionPointcut(candidateAspectClass, newString[0], newClass<?>[0]);
ajexp.setExpression(aspectJAnnotation.getPointcutExpression());
if (this.beanFactory!=null) {
ajexp.setBeanFactory(this.beanFactory);
   }
returnajexp;
}

首先,会通过 AbstractAspectJAdvisorFactory 类的findAspectJAnnotationOnMethod方法获取方法上标记的增强注解信息,我们进入这个方法看一下。

@NullableprotectedstaticAspectJAnnotation<?>findAspectJAnnotationOnMethod(Methodmethod) {
for (Class<?>clazz : ASPECTJ_ANNOTATION_CLASSES) {
AspectJAnnotation<?>foundAnnotation=findAnnotation(method, (Class<Annotation>) clazz);
if (foundAnnotation!=null) {
returnfoundAnnotation;
      }
   }
returnnull;
}

其中的常量定义如下,也就是@Pointcut以及五种增强类型对应的注解。

privatestaticfinalClass<?>[] ASPECTJ_ANNOTATION_CLASSES=newClass<?>[] {
Pointcut.class, Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class};

findAspectJAnnotationOnMethod方法中,会遍历这些注解类,对于每一个遍历到的注解类型,如果发现给定的方法上标记了这个注解,那么就返回封装好的 AspectJAnnotation 注解信息,如果都没有匹配到,则返回空。

这个逻辑中还隐含了一个逻辑,如果一个注解在给定的方法上找到了,那么后面就不再判断了。

回到getPointcut方法中,如果上一步没有获取到注解信息,那么就说明当前要处理的方法不是一个增强方法,就不再处理了。

接下来,创建一个 AspectJExpressionPointcut 对象ajexp,将切面类的类型、增强注解中的切入点表达式、当前的 Spring 容器等赋值到ajexp的对应属性,最后,将它作为getPointcut方法的结果返回。

至此,getPointcut方法就结束了,最终返回一个 AspectJExpressionPointcut 类型的结果或者一个空值。我们接着看getAdvisor方法的另外一个关键步骤。

创建 Advisor 对象

如果上一步获取的切入点信息不为空的话,则会创建 Advisor 对象并返回。

returnnewInstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,
this, aspectInstanceFactory, declarationOrderInAspect, aspectName);

这里创建 Advisor 的方式是通过构造方法创建,它的具体类型是 InstantiationModelAwarePointcutAdvisorImpl,我们现通过继承关系了解一下这个类。

image.png

先对它的继承关系大致有个印象,然后我们看构造方法中的逻辑。

publicInstantiationModelAwarePointcutAdvisorImpl(AspectJExpressionPointcutdeclaredPointcut,
MethodaspectJAdviceMethod, AspectJAdvisorFactoryaspectJAdvisorFactory,
MetadataAwareAspectInstanceFactoryaspectInstanceFactory, intdeclarationOrder, StringaspectName) {
this.declaredPointcut=declaredPointcut;
this.declaringClass=aspectJAdviceMethod.getDeclaringClass();
this.methodName=aspectJAdviceMethod.getName();
this.parameterTypes=aspectJAdviceMethod.getParameterTypes();
this.aspectJAdviceMethod=aspectJAdviceMethod;
this.aspectJAdvisorFactory=aspectJAdvisorFactory;
this.aspectInstanceFactory=aspectInstanceFactory;
this.declarationOrder=declarationOrder;
this.aspectName=aspectName;
if (aspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
// Static part of the pointcut is a lazy type.PointcutpreInstantiationPointcut=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=newPerTargetInstantiationModelPointcut(
this.declaredPointcut, preInstantiationPointcut, aspectInstanceFactory);
this.lazy=true;
   }
else {
// A singleton aspect.this.pointcut=this.declaredPointcut;
this.lazy=false;
this.instantiatedAdvice=instantiateAdvice(this.declaredPointcut);
   }
}

其实并没有什么复杂的逻辑,就是将参数传入的各项信息复制给了对应的成员变量。

到这里,getAdvisor方法的原理也就分析完了。

findCandidateAdvisors 方法小结

经过三篇文章的分析,我们已经了解了 AnnotationAwareAspectJAutoProxyCreator 类中的findCandidateAdvisors方法作为被后处理器调用的方法,如何从当前容器中查找到所有的切面配置类,然后再从这些类中找到所有的增强方法并封装成对应的 Advisor 对象返回。

为了让后续的分析更加连贯,我们再回顾一下之前的内容。

  1. 我们最初从 AbstractAuthProxyCreator 类的wrapIfNecessary方法为入口,分析 Spring 如何在后处理器中为已经完成初始化的 Bean 实例创建 AOP 代理。
  2. wrapIfNecessary方法中,会通过getAdvicesAndAdvisorsForBean方法获取能够对当前 Bean 实例进行增强的 Advisor,这个工作又被交给了findEligibleAdvisors方法。
  3. findEligibleAdvisors方法中的第一步,就是获取到容器中所有能获取到的 Advisor。

前面的几篇文章,就是在分析如何从容器中获取到全部的 Advisor,我会将最近的几篇文章链接放在文章末尾以供回顾。下一篇讲开始分析之后的内容,也就是如何从全部的 Advisor 中找到与当前处理的 Bean 实例匹配的 Advisor。

总结

本文分析了 Spring 查找注解配置的 AOP 切面信息的最后一部分,Spring 会将查找到的所有增强类中的方法进行筛选,找到所有的增强方法,并将其封装成对应的 Advisor。


相关阅读:

目录
相关文章
|
19小时前
|
监控 Java 应用服务中间件
Spring Boot 源码面试知识点
【5月更文挑战第12天】Spring Boot 是一个强大且广泛使用的框架,旨在简化 Spring 应用程序的开发过程。深入了解 Spring Boot 的源码,有助于开发者更好地使用和定制这个框架。以下是一些关键的知识点:
19 6
|
19小时前
|
Java 应用服务中间件 测试技术
深入探索Spring Boot Web应用源码及实战应用
【5月更文挑战第11天】本文将详细解析Spring Boot Web应用的源码架构,并通过一个实际案例,展示如何构建一个基于Spring Boot的Web应用。本文旨在帮助读者更好地理解Spring Boot的内部工作机制,以及如何利用这些机制优化自己的Web应用开发。
16 3
|
19小时前
|
安全 Java 开发者
深入理解Spring Boot配置绑定及其实战应用
【4月更文挑战第10天】本文详细探讨了Spring Boot中配置绑定的核心概念,并结合实战示例,展示了如何在项目中有效地使用这些技术来管理和绑定配置属性。
11 1
|
19小时前
|
XML Java 数据格式
Spring高手之路18——从XML配置角度理解Spring AOP
本文是全面解析面向切面编程的实践指南。通过深入讲解切面、连接点、通知等关键概念,以及通过XML配置实现Spring AOP的步骤。
22 6
Spring高手之路18——从XML配置角度理解Spring AOP
|
19小时前
|
消息中间件 开发框架 Java
什么是Spring Boot 自动配置?
Spring Boot 是一个流行的 Java 开发框架,它提供了许多便利的功能和工具,帮助开发者快速构建应用程序。其中一个最引人注目的特性是其强大的自动配置功能。
9 0
|
19小时前
|
Java Spring
Spring文件配置以及获取
Spring文件配置以及获取
13 0
|
19小时前
|
存储 前端开发 Java
Spring Boot自动装配的源码学习
【4月更文挑战第8天】Spring Boot自动装配是其核心机制之一,其设计目标是在应用程序启动时,自动配置所需的各种组件,使得应用程序的开发和部署变得更加简单和高效。下面是关于Spring Boot自动装配的源码学习知识点及实战。
15 1
|
19小时前
|
传感器 人工智能 前端开发
JAVA语言VUE2+Spring boot+MySQL开发的智慧校园系统源码(电子班牌可人脸识别)Saas 模式
智慧校园电子班牌,坐落于班级的门口,适合于各类型学校的场景应用,班级学校日常内容更新可由班级自行管理,也可由学校统一管理。让我们一起看看,电子班牌有哪些功能呢?
101 4
JAVA语言VUE2+Spring boot+MySQL开发的智慧校园系统源码(电子班牌可人脸识别)Saas 模式
|
XML Java 数据格式
Spring生命周期以及如何在Spring启动时加入逻辑
Spring生命周期以及如何在Spring启动时加入逻辑
141 0
|
19小时前
|
Java 应用服务中间件 Maven
SpringBoot 项目瘦身指南
SpringBoot 项目瘦身指南
56 0