跟着小马哥学系列之 Spring AOP(AspectJAdvisorFactory 详解)

学好路更宽,钱多少加班。 ——小马哥

版本修订

  • 2021.5.19:去除目录

简介

大家好,我是小马哥成千上万粉丝中的一员!2019年8月有幸在叩丁狼教育举办的猿圈活动中知道有这么一位大咖,从此结下了不解之缘!此系列在多次学习极客时间《小马哥讲Spring AOP 编程思想》基础上形成的个人一些总结。希望能帮助各位小伙伴, 祝小伙伴早日学有所成。

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 的实例。

类图

跟着小马哥学系列之 Spring AOP(AspectJAdvisorFactory 详解)_第1张图片

  • 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;
}

总结(一张图搞定)

跟着小马哥学系列之 Spring AOP(AspectJAdvisorFactory 详解)_第2张图片

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

你可能感兴趣的:(spring,aop,java,spring)