Spring AOP (3) Advisor architecture-Alibaba Cloud Developer Community

**Spring AOP is one of the two cornerstones of Spring. If you do not know its basic concepts, you can view the basic concepts of AOP and the modifier mode and JDK Proxy in these two articles. **From the perspective of code execution, the execution process of Spring AOP is divided into four steps:

  • step 1: The Spring Framework generates Advisor instance, which can be @Aspect, @Asyncsuch as annotation generation instances, can also be customized by programmers AbstractAdvisorthe instance of the subclass.
  • Step 2: After the Spring Framework initializes the target instance BeanPostProcessorthe postProcessAfterInitializationmethod, based on the entry point of the Advisor instance Pointcutselect a Advisor instance that is suitable for the target object.
  • Step 3: The Spring Framework generates a proxy object based on the Advisor instance.
  • Step 4: When the method is called, the Spring Framework executes the notification Advisor the instance. AdviceThe logic.

**Due to the large amount of source code involved in these four steps, one article cannot be explained completely. This article only explains the first step. AdvisorThe source code generated by the instance. In the following article, we will explain the key logic in the following steps in turn.

Advisor architecture

**Spring has a large number of mechanisms implemented through AOP, such @Asyncasynchronous call and @Transational. In addition, users can also use @Aspectannotation definition section or direct inheritance AbstractPointcutAdvisorto provide the tangent logic. In these cases, AOP generates the corresponding Advisor instance.

**Let's take a look at the related class diagrams of the Advisor. First, take a look org.aopalliancethe class diagram under the package. aopalliance is a public package organized by AOP. It is used to enhance and call methods in AOP. It is equivalent to a jsr standard and only has interfaces and exceptions. It is used in AOP frameworks such as AspectJ and Spring.

aopalliance defines AOP notifications. AdviceAnd connection points Joinpointinterface and inherit the above interface MethodInterceptorand MethodInvocation. I believe everyone is familiar with these two categories.

**Then, let's take a look at the Spring AOP-related class diagrams in the Advisor. Advisor is a unique concept of Spring AOP. The most important classes are AbstractPointcutAdvisorand InstantiationModelAwarePointcutAdvisor. The relevant explanations are shown in the figure. If the concepts and classes in this figure are familiar to the students, then the understanding of AOP will be very deep.

Obtain all Advisorinstance

the function entry for generating Advisor an instance is AbstractAdvisorAutoProxyCreatorthe findCandidateAdvisorsfunction.

// AbstractAdvisorAutoProxyCreator.java 找出当前所有的Advisor
protected List<Advisor> findCandidateAdvisors() {
    Assert.state(this.advisorRetrievalHelper != null, "No BeanFactoryAdvisorRetrievalHelper available");
    return this.advisorRetrievalHelper.findAdvisorBeans();
}

// AnnotationAwareAspectJAutoProxyCreator,是AbstractAdvisorAutoProxyCreator的子类
@Override
protected 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;
}

**Related ProxyCreator also have a class system, but it is too complicated and of little importance. Let's skip it first and directly classify specific classes. From the preceding code AbstractAdvisorAutoProxyCreator the findCandidateAdvisors the function directly obtains Advisorinstance, for example AsyncAnnotationAdvisorinstance, or custom AbstractPointcutAdvisorsubclass of the instance. AdvisorRetrievalHelper The findAdvisorBeans function pass BeanFactorythe getBeanall types are obtained Advisorthe instance.

Xuner AnnotationAwareAspectJAutoProxyCreator it can be seen from its class name that it is a AspectJ-related creator used to obtain @Aspectthe defined Advisor instance, that is InstantiationModelAwarePointcutAdvisorinstance.

  next, let's take a look BeanFactoryAspectJAdvisorsBuilderthe buildAspectJAdvisorsfunction, it according @Aspectthe modified section instance generates the corresponding Advisorinstance.

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

buildAspectJAdvisorsWhen a function is executed, there are two cases: the first one is not initialized, that is aspectNamesif it is null, run buildAspectJAdvisorsFirstlyduring the first initialization, a section name list is generated. aspectBeanNamesAnd to return Advisor list, and will generate Advisorplace an instance in advisorsCachein.

**In the second case, call again after initialization to traverse aspectNames, from advisorsCache take out the corresponding Advisorinstance, or advisorsCacheretrieve the factory class object corresponding to the Advisor and generate it again Advisorinstance.

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

buildAspectJAdvisorsFirstlyThe logic of the function is as follows:

  • use BeanFactoryUtilsobtain all the BeanFactory in the BeanName, and then use BeanFactoryobtain all Bean instances.
  • Traverse the Bean instance through ReflectiveAspectJAdvisorFactorythe isAspectfunction to determine whether the instance is a tangent instance, that is @Aspectthe instance modified by the annotation.
  • If yes, use ReflectiveAspectJAdvisorFactoryaccording to the definition of the slice instance, multiple corresponding Advisorand add the instance advisorsCachein.

Generate InstantiationModelAwarePointcutAdvisorImpl instance

ReflectiveAspectJAdvisorFactory the getAdvisors function will get @Aspectmodified in the instance of all no quilt @Pointcutmodify the method, and then call getAdvisorfunctions and use these methods as parameters.

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

getAdvisorThe function generates a Advisor instance based on the annotation on the method of the tangent instance passed in as a parameter, that is InstantiationModelAwarePointcutAdvisorImplobject. Generate an entry point expression based on the method AspectJExpressionPointcut . We all know... PointcutAdvisorAn instance must have one Pointcutand Adviceinstance. The annotation on the modification method includes: @Pointcut, @Around, @Before, @After, @AfterReturningand @AfterThrowing, so InstantiationModelAwarePointcutAdvisorImpldifferent annotations are generated based on different annotations. AdviceThe notification.

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

InstantiationModelAwarePointcutAdvisorImplIn the constructor of generates the corresponding Pointcutand Advice. instantiateAdviceFunction called ReflectiveAspectJAdvisorFactorythe getAdvicefunction.

// ReflectiveAspectJAdvisorFactory
public 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;
}

... At this point, Spring AOP has obtained all of the containers Advisorafter each instance is initialized Advisorthe Pointcutfilter entry points to obtain the appropriate Advisorand generate a proxy instance.

Postscript

**Spring AOP subsequent articles will be updated soon. Please continue to pay attention.

Selected, One-Stop Store for Enterprise Applications
Support various scenarios to meet companies' needs at different stages of development

Start Building Today with a Free Trial to 50+ Products

Learn and experience the power of Alibaba Cloud.

Sign Up Now