学好路更宽,钱多少加班。 ——小马哥
大家好,我是小马哥成千上万粉丝中的一员!2019年8月有幸在叩丁狼教育举办的猿圈活动中知道有这么一位大咖,从此结下了不解之缘!此系列在多次学习极客时间《小马哥讲Spring AOP 编程思想》基础上形成的个人一些总结。希望能帮助各位小伙伴, 祝小伙伴早日学有所成。
Spring 整合 AspectJ,对 AspectJ 部分注解语法
的支持(详情见 AspectJExpressionPointcut#SUPPORTED_PRIMITIVES
)。 通过标注 @Aspect 注解类的元信息(AspectMetadata)获取 Advisor 列表或者根据指定的 Advice 方法(标注 AspectJ 注解的方法或者字段(@Before、@After、@AfterReturning、@AfterThrowing、@Around以及@DeclareParents))获取 Advisor
或者 Advice
。
AspectJ aspect
类的元数据(字段 aspectName 和 aspectClass),附加了一个 Spring AOP Pointcut
对于每个条款(字段 perClausePointcut)。使用AspectJ 5
AJType 反射 API(字段 ajType),使我们能够使用不同的AspectJ
实例化模型,如singleton、pertarget 和 perthis
。
为了与 Spring bean 工厂解耦,该接口提供了获取 AspectJ aspect 实例。扩展 Ordered 接口以表示底层 aspect 链中的顺序。
AspectInstanceFactory
的子接口,它返回与AspectJ
注释关联的元信息AspectMetadata
.
具有延迟、单例、委派特点来创建 aspect实例
materialized
字段)MetadataAwareAspectInstanceFactory
对象在获取 aspect 实例时,通过字段 maaif
去获取实例由 Spring IoC 容器根据 aspect bean 名称和类型来创建 aspect 实例
由 Spring IoC 提供的原型支持的
AspectInstanceFactory
,bean 作用域必须是原型(Prototype)
。
通过 Java 反射调用无参构造器获取 aspect 实例
实现了
MetadataAwareAspectInstanceFactory
和扩展了SimpleAspectInstanceFactory
。多了AspectMetadata
信息
AspectJPointcutAdvisor 的内部实现。请注意,每个目标方法都将有一个该 advisor 的实例。
Advisor
接口具有获取 Pointcut
能力AspectJAdvisorFactory 的抽象基类,可以从满足 AspectJ 5 注解语法的 AspectJ 类中创建 Spring AOP Advisor。此类处理注解解析和验证功能。它实际上并不生成 Spring AOP Advisors,被推迟到子类。
如果有 @Aspect 注解,并且不是AspectJ 编译器编译的,是适合 Spring AOP 系统使用的 AspectJ aspect。
@Override
public boolean isAspect(Class<?> clazz) {
// 类上是否有 @Aspect 注解同时不能是由 AspectJ 编译器生成的类(字段名称以 ajc$ 开头)
return (hasAspectAnnotation(clazz) && !compiledByAjc(clazz));
}
给定的类是否是有效的 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.");
}
}
继承 AbstractAspectJAdvisorFactory 。可以从满足 AspectJ 5 注解语法的 Aspect 类中创建 Spring AOP Advisor,通过反射调用相对应的 advice 方法
同一个 asepct 内 advice 方法排序比较器,它由 ConvertingComparator 和 InstanceComparator + String 组成。
根据任意的类顺序比较对象。允许对象根据它们所继承的类的类型进行排序,如果两个对象都是相同类型的实例,这个比较器将返回 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;
}
}
在比较之前进行转换的比较器。在将每个值传递给基础 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);
}
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);
}
通过 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;
}
为给定 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;
}
从给定 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);
}
从给定 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;
}
关于 Advice 细节可以参阅我的另外写的 跟着小马哥学系列之 Spring AOP( Advice 组件详解)