版本修订

  • 2021.5.19:去除目录


AspectJAdvisorFactory 功能

Spring 整合 AspectJ,对 AspectJ 部分注解语法的支持(详情见 AspectJExpressionPointcut#SUPPORTED_PRIMITIVES)。 通过标注 @Aspect 注解类的元信息(AspectMetadata)获取 Advisor 列表或者根据指定的 Advice 方法(标注 AspectJ 注解的方法或者字段(@Before、@After、@AfterReturning、@AfterThrowing、@Around以及@DeclareParents))获取 Advisor 或者 Advice

相关类/接口介绍

AspectMetadata

AspectJ aspect 类的元数据(字段 aspectName 和 aspectClass),附加了一个 Spring AOP Pointcut
对于每个条款(字段 perClausePointcut)。使用 AspectJ 5 AJType 反射 API(字段 ajType),使我们能够使用不同的 AspectJ 实例化模型,如singleton、pertarget 和 perthis

AspectInstanceFactory

为了与 Spring bean 工厂解耦,该接口提供了获取 AspectJ aspect 实例。扩展 Ordered 接口以表示底层 aspect 链中的顺序。

MetadataAwareAspectInstanceFactory

AspectInstanceFactory 的子接口,它返回与 AspectJ 注释关联的元信息 AspectMetadata.

LazySingletonAspectInstanceFactoryDecorator

具有延迟、单例、委派特点来创建 aspect实例

  • 延迟:如果不获取 aspect 对象,则不会进行实例化,
  • 单例:如果已经实例化了则是同一个对象(内部关联了一个 materialized 字段)
  • 委派:通过构造器传入 MetadataAwareAspectInstanceFactory 对象在获取 aspect 实例时,通过字段 maaif 去获取实例
BeanFactoryAspectInstanceFactory

由 Spring IoC 容器根据 aspect bean 名称和类型来创建 aspect 实例

PrototypeAspectInstanceFactory

由 Spring IoC 提供的原型支持的 AspectInstanceFactory,bean 作用域必须是 原型(Prototype)

SimpleAspectInstanceFactory

通过 Java 反射调用无参构造器获取 aspect 实例

SimpleMetadataAwareAspectInstanceFactory

实现了 MetadataAwareAspectInstanceFactory 和扩展了 SimpleAspectInstanceFactory 。多了 AspectMetadata 信息

InstantiationModelAwarePointcutAdvisorImpl

AspectJPointcutAdvisor 的内部实现。请注意,每个目标方法都将有一个该 advisor 的实例。

类图

小马哥 Java 训练营 官网 jasonma小马哥_spring

  • Advisor:参见我写的这篇 AdvisorChainFactory 详解 中有说明
  • PointcutAdvisor:扩展了 Advisor 接口具有获取 Pointcut 能力
  • InstantiationModelAwarePointcutAdvisor:该接口被 Spring AOP Advisor 实现,包装了可能具有延迟初始化策略的 AspectJ aspect。例如,perThis 实例化模型意味着 advice 的延迟初始化。
  • Ordered:可以定义顺序以便哪个 advice/advisor 先执行
  • AspectJPrecedenceInformation:接口将由不同类型的 advice/advisor 实现,这些类型可以提供按 AspectJ 的优先规则对 advice/advisor 进行排序所需的信息。

AbstractAspectJAdvisorFactory

AspectJAdvisorFactory 的抽象基类,可以从满足 AspectJ 5 注解语法的 AspectJ 类中创建 Spring AOP Advisor。此类处理注解解析和验证功能。它实际上并不生成 Spring AOP Advisors,被推迟到子类。

方法解读

isAspect

如果有 @Aspect 注解,并且不是AspectJ 编译器编译的,是适合 Spring AOP 系统使用的 AspectJ aspect。

@Override
public boolean isAspect(Class<?> clazz) {
	// 类上是否有 @Aspect 注解同时不能是由 AspectJ 编译器生成的类(字段名称以 ajc$ 开头)
	return (hasAspectAnnotation(clazz) && !compiledByAjc(clazz));
}

validate

给定的类是否是有效的 AspectJ aspect 类

public void validate(Class<?> aspectClass) throws AopConfigException {
	// 父类有 @Aspect 注解但不是抽象的那就是错误
	if (aspectClass.getSuperclass().getAnnotation(Aspect.class) != null &&
			!Modifier.isAbstract(aspectClass.getSuperclass().getModifiers())) {
		throw new AopConfigException("[" + aspectClass.getName() + "] cannot extend concrete aspect [" +
				aspectClass.getSuperclass().getName() + "]");
	}
	// 获取 AjType 对象(AjTypeSystem 内部关联一个 Map,类对象作为 key,把 AjTypeImpl 对象 包装成 WeakReference 对象作为 value) 
	AjType<?> ajType = AjTypeSystem.getAjType(aspectClass);
	// 类上没有 @Aspect 注解报错
	if (!ajType.isAspect()) {
		throw new NotAnAtAspectException(aspectClass);
	}
	// @Aspect value 代表 aspect 实例化模型默认是 SINGLETON, 不支持 PERCFLOW 和 PERCFLOWBELOW 类型
	if (ajType.getPerClause().getKind() == PerClauseKind.PERCFLOW) {
		throw new AopConfigException(aspectClass.getName() + " uses percflow instantiation model: " +
				"This is not supported in Spring AOP.");
	}
	if (ajType.getPerClause().getKind() == PerClauseKind.PERCFLOWBELOW) {
		throw new AopConfigException(aspectClass.getName() + " uses percflowbelow instantiation model: " +
				"This is not supported in Spring AOP.");
	}
}

ReflectiveAspectJAdvisorFactory

继承 AbstractAspectJAdvisorFactory 。可以从满足 AspectJ 5 注解语法的 Aspect 类中创建 Spring AOP Advisor,通过反射调用相对应的 advice 方法

METHOD_COMPARATOR 属性

同一个 asepct 内 advice 方法排序比较器,它由 ConvertingComparator 和 InstanceComparator + String 组成。

InstanceComparator

根据任意的类顺序比较对象。允许对象根据它们所继承的类的类型进行排序,如果两个对象都是相同类型的实例,这个比较器将返回 0。如果需要额外的排序,可以考虑使用 Comparator.thenComparing(Comparator)。

public class InstanceComparator<T> implements Comparator<T> {

	private final Class<?>[] instanceOrder;

	// instanceOrder 在比较对象时应该使用的类的有序列表。列表中较早的类将被赋予更高的优先级。
	public InstanceComparator(Class<?>... instanceOrder) {
		Assert.notNull(instanceOrder, "'instanceOrder' array must not be null");
		this.instanceOrder = instanceOrder;
	}

	// 比较时调用该方法
	@Override
	public int compare(T o1, T o2) {
		// 获取根据类对象获取在列表中的顺序
		int i1 = getOrder(o1);
		int i2 = getOrder(o2);
		// 根据列表中的顺序进行比较,列表中较早的类将被赋予更高的优先级。
		return (Integer.compare(i1, i2));
	}

	private int getOrder(@Nullable T object) {
		if (object != null) {
			for (int i = 0; i < this.instanceOrder.length; i++) {
			
				if (this.instanceOrder[i].isInstance(object)) {
					return i;
				}
			}
		}
		return this.instanceOrder.length;
	}

}

ConvertingComparator

在比较之前进行转换的比较器。在将每个值传递给基础 Comparator 之前,将使用指定的 Converter 对其进行转换。

// 在调用 compare 比较的时候,会先转换,再调用比较器的 compare 方法
@Override
public int compare(S o1, S o2) {
	T c1 = this.converter.convert(o1);
	T c2 = this.converter.convert(o2);
	return this.comparator.compare(c1, c2);
}

METHOD_COMPARATOR 大解密

private static final Comparator<Method> METHOD_COMPARATOR;

static {
	Comparator<Method> adviceKindComparator = new ConvertingComparator<>(
			// 构建一个实例比较器以类的在列表中的顺序来比较大小
			new InstanceComparator<>(
					Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class),
			// 把方法转换为 AspectJAnnotation 对象
			(Converter<Method, Annotation>) method -> {
				AspectJAnnotation<?> annotation =
					AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(method);
				return (annotation != null ? annotation.getAnnotation() : null);
			});
		// 按照方法名称进行比较(String 字符串(按 ASCII 码)比较,ASCII 码小的在前)
	Comparator<Method> methodNameComparator = new ConvertingComparator<>(Method::getName);
	// 如果 adviceKindComparator  比较结果相等则按方法名称进行比较
	METHOD_COMPARATOR = adviceKindComparator.thenComparing(methodNameComparator);
}

方法解读

getPointcut

通过 AspectJ Advice 注解获取 AspectJ 语法表达式的 Pointcut

@Nullable
private AspectJExpressionPointcut getPointcut(Method candidateAdviceMethod, Class<?> candidateAspectClass) {
	// 通过方法上是否标有 @Pointcut, @Around, @Before,@After, @AfterReturning,  @AfterThrowing 
	// 然后再通过注解上的 value 或者 pointcut 属性获取 AspectJAnnotation 实例
	AspectJAnnotation<?> aspectJAnnotation =
			AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
	if (aspectJAnnotation == null) {
		return null;
	}
    // 通过 aspect 类构建 AspectJExpressionPointcut 实例
	AspectJExpressionPointcut ajexp =
			new AspectJExpressionPointcut(candidateAspectClass, new String[0], new Class<?>[0]);
	// 设置 pointcut 表达式
	ajexp.setExpression(aspectJAnnotation.getPointcutExpression());
	if (this.beanFactory != null) {
		// 设置 beanFactory,主要获取 beanFactory 的 ClassLoader
		ajexp.setBeanFactory(this.beanFactory);
	}
	return ajexp;
}

List getAdvisors

为给定 aspect 实例上所有标注 AspectJ Advice 注解的方法/字段构建 Spring AOP advisor

// 通过 aspect 类获取除了标注 @Pointcut 注解和合成以及桥接的方法之外的所有方法,然后进行排序
private List<Method> getAdvisorMethods(Class<?> aspectClass) {
	final List<Method> methods = new ArrayList<>();
	ReflectionUtils.doWithMethods(aspectClass, method -> {
		// 通过 aspect 类获取所有除了标注 Pointcut 注解和合成以及桥接的方法
		if (AnnotationUtils.getAnnotation(method, Pointcut.class) == null) {
			methods.add(method);
		}
	}, ReflectionUtils.USER_DECLARED_METHODS);
	// 进行排序(排序规则在 METHOD_COMPARATOR 属性中已说明)
	methods.sort(METHOD_COMPARATOR);
	return methods;
}



@Override
public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {
	// 通过 aspect 实例工厂获取 aspect 所在类
	Class<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
	// 通过 aspect 实例工厂获取 aspect 名称
	String aspectName = aspectInstanceFactory.getAspectMetadata().getAspectName();
	// 验证 aspect 类父类如果有 @Aspect 注解则其必须是抽象类
	validate(aspectClass);

	//我们需要用装饰器来包装 MetadataAwareAspectInstanceFactory 只实例化一次(前面 相关类/接口介绍 有说明)。
	MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory =
			new LazySingletonAspectInstanceFactoryDecorator(aspectInstanceFactory);

	List<Advisor> advisors = new ArrayList<>();
	// 获取排序好的方法
	for (Method method : getAdvisorMethods(aspectClass)) {
		// 调用4个参数的重载方法获取 Advisor
		Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, advisors.size(), aspectName);
		if (advisor != null) {
			advisors.add(advisor);
		}
	}

	// 如果它是 PERTARGET 的 aspect,则创建虚拟实例化 aspect(默认是 SINGLETON 一般不会满足条件)
	if (!advisors.isEmpty() && lazySingletonAspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
		Advisor instantiationAdvisor = new SyntheticInstantiationAdvisor(lazySingletonAspectInstanceFactory);
		advisors.add(0, instantiationAdvisor);
	}

	// 寻找 aspect 中定义 introduction 字段(@DeclareParents 注解).
	for (Field field : aspectClass.getDeclaredFields()) {
		// 要是有 @DeclareParents 返回 DeclareParentsAdvisor 实例,加载 Advisor 列表的末尾
		Advisor advisor = getDeclareParentsAdvisor(field);
		if (advisor != null) {
			advisors.add(advisor);
		}
	}

	return advisors;
}

