AI智能
改变未来

Spring AOP(三) Advisor类架构

 Spring AOP是Spring的两大基石之一,不了解其基础概念的同学可以查看这两篇文章AOP基本概念和修饰者模式和JDK Proxy。
 如果从代码执行角度来看,Spring AOP的执行过程分为四大步骤:

  • 步骤一:Spring框架生成Advisor实例,可以是
    @Aspect

    @Async

    等注解生成的实例,也可以是程序员自定义的

    AbstractAdvisor

    子类的实例。

  • 步骤二:Spring框架在目标实例初始化完成后,也就是使用
    BeanPostProcessor

    postProcessAfterInitialization

    方法,根据Advisor实例中切入点

    Pointcut

    的定义,选择出适合该目标对象的Advisor实例。

  • 步骤三:Spring框架根据Advisor实例生成代理对象。
  • 步骤四:调用方法执行过程时,Spring框架执行Advisor实例的通知
    Advice

    逻辑。

 由于这四个步骤涉及的源码量较大,一篇文章无法直接完全讲解完,本篇文章只讲解第一步

Advisor

实例生成的源码分析。接下来的文章我们就依次讲解一下后续步骤中比较关键的逻辑。

Advisor类架构

  Spring中有大量的机制都是通过AOP实现的,比如说

@Async

的异步调用和

@Transational

。此外,用户也可以使用

@Aspect

注解定义切面或者直接继承

AbstractPointcutAdvisor

来提供切面逻辑。上述这些情况下,AOP都会生成对应的Advisor实例。

 我们先来看一下Advisor的相关类图。首先看一下

org.aopalliance

包下的类图。aopalliance是AOP组织下的公用包,用于AOP中方法增强和调用,相当于一个jsr标准,只有接口和异常,在AspectJ、Spring等AOP框架中使用。

 aopalliance定义了AOP的通知

Advice

和连接点

Joinpoint

接口,并且还有继承上述接口的

MethodInterceptor

MethodInvocation

。这两个类相信大家都很熟悉。

 然后我们来看一下Spring AOP中Advisor相关的类图。Advisor是Spring AOP独有的概念,比较重要的类有

AbstractPointcutAdvisor

InstantiationModelAwarePointcutAdvisor

。相关的讲解都在图中表明了,如果这张图中的概念和类同学们都熟识,那么对AOP的了解就已经很深入了。

获取所有

Advisor

实例

 AOP生成Advisor实例的函数入口是

AbstractAdvisorAutoProxyCreator

findCandidateAdvisors

函数。

// AbstractAdvisorAutoProxyCreator.java 找出当前所有的Advisorprotected List<Advisor> findCandidateAdvisors() {    Assert.state(this.advisorRetrievalHelper != null, \"No BeanFactoryAdvisorRetrievalHelper available\");    return this.advisorRetrievalHelper.findAdvisorBeans();}// AnnotationAwareAspectJAutoProxyCreator,是AbstractAdvisorAutoProxyCreator的子类@Overrideprotected List<Advisor> findCandidateAdvisors() {    // 调用父类的findCandidateAdvisor函数,一般找出普通的直接    // 继承Advisor接口的实例,比如说`@Async`所需的`AsyncAnnotationAdvisor`    List<Advisor> advisors = super.findCandidateAdvisors();    // 为AspectJ的切面构造Advisor,也就是说处理@Aspect修饰的类,生成上文中说的`InstantiationModelAwarePointcutAdvisor`实例    if (this.aspectJAdvisorsBuilder != null) {        advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());    }    return advisors;}

 相关的ProxyCreator也有一个类体系,不过太过繁杂,而且重要性不大,我们就先略过,直接将具体的类。由上边代码可知

AbstractAdvisorAutoProxyCreator

findCandidateAdvisors

函数是直接获取Spring容器中的

Advisor

实例,比如说

AsyncAnnotationAdvisor

实例,或者说我们自定义的

AbstractPointcutAdvisor

的子类实例。

AdvisorRetrievalHelper

findAdvisorBeans

函数通过

BeanFactory

getBean

获取了所有类型为

Advisor

的实例。

 而

AnnotationAwareAspectJAutoProxyCreator

看其类名就可知,是与AspectJ相关的创建器,用来获取

@Aspect

定义的Advisor实例,也就是

InstantiationModelAwarePointcutAdvisor

实例。

 接下去我们看一下

BeanFactoryAspectJAdvisorsBuilder

buildAspectJAdvisors

函数,它根据

@Aspect

修饰的切面实例生成对应的

Advisor

实例。

