Advisor获取解析

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()方法)

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值