Advisor getAdvisor

从给定 AspectJ advice 方法.构建一个 Spring AOP Advisor

/**
 * 
 * @param candidateAdviceMethod  advice 方法
 * @param expressionPointcut     AspectJ 表达式 pointcut
 * @param aspectInstanceFactory  aspect 实例工厂
 * @param declarationOrder       在同一个 aspect 中定义的顺序(5.2.7 之前 最终 advice 会在 后置/异常 advice 之前执行就因为这个定义的有问题 )
 * @param aspectName             aspect 名称
 */
@Override
@Nullable
public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory,
		int declarationOrderInAspect, String aspectName) {
	// 验证 aspect 类父类如果有 @Aspect 注解则其必须是抽象类
	validate(aspectInstanceFactory.getAspectMetadata().getAspectClass());
	// 获取 AspectJExpressionPointcut
	AspectJExpressionPointcut expressionPointcut = getPointcut(
			candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass());
	if (expressionPointcut == null) {
		return null;
	}
	// 返回 InstantiationModelAwarePointcutAdvisorImpl 对象
	return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,
			this, aspectInstanceFactory, declarationOrderInAspect, aspectName);
}

getAdvice

从给定 AspectJ advice 方法.构建一个 Spring AOP Advice

/**
 * 
 * @param candidateAdviceMethod  advice 方法
 * @param expressionPointcut     AspectJ 表达式 pointcut
 * @param aspectInstanceFactory  aspect 实例工厂
 * @param declarationOrder       在同一个 aspect 中定义的顺序(5.2.7 之前 最终 advice 会在 后置/异常 advice 之前执行就因为这个定义的有问题 )
 * @param aspectName             aspect 名称
 */
