SpringAOP解析
切点匹配解析
Advisor与@Aspect解析
getPointcut解析
文章目录
前言
实际spring源码中针对Advisors获取的功能在BeanFactoryAspectJAdvisorsBuilder类中实现;为了解析过程中的代码量,构建了一个SimulateBeanFactoryAspectJAdvisorsBuilder类,基本功能与BeanFactoryAspectJAdvisorsBuilder保持一致,删除了部分与当前目标功能无关代码.(后续解析过程中出现SimulateXXX的类均为模拟过程类,其基本功能均保持一致).
一、解析Advisors获取过程
1.获取beanFactory中所有的bean名称以及bean类型,遍历筛选出拥有@Aspect注解的bean
2.获取筛选出的bean元信息(Metadata) 并封装为Metadata工厂
3.将@Aspect类型Metadata工厂传递给advisorFactory并获取对应的advisor集合
4.返回获取到的所有advisor集合
# 解析过程中所用到的两个工厂类型
ListableBeanFactory beanFactory
AspectJAdvisorFactory advisorFactory
public List<Advisor> buildAspectJAdvisors() {
// 获取所有Object类型 bean名称
String[] strings1 = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.beanFactory, Object.class, true, false);
List<Advisor> advisors = new ArrayList<>();
for (String beanName : strings1) {
Class<?> beanType = this.beanFactory.getType(beanName);
// 通过advisor工厂验证当前类型是否为@Aspect类型切面
if (this.advisorFactory.isAspect(beanType)) {
AspectMetadata aspectMetadata = new AspectMetadata(beanType, beanName);
// 目前仅考虑单例解析
// BeanFactoryAspectInstanceFactory是一个MetadataFactory
BeanFactoryAspectInstanceFactory factory = new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
if (classAdvisors != null){
advisors.addAll(classAdvisors);
}
}
}
return advisors;
}
二、getAdvisors()方法解析
1.AbstractAspectJAdvisorFactory
AbstractAspectJAdvisorFactory实现了AspectJAdvisorFactory接口,同时AbstractAspectJAdvisorFactory作为抽象类其子类需要实现AspectJAdvisorFactory中各个方法,上文中所述advisorFactory.getAdvisors()方法就是调用AspectJAdvisorFactory接口所声明的getAdvisors()方法
public interface AspectJAdvisorFactory {
boolean isAspect(Class<?> clazz);
void validate(Class<?> aspectClass) throws AopConfigException;
List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory);
@Nullable
Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName);
@Nullable
Advice getAdvice(Method candidateAdviceMethod, AspectJExpressionPointcut expressionPointcut, MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName);
}
创建两个模拟类模拟实现AspectJAdvisorFactory抽象类的各个功能, 其中SimulateAbstractAspectJAdvisorFactoryImpl类用于实现getAdvisors() getAdvisor() getAdvice()三个方法,其余方法均在SimulateAbstractAspectJAdvisorFactory中实现.
2.SimulateAbstractAspectJAdvisorFactoryImpl
根据上面叙述SimulateAbstractAspectJAdvisorFactoryImpl类主要用于实现getAdvisors() getAdvisor() getAdvice()三个方法,根据方法名可以看出这三个方法是获取切面的核心方法类
2.1 getAdvisors()解析
根据方法名可以得知getAdvisors()方法主要获取当前bean对象(@Aspect修饰)的所有切面对象集合:
通过传入的Metadata工厂获取对应bean的Metadata中存储的类对象,通过类对象中的方法对象通过getAdvisor()方法获取切面对象
@Override
public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {
// aspectInstanceFactory: 当前处理bean的Metadata工厂对象
List<Advisor> advisors = new ArrayList<>();
// 获取当前bean的Metadata对象
AspectMetadata aspectMetadata = aspectInstanceFactory.getAspectMetadata();
// 获得当前bean的类对象
Class<?> aspectClass = aspectMetadata.getAspectClass();
// 遍历当前类的方法
for (Method method : aspectClass.getDeclaredMethods()) {
// 根据当前方法 获取对应的切面对象(当前方法、Metadata工厂、0、当前bean名称)
Advisor advisor = getAdvisor(method, aspectInstanceFactory, 0, aspectMetadata.getAspectName());
if (advisor != null){
advisors.add(advisor);
}
}
return advisors;
}
2.2 getAdvisor()解析
根据方法名可以得知getAdvisor()方法主要获取单个切面对象,其主要流程为:
1.获取expressionPointcut(切点表达式对象)
2.获取advisor对象由InstantiationModelAwarePointcutAdvisorImpl类封装
@Override
public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrderInAspect, String aspectName) {
AspectJExpressionPointcut expressionPointcut = getPointcut(candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass());
if (expressionPointcut == null) {
return null;
}
// 实例化advisor(切面) 传递(切点(包含切点表达式), 当前方法, this, 工厂对象, declarationOrderInAspect, aspectName)
/**
* 实例化advisor(切面) 内部同时实例化通知advice
* 传递参数: 解析切点对象、当前解析方法、当前解析工厂对象(advisor工厂)、aspect工厂对象(aspectMetadata)、declarationOrderInAspect、aspectName
* candidateAdviceMethod: 通过当前解析方法获取其对应注解类(@After....) 根据不同注解类创建不同advisor对象(AspectJAfterAdvice....)
* expressionPointcut: 将切点对象信息封装进advice对象中
* this(advisor工厂): 在InstantiationModelAwarePointcutAdvisorImpl对象中创建advisor对象
* aspectInstanceFactory: 主要用于验证当前解析类是否为aspect类
*
*/
return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod, this, aspectInstanceFactory, declarationOrderInAspect, aspectName);
}
2.3 getPointcut()解析
根据2.2所述,传入getPointcut()的参数为candidateAdviceMethod(当前方法)与candidateAspectClass(当前类对象);
findAspectJAnnotationOnMethod()方法获取修饰当前切点的注解信息如下:
@Pointcut, @Around, @Before, @After, @AfterReturning, @AfterThrowing
同时还将注解中的值进行存储,最终通过AspectJAnnotation类进行封装
// 获得切点实例
private AspectJExpressionPointcut getPointcut(Method candidateAdviceMethod, Class<?> candidateAspectClass){
// 解析切点类信息与切点表达式信息 封装在AspectJAnnotation对象中
AspectJAnnotation<?> aspectJAnnotation = findAspectJAnnotationOnMethod(candidateAdviceMethod);
if (aspectJAnnotation == null)
return null;
// 实例化切点
AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut(candidateAspectClass, new String[0], new Class[0]);
// 将aspectJAnnotation获取表达式信息传递给pointcut
pointcut.setExpression(aspectJAnnotation.getPointcutExpression());
return pointcut;
}
具体详细解析getPointcut解析
2.4 InstantiationModelAwarePointcutAdvisorImpl类解析
由于InstantiationModelAwarePointcutAdvisorImpl类包含大量代码,考虑到getAdvisor()方法中直接实例化InstantiationModelAwarePointcutAdvisorImpl对象,那么可以直接InstantiationModelAwarePointcutAdvisorImpl的构造方法进行理解.
参数:
declaredPointcut:上一步获取的切点对象
aspectJAdviceMethod:当前接解析方法
AspectJAdvisorFactory: AdvisorFactory工厂 (传递了this)
aspectInstanceFactory:Metadata工厂
declarationOrder:
aspectName: bean名称
// InstantiationModelAwarePointcutAdvisorImpl的构造方法
public InstantiationModelAwarePointcutAdvisorImpl(AspectJExpressionPointcut declaredPointcut, Method aspectJAdviceMethod, AspectJAdvisorFactory aspectJAdvisorFactory, MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {
// 成员赋值操作
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条件暂时不用管
if (aspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
Pointcut preInstantiationPointcut = Pointcuts.union(aspectInstanceFactory.getAspectMetadata().getPerClausePointcut(), this.declaredPointcut);
this.pointcut = new PerTargetInstantiationModelPointcut(this.declaredPointcut, preInstantiationPointcut, aspectInstanceFactory);
this.lazy = true;
} else {
// 单例
this.pointcut = this.declaredPointcut;
this.lazy = false;
// 实例化获取advice(通知)
this.instantiatedAdvice = this.instantiateAdvice(this.declaredPointcut);
}
}
通过this.instantiatedAdvice可以发现在构造方法实例化的Advice对象就是通过this.instantiateAdvice(this.declaredPointcut)方法得到
// 实例化通知对象
private Advice instantiateAdvice(AspectJExpressionPointcut pointcut) {
Advice advice = this.aspectJAdvisorFactory.getAdvice(this.aspectJAdviceMethod, pointcut, this.aspectInstanceFactory, this.declarationOrder, this.aspectName);
return advice != null ? advice : EMPTY_ADVICE;
}
在instantiateAdvice()方法中this.aspectJAdvisorFactory是调用InstantiationModelAwarePointcutAdvisorImpl方法的类自己(所以传递参数为this)故当前调用的getAdvice()方法实际就是调用SimulateAbstractAspectJAdvisorFactoryImpl类的getAdvice()方法
2.5 getAdvice()解析
getAdvice()主要用于实例化advice对象,其主要流程:
1.验证当前类是否为@Aspect修饰
2.获取当前方法所修饰的注解信息(切点信息) 如@after、@before…并通过AspectJAnnotation类进行封装(包含注解信息与对应value)
3.根据不同的注解信息创建不同的Advice对象
4.对advice对象进行初始化
// 实例化advice 在InstantiationModelAwarePointcutAdvisorImpl对象中调用
@Override
public Advice getAdvice(Method candidateAdviceMethod, AspectJExpressionPointcut expressionPointcut, MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {
// 验证当前解析类是否为Aspect类
Class<?> candidateAspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
validate(candidateAspectClass);
// 获得方法对应注解 返回值为AspectJAnnotation对象(封装好的切点信息)
AspectJAnnotation<?> aspectAnnotation = findAspectJAnnotationOnMethod(candidateAdviceMethod);
if (aspectAnnotation == null){
return null;
}
AbstractAspectJAdvice springAdvice = null;
// 根据注解信息不同创建不同的advice对象
switch (aspectAnnotation.getAnnotationType()){
case AtAfter:
springAdvice = new AspectJAfterAdvice(candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
break;
case AtAround:
springAdvice = new AspectJAroundAdvice(candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
break;
case AtBefore:
springAdvice = new AspectJMethodBeforeAdvice(candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
break;
case AtAfterThrowing:
springAdvice = new AspectJAfterThrowingAdvice(candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
break;
case AtAfterReturning:
springAdvice = new AspectJAfterReturningAdvice(candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
break;
case AtPointcut:
break;
}
springAdvice.setAspectName(aspectName);
springAdvice.setDeclarationOrder(declarationOrder);
// 这里在父类中设置了一个公共调用类调用父类中private修饰功能
// aspectJAnnotationParameterNameDiscoverer.getParameterNames()父类方法不可直接调用private修饰
String[] argNames = this.ParameterName(candidateAdviceMethod);
if (argNames != null){
springAdvice.setArgumentNamesFromStringArray(argNames);
}
springAdvice.calculateArgumentBindings();
return springAdvice;
}
总结
Advisor获取主要通过实现AdvisorFactory接口中的getAdvisors() getAdvisor() getAdvice()三个方法实现,其中的调用次序为:getAdvisors() -> getAdvisor() -> getAdvice()实现
需要注意的是Advisor对象在getAdvisor()中通过实例化InstantiationModelAwarePointcutAdvisorImpl类实现,在类中封装了Advice成员对象(调用了getAdvice()方法)