Spring AOP(三) Advisor类架构

39次阅读

共计 10344 个字符,预计需要花费 26 分钟才能阅读完成。

 Spring AOP 是 Spring 的两大基石之一,不了解其基础概念的同学可以查看这两篇文章 AOP 基本概念和修饰者模式和 JDK Proxy。如果从代码执行角度来看,Spring AOP 的执行过程分为四大步骤:

步骤一:Spring 框架生成 Advisor 实例,可以是 @Aspect,@Async 等注解生成的实例,也可以是程序员自定义的 AbstractAdvisor 子类的实例。
步骤二:Spring 框架在目标实例初始化完成后,也就是使用 BeanPostProcessor 的 postProcessAfterInitialization 方法,根据 Advisor 实例中切入点 Pointcut 的定义,选择出适合该目标对象的 Advisor 实例。
步骤三:Spring 框架根据 Advisor 实例生成代理对象。
步骤四:调用方法执行过程时,Spring 框架执行 Advisor 实例的通知 Advice 逻辑。

 由于这四个步骤涉及的源码量较大,一篇文章无法直接完全讲解完,本篇文章只讲解第一步 Advisor 实例生成的源码分析。接下来的文章我们就依次讲解一下后续步骤中比较关键的逻辑。
Advisor 类架构
  Spring 中有大量的机制都是通过 AOP 实现的,比如说 @Async 的异步调用和 @Transational。此外,用户也可以使用 @Aspect 注解定义切面或者直接继承 AbstractPointcutAdvisor 来提供切面逻辑。上述这些情况下,AOP 都会生成对应的 Advisor 实例。
 我们先来看一下 Advisor 的相关类图。首先看一下 org.aopalliance 包下的类图。aopalliance 是 AOP 组织下的公用包,用于 AOP 中方法增强和调用,相当于一个 jsr 标准,只有接口和异常,在 AspectJ、Spring 等 AOP 框架中使用。

 aopalliance 定义了 AOP 的通知 Advice 和连接点 Joinpoint 接口,并且还有继承上述接口的 MethodInterceptor 和 MethodInvocation。这两个类相信大家都很熟悉。
 然后我们来看一下 Spring AOP 中 Advisor 相关的类图。Advisor 是 Spring AOP 独有的概念,比较重要的类有 AbstractPointcutAdvisor 和 InstantiationModelAwarePointcutAdvisor。相关的讲解都在图中表明了,如果这张图中的概念和类同学们都熟识,那么对 AOP 的了解就已经很深入了。

获取所有 Advisor 实例
 AOP 生成 Advisor 实例的函数入口是 AbstractAdvisorAutoProxyCreator 的 findCandidateAdvisors 函数。
// AbstractAdvisorAutoProxyCreator.java 找出当前所有的 Advisor
protected List<Advisor> findCandidateAdvisors() {
Assert.state(this.advisorRetrievalHelper != null, “No BeanFactoryAdvisorRetrievalHelper available”);
return this.advisorRetrievalHelper.findAdvisorBeans();
}

// AnnotationAwareAspectJAutoProxyCreator,是 AbstractAdvisorAutoProxyCreator 的子类
@Override
protected List<Advisor> findCandidateAdvisors() {
// 调用父类的 findCandidateAdvisor 函数,一般找出普通的直接
// 继承 Advisor 接口的实例,比如说 `@Async` 所需的 `AsyncAnnotationAdvisor`
List<Advisor> advisors = super.findCandidateAdvisors();
// 为 AspectJ 的切面构造 Advisor,也就是说处理 @Aspect 修饰的类,生成上文中说的 `InstantiationModelAwarePointcutAdvisor` 实例
if (this.aspectJAdvisorsBuilder != null) {
advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
}
return advisors;
}
 相关的 ProxyCreator 也有一个类体系,不过太过繁杂,而且重要性不大,我们就先略过,直接将具体的类。由上边代码可知 AbstractAdvisorAutoProxyCreator 的 findCandidateAdvisors 函数是直接获取 Spring 容器中的 Advisor 实例,比如说 AsyncAnnotationAdvisor 实例,或者说我们自定义的 AbstractPointcutAdvisor 的子类实例。AdvisorRetrievalHelper 的 findAdvisorBeans 函数通过 BeanFactory 的 getBean 获取了所有类型为 Advisor 的实例。
 而 AnnotationAwareAspectJAutoProxyCreator 看其类名就可知,是与 AspectJ 相关的创建器,用来获取 @Aspect 定义的 Advisor 实例,也就是 InstantiationModelAwarePointcutAdvisor 实例。
 接下去我们看一下 BeanFactoryAspectJAdvisorsBuilder 的 buildAspectJAdvisors 函数,它根据 @Aspect 修饰的切面实例生成对应的 Advisor 实例。