public List<Advisor> buildAspectJAdvisors() {    List<String> aspectNames = this.aspectBeanNames;    // 第一次初始化,synchronized加双次判断,和经典单例模式的写法一样。    if (aspectNames == null) {        synchronized (this) {            aspectNames = this.aspectBeanNames;            if (aspectNames == null) {                // Spring源码并没有buildAspectJAdvisorsFirstly函数,为了方便理解添加。                // 获取aspectNames,创建Advisor实例,并且存入aspectFactoryCache缓存                return buildAspectJAdvisorsFirstly();            }        }    }    if (aspectNames.isEmpty()) {        return Collections.emptyList();    }    List<Advisor> advisors = new ArrayList<>();    // 遍历aspectNames,依次获取对应的Advisor实例,或者是MetadataAwareAspectInstanceFactory生成的Advisor实例    for (String aspectName : aspectNames) {        List<Advisor> cachedAdvisors = this.advisorsCache.get(aspectName);        // cache可以取到实例,该Advisor是单例的        if (cachedAdvisors != null) {            advisors.addAll(cachedAdvisors);        }        else {            // 取得Advisor对应的工厂类实例,再次生成Advisor实例,该Advisor是多实例的。            MetadataAwareAspectInstanceFactory factory = this.aspectFactoryCache.get(aspectName);            advisors.addAll(this.advisorFactory.getAdvisors(factory));        }    }    return advisors;}

buildAspectJAdvisors

函数执行时分为两种情况,第一个未初始化时,也就是

aspectNames

为null时,执行

buildAspectJAdvisorsFirstly

进行第一次初始化,在这一过程中生成切面名称列表

aspectBeanNames

和要返回的

Advisor

列表,并且将生成的

Advisor

实例放置到

advisorsCache

中。

 第二种情况则是已经初始化后再次调用,遍历

aspectNames

,从

advisorsCache

取出对应的

Advisor

实例,或者从

advisorsCache

取出Advisor对应的工厂类对象,再次生成

Advisor

实例。

public List<Advisor> buildAspectJAdvisorsFirstly() {    List<Advisor> advisors = new ArrayList<>();    List<String> aspectNames = new ArrayList<>();    // 调用BeanFactoryUtils获取所有bean的名称    String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(            this.beanFactory, Object.class, true, false);    for (String beanName : beanNames) {        if (!isEligibleBean(beanName)) {            continue;        }        // 获取对应名称的bean实例        Class<?> beanType = this.beanFactory.getType(beanName);        if (beanType == null) {            continue;        }        /**         * AbstractAspectJAdvisorFactory类的isAspect函数来判断是否为切面实例         * 判断条件为是否被@Aspect修饰或者是由AspectJ编程而来。         */        if (this.advisorFactory.isAspect(beanType)) {            aspectNames.add(beanName);            AspectMetadata amd = new AspectMetadata(beanType, beanName);            // 切面的属性为单例模式            if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {                MetadataAwareAspectInstanceFactory factory =                        new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);                // 获取一个切面中所有定义的Advisor实例。一个切面可以定义多个Advisor。                List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);                // 单例模式,只需要将生成的Advisor添加到缓存                if (this.beanFactory.isSingleton(beanName)) {                    this.advisorsCache.put(beanName, classAdvisors);                }                // 多实例模式,需要保存工厂类,便于下一次再次生成Advisor实例。                else {                    this.aspectFactoryCache.put(beanName, factory);                }                advisors.addAll(classAdvisors);            }            else {                MetadataAwareAspectInstanceFactory factory =                        new PrototypeAspectInstanceFactory(this.beanFactory, beanName);                this.aspectFactoryCache.put(beanName, factory);                advisors.addAll(this.advisorFactory.getAdvisors(factory));            }        }    }    this.aspectBeanNames = aspectNames;    return advisors;}

buildAspectJAdvisorsFirstly

函数的逻辑如下:

  • 首先使用
    BeanFactoryUtils

    获取了BeanFactory中所有的BeanName,然后进而使用

    BeanFactory

    获取所有的Bean实例。

  • 遍历Bean实例,通过
    ReflectiveAspectJAdvisorFactory

    isAspect

    函数判断该实例是否为切面实例,也就是被

    @Aspect

    注解修饰的实例。

  • 如果是,则使用
    ReflectiveAspectJAdvisorFactory

    ,根据切面实例的定义来生成对应的多个

    Advisor

    实例,并且将其加入到

    advisorsCache

    中。

生成InstantiationModelAwarePointcutAdvisorImpl实例

ReflectiveAspectJAdvisorFactory

getAdvisors

函数会获取

@Aspect

修饰的实例中所有没有

@Pointcut

修饰的方法,然后调用

getAdvisor

函数,并且将这些方法作为参数。

public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory,        int declarationOrderInAspect, String aspectName) {    validate(aspectInstanceFactory.getAspectMetadata().getAspectClass());    // 获得该方法上的切入点条件表达式    AspectJExpressionPointcut expressionPointcut = getPointcut(            candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass());    if (expressionPointcut == null) {        return null;    }    // 生成Advisor实例    return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,            this, aspectInstanceFactory, declarationOrderInAspect, aspectName);}private AspectJExpressionPointcut getPointcut(Method candidateAdviceMethod, Class<?> candidateAspectClass) {    // 获得该函数上@Pointcut, @Around, @Before, @After, @AfterReturning, @AfterThrowing注解的信息    AspectJAnnotation<?> aspectJAnnotation =            AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);    // 没有上述注解,则直接返回    if (aspectJAnnotation == null) {        return null;    }    AspectJExpressionPointcut ajexp =            new AspectJExpressionPointcut(candidateAspectClass, new String[0], new Class<?>[0]);    // 获得注解信息中的切入点判断表达式            ajexp.setExpression(aspectJAnnotation.getPointcutExpression());    if (this.beanFactory != null) {        ajexp.setBeanFactory(this.beanFactory);    }    return ajexp;}

getAdvisor

函数就是根据作为参数传入的切面实例的方法上的注解来生成Advisor实例,也就是

InstantiationModelAwarePointcutAdvisorImpl

对象。依据方法上的切入点表达式生成

AspectJExpressionPointcut


 我们都知道

PointcutAdvisor

实例中必然有一个

Pointcut

Advice

实例。修饰在方法上的注解包括:

@Pointcut

,

@Around

,

@Before

,

@After

,

@AfterReturning

@AfterThrowing

,所以

InstantiationModelAwarePointcutAdvisorImpl

会依据不同的不同的注解生成不同的

Advice

通知。

public InstantiationModelAwarePointcutAdvisorImpl(AspectJExpressionPointcut declaredPointcut,        Method aspectJAdviceMethod, AspectJAdvisorFactory aspectJAdvisorFactory,        MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {    // .... 省略成员变量的直接赋值    // 单例模式时    this.pointcut = this.declaredPointcut;    this.lazy = false;    // 按照注解解析 Advice    this.instantiatedAdvice = instantiateAdvice(this.declaredPointcut);}

InstantiationModelAwarePointcutAdvisorImpl

的构造函数中会生成对应的

Pointcut

Advice

instantiateAdvice

函数调用了

ReflectiveAspectJAdvisorFactory

getAdvice

函数。

// ReflectiveAspectJAdvisorFactorypublic Advice getAdvice(Method candidateAdviceMethod, AspectJExpressionPointcut expressionPointcut,        MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {    Class<?> candidateAspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();    validate(candidateAspectClass);    // 获取 Advice 注解    AspectJAnnotation<?> aspectJAnnotation =            AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);    if (aspectJAnnotation == null) {        return null;    }    // 检查是否为AspectJ注解    if (!isAspect(candidateAspectClass)) {        throw new AopConfigException(\"Advice must be declared inside an aspect type: \" +                \"Offending method \'\" + candidateAdviceMethod + \"\' in class [\" +                candidateAspectClass.getName() + \"]\");    }        AbstractAspectJAdvice springAdvice;    // 按照注解类型生成相应的 Advice 实现类    switch (aspectJAnnotation.getAnnotationType()) {        case AtPointcut:            if (logger.isDebugEnabled()) {                logger.debug(\"Processing pointcut \'\" + candidateAdviceMethod.getName() + \"\'\");            }            return null;        case AtAround: // @Before 生成 AspectJMethodBeforeAdvice            springAdvice = new AspectJAroundAdvice(                    candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);            break;        case AtBefore: // @After 生成 AspectJAfterAdvice            springAdvice = new AspectJMethodBeforeAdvice(                    candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);            break;        case AtAfter: // @AfterReturning 生成 AspectJAfterAdvice            springAdvice = new AspectJAfterAdvice(                    candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);            break;        case AtAfterReturning: // @AfterThrowing 生成 AspectJAfterThrowingAdvice            springAdvice = new AspectJAfterReturningAdvice(                    candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);            AfterReturning afterReturningAnnotation = (AfterReturning) aspectJAnnotation.getAnnotation();            if (StringUtils.hasText(afterReturningAnnotation.returning())) {                springAdvice.setReturningName(afterReturningAnnotation.returning());            }            break;        case AtAfterThrowing: // @Around 生成 AspectJAroundAdvice            springAdvice = new AspectJAfterThrowingAdvice(                    candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);            AfterThrowing afterThrowingAnnotation = (AfterThrowing) aspectJAnnotation.getAnnotation();            if (StringUtils.hasText(afterThrowingAnnotation.throwing())) {                springAdvice.setThrowingName(afterThrowingAnnotation.throwing());            }            break;        default:            throw new UnsupportedOperationException(                    \"Unsupported advice type on method: \" + candidateAdviceMethod);    } // 配置Advice    springAdvice.setAspectName(aspectName);    springAdvice.setDeclarationOrder(declarationOrder);    // 获取方法的参数列表方法    String[] argNames = this.parameterNameDiscoverer.getParameterNames(candidateAdviceMethod);    if (argNames != null) {        // 设置参数名称        springAdvice.setArgumentNamesFromStringArray(argNames);    }    springAdvice.calculateArgumentBindings();    return springAdvice;}

 至此,Spring AOP就获取了容器中所有的

Advisor

实例,下一步在每个实例初始化完成后,根据这些

Advisor

Pointcut

切入点进行筛选,获取合适的

Advisor

实例,并生成代理实例。

后记

 Spring AOP后续文章很快就会更新,请大家继续关注。

赞(0) 打赏
未经允许不得转载:爱站程序员基地 » Spring AOP(三) Advisor类架构