@Override
@Nullable
public Advice getAdvice(Method candidateAdviceMethod, AspectJExpressionPointcut expressionPointcut,
		MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {

	Class<?> candidateAspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
	// 验证 aspect 类父类如果有 @Aspect 注解则其必须是抽象类
	validate(candidateAspectClass);
	// 根据 advice 方法 标注 AspectJ Advice 注解获取注解元信息
	AspectJAnnotation<?> aspectJAnnotation =
			AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
	if (aspectJAnnotation == null) {
		return null;
	}

	// 验证 aspect 类上是否有 @Aspect 注解
	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;
	// 根据 advice 方法标注的 AspectJ Advice 注解类型( @Pointcut 则返回 null)不同的 Advice 并设置相关参数
	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())) {
			    // 对应 @AfterReturing returning 属性设置用于后续参数绑定
				springAdvice.setReturningName(afterReturningAnnotation.returning());
			}
			break;
		case AtAfterThrowing:
			springAdvice = new AspectJAfterThrowingAdvice(
					candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
			AfterThrowing afterThrowingAnnotation = (AfterThrowing) aspectJAnnotation.getAnnotation();
			if (StringUtils.hasText(afterThrowingAnnotation.throwing())) {
				// 对应 @AfterThrowing throwing 属性设置用于后续参数绑定
				springAdvice.setThrowingName(afterThrowingAnnotation.throwing());
			}
			break;
		default:
			throw new UnsupportedOperationException(
					"Unsupported advice type on method: " + candidateAdviceMethod);
	}

	// aspect 名称设置
	springAdvice.setAspectName(aspectName);
	// 顺序设置
	springAdvice.setDeclarationOrder(declarationOrder);
	// 如果注解有 argNames 属性则设置参数
	String[] argNames = this.parameterNameDiscoverer.getParameterNames(candidateAdviceMethod);
	if (argNames != null) {
		//  argumentNames 属性设置
		springAdvice.setArgumentNamesFromStringArray(argNames);
	}
	// 进行参数绑定
	springAdvice.calculateArgumentBindings();

	return springAdvice;
}

总结(一张图搞定)

小马哥 Java 训练营 官网 jasonma小马哥_AOP_02

关于 Advice 细节可以参阅我的另外写的 跟着小马哥学系列之 Spring AOP( Advice 组件详解)