public List<Advisor> buildAspectJAdvisors() {
List<String> aspectNames = this.aspectBeanNames;
// 第一次初始化,synchronized 加双次判断,和经典单例模式的写法一样。
if (aspectNames == null) {
synchronized (this) {
aspectNames = this.aspectBeanNames;
if (aspectNames == null) {
// Spring 源码并没有 buildAspectJAdvisorsFirstly 函数,为了方便理解添加。
// 获取 aspectNames,创建 Advisor 实例,并且存入 aspectFactoryCache 缓存
return buildAspectJAdvisorsFirstly();
}
}
}

if (aspectNames.isEmpty()) {
return Collections.emptyList();
}
List<Advisor> advisors = new ArrayList<>();
// 遍历 aspectNames, 依次获取对应的 Advisor 实例,或者是 MetadataAwareAspectInstanceFactory 生成的 Advisor 实例
for (String aspectName : aspectNames) {
List<Advisor> cachedAdvisors = this.advisorsCache.get(aspectName);
// cache 可以取到实例,该 Advisor 是单例的
if (cachedAdvisors != null) {
advisors.addAll(cachedAdvisors);
}
else {
// 取得 Advisor 对应的工厂类实例,再次生成 Advisor 实例,该 Advisor 是多实例的。
MetadataAwareAspectInstanceFactory factory = this.aspectFactoryCache.get(aspectName);
advisors.addAll(this.advisorFactory.getAdvisors(factory));
}
}
return advisors;
}
 buildAspectJAdvisors 函数执行时分为两种情况,第一个未初始化时,也就是 aspectNames 为 null 时,执行 buildAspectJAdvisorsFirstly 进行第一次初始化,在这一过程中生成切面名称列表 aspectBeanNames 和要返回的 Advisor 列表,并且将生成的 Advisor 实例放置到 advisorsCache 中。
 第二种情况则是已经初始化后再次调用,遍历 aspectNames,从 advisorsCache 取出对应的 Advisor 实例,或者从 advisorsCache 取出 Advisor 对应的工厂类对象,再次生成 Advisor 实例。
public List<Advisor> buildAspectJAdvisorsFirstly() {
List<Advisor> advisors = new ArrayList<>();
List<String> aspectNames = new ArrayList<>();
// 调用 BeanFactoryUtils 获取所有 bean 的名称
String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this.beanFactory, Object.class, true, false);
for (String beanName : beanNames) {
if (!isEligibleBean(beanName)) {
continue;
}
// 获取对应名称的 bean 实例
Class<?> beanType = this.beanFactory.getType(beanName);
if (beanType == null) {
continue;
}
/**
* AbstractAspectJAdvisorFactory 类的 isAspect 函数来判断是否为切面实例
* 判断条件为是否被 @Aspect 修饰或者是由 AspectJ 编程而来。
*/
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);
// 获取一个切面中所有定义的 Advisor 实例。一个切面可以定义多个 Advisor。
List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
// 单例模式,只需要将生成的 Advisor 添加到缓存
if (this.beanFactory.isSingleton(beanName)) {
this.advisorsCache.put(beanName, classAdvisors);
}
// 多实例模式,需要保存工厂类,便于下一次再次生成 Advisor 实例。
else {
this.aspectFactoryCache.put(beanName, factory);
}
advisors.addAll(classAdvisors);
}
else {
MetadataAwareAspectInstanceFactory factory =
new PrototypeAspectInstanceFactory(this.beanFactory, beanName);
this.aspectFactoryCache.put(beanName, factory);
advisors.addAll(this.advisorFactory.getAdvisors(factory));
}
}
}
this.aspectBeanNames = aspectNames;
return advisors;
}
 buildAspectJAdvisorsFirstly 函数的逻辑如下:

首先使用 BeanFactoryUtils 获取了 BeanFactory 中所有的 BeanName,然后进而使用 BeanFactory 获取所有的 Bean 实例。
遍历 Bean 实例,通过 ReflectiveAspectJAdvisorFactory 的 isAspect 函数判断该实例是否为切面实例,也就是被 @Aspect 注解修饰的实例。
如果是,则使用 ReflectiveAspectJAdvisorFactory,根据切面实例的定义来生成对应的多个 Advisor 实例,并且将其加入到 advisorsCache 中。

生成 InstantiationModelAwarePointcutAdvisorImpl 实例
 ReflectiveAspectJAdvisorFactory 的 getAdvisors 函数会获取 @Aspect 修饰的实例中所有没有被 @Pointcut 修饰的方法,然后调用 getAdvisor 函数,并且将这些方法作为参数。
public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory,
int declarationOrderInAspect, String aspectName) {

validate(aspectInstanceFactory.getAspectMetadata().getAspectClass());
// 获得该方法上的切入点条件表达式
AspectJExpressionPointcut expressionPointcut = getPointcut(
candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass());
if (expressionPointcut == null) {
return null;
}
// 生成 Advisor 实例
return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,
this, aspectInstanceFactory, declarationOrderInAspect, aspectName);
}

private AspectJExpressionPointcut getPointcut(Method candidateAdviceMethod, Class<?> candidateAspectClass) {
// 获得该函数上 @Pointcut, @Around, @Before, @After, @AfterReturning, @AfterThrowing 注解的信息
AspectJAnnotation<?> aspectJAnnotation =
AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
// 没有上述注解,则直接返回
if (aspectJAnnotation == null) {
return null;
}

AspectJExpressionPointcut ajexp =
new AspectJExpressionPointcut(candidateAspectClass, new String[0], new Class<?>[0]);
// 获得注解信息中的切入点判断表达式
ajexp.setExpression(aspectJAnnotation.getPointcutExpression());
if (this.beanFactory != null) {
ajexp.setBeanFactory(this.beanFactory);
}
return ajexp;
}

 getAdvisor 函数就是根据作为参数传入的切面实例的方法上的注解来生成 Advisor 实例,也就是 InstantiationModelAwarePointcutAdvisorImpl 对象。依据方法上的切入点表达式生成 AspectJExpressionPointcut。我们都知道 PointcutAdvisor 实例中必然有一个 Pointcut 和 Advice 实例。修饰在方法上的注解包括:@Pointcut, @Around, @Before, @After, @AfterReturning 和 @AfterThrowing,所以 InstantiationModelAwarePointcutAdvisorImpl 会依据不同的不同的注解生成不同的 Advice 通知。
public InstantiationModelAwarePointcutAdvisorImpl(AspectJExpressionPointcut declaredPointcut,
Method aspectJAdviceMethod, AspectJAdvisorFactory aspectJAdvisorFactory,
MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {
// …. 省略成员变量的直接赋值

// 单例模式时
this.pointcut = this.declaredPointcut;
this.lazy = false;
// 按照注解解析 Advice
this.instantiatedAdvice = instantiateAdvice(this.declaredPointcut);
}
 InstantiationModelAwarePointcutAdvisorImpl 的构造函数中会生成对应的 Pointcut 和 Advice。instantiateAdvice 函数调用了 ReflectiveAspectJAdvisorFactory 的 getAdvice 函数。
// ReflectiveAspectJAdvisorFactory
public Advice getAdvice(Method candidateAdviceMethod, AspectJExpressionPointcut expressionPointcut,
MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {

Class<?> candidateAspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
validate(candidateAspectClass);
// 获取 Advice 注解
AspectJAnnotation<?> aspectJAnnotation =
AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
if (aspectJAnnotation == null) {
return null;
}

// 检查是否为 AspectJ 注解
if (!isAspect(candidateAspectClass)) {
throw new AopConfigException(“Advice must be declared inside an aspect type: ” +
“Offending method ‘” + candidateAdviceMethod + “‘ in class [” +
candidateAspectClass.getName() + “]”);
}

AbstractAspectJAdvice springAdvice;
// 按照注解类型生成相应的 Advice 实现类
switch (aspectJAnnotation.getAnnotationType()) {
case AtPointcut:
if (logger.isDebugEnabled()) {
logger.debug(“Processing pointcut ‘” + candidateAdviceMethod.getName() + “‘”);
}
return null;
case AtAround: // @Before 生成 AspectJMethodBeforeAdvice
springAdvice = new AspectJAroundAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
break;
case AtBefore: // @After 生成 AspectJAfterAdvice
springAdvice = new AspectJMethodBeforeAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
break;
case AtAfter: // @AfterReturning 生成 AspectJAfterAdvice
springAdvice = new AspectJAfterAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
break;
case AtAfterReturning: // @AfterThrowing 生成 AspectJAfterThrowingAdvice
springAdvice = new AspectJAfterReturningAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
AfterReturning afterReturningAnnotation = (AfterReturning) aspectJAnnotation.getAnnotation();
if (StringUtils.hasText(afterReturningAnnotation.returning())) {
springAdvice.setReturningName(afterReturningAnnotation.returning());
}
break;
case AtAfterThrowing: // @Around 生成 AspectJAroundAdvice
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);
}
// 配置 Advice
springAdvice.setAspectName(aspectName);
springAdvice.setDeclarationOrder(declarationOrder);
// 获取方法的参数列表方法
String[] argNames = this.parameterNameDiscoverer.getParameterNames(candidateAdviceMethod);
if (argNames != null) {
// 设置参数名称
springAdvice.setArgumentNamesFromStringArray(argNames);
}
springAdvice.calculateArgumentBindings();

return springAdvice;
}
 至此,Spring AOP 就获取了容器中所有的 Advisor 实例,下一步在每个实例初始化完成后,根据这些 Advisor 的 Pointcut 切入点进行筛选,获取合适的 Advisor 实例,并生成代理实例。
后记
 Spring AOP 后续文章很快就会更新,请大家继续关注。

正文完
 0