Wanzi long text! In-depth analysis of the SpringAOP source code, from scratch to get it done in minutes

1. Know AOP and its use

Second, the characteristics of AOP

2.1 Spring AOP

2.1.1 It is implemented based on dynamic proxy

Spring 提供了很多的实现AOP的方式:Spring 接口方式,schema配置方式和注解的方式. 
如果使用接口方式引入AOP, 就是用JDK提供的动态代理来实现.
如果没有使用接口的方式引入. 那么就是使用CGLIB来实现的

Study the use of interfaces to implement AOP, the purpose is to better understand the two ways spring uses dynamic proxy to implement AOP

2.1.2 Spring provides support for AspectJ, but only provides support for some functions: namely AspectJ's pointcut analysis (expression) and matching

When we write aspects, we often use @Aspect, @Before, @Pointcut, @After, @AfterReturning, @AfterThrowing, etc., which are provided by AspectJ.

We know that AspectJ is very useful and efficient. So why doesn't Spring use AspectJ's full set of things? Especially AspectJ's static weaving.

Let's first take a look at the characteristics of AspectJ

AspectJ的特点
1. AspectJ属于静态织入. 他是通过修改代码实现的. 它的织入时机有三种
    1) Compile-time weaving: 编译期织入. 例如: 类A使用AspectJ增加了一个属性. 类B引用了类A, 这个场景就需要在编译期的时候进行织入, 否则类B就没有办法编译, 会报错.
    2) Post-compile weaving: 编译后织入.也就是已经生成了.class文件了, 或者是都已经达成jar包了. 这个时候, 如果我们需要增强, 就要使用到编译后织入
    3) Loading-time weaving: 指的是在加载类的时候进行织入. 

2. AspectJ实现了对AOP变成完全的解决方案. 他提供了很多Spring AOP所不能实现的功能
3. 由于AspectJ是在实际代码运行前就完成了织入, 因此可以认为他生成的类是没有额外运行开销的.

Extension: Why is AspectJ's static weaving not used here? Because if you introduce static weaving, you need to use AspectJ's own parser. AspectJ files are files ending with aj suffix. Spring has no way to do this, so AspectJ should be used Own parser for parsing. This increases the cost of Spring.

Three, AOP configuration method

The above mentioned Spring AOP and AspectJ. It also said that AspectJ defines many annotations, such as: @Aspect, @Pointcut, @Before, @After, etc. However, we use Spring AOP to write in pure java code. In other words It belongs to Spring completely, and has nothing to do with AspectJ. Spring just follows the concepts in AspectJ. Including the annotations of the jar package provided by AspectJ. However, it does not depend on the functionality of AspectJ.

There are three ways to configure Spring AOP.

  • The first: configuration based on the interface. In the Spring 1.2 version, what is provided is completely implemented based on the interface
  • The second type: Schema-based configuration. After spring 2.0, xml is used for configuration.
  • The third type: based on annotation @Aspect. This method is the simplest and most convenient. Although it is called AspectJ, it has nothing to do with AspectJ.

Because we mainly use annotations to configure AOP in our daily work, and the annotations are mainly implemented based on the first interface.  Therefore, we will focus on the first and third configuration methods.

3.1 Configuration based on interface mode. In Spring 1.2 version, what is provided is implemented completely based on interface mode

This method is the oldest method, but because spring has done a good backward compatibility, there are still many codes using this method,  such as declarative transactions.

So, how does Spring implement AOP when AspectJ is not introduced? Let's look at an example:

1. Define a business logic interface class

package com.lxl.www.aop.interfaceAop;

/**
 * 使用接口方式实现AOP, 默认通过JDK的动态代理来实现. 非接口方式, 使用的是cglib实现动态代理
 *
 * 业务接口类-- 计算器接口类
 *
 * 定义三个业务逻辑方法
 */
public interface IBaseCalculate {

    int add(int numA, int numB);

    int sub(int numA, int numB);

    int div(int numA, int numB);

    int multi(int numA, int numB);

    int mod(int numA, int numB);

}

2. Define business logic classes

package com.lxl.www.aop.interfaceAop;//业务类,也是目标对象

import com.lxl.www.aop.Calculate;

import org.springframework.aop.framework.AopContext;
import org.springframework.stereotype.Service;

/**
 * 业务实现类 -- 基础计算器
 */

public class BaseCalculate implements IBaseCalculate {

    @Override
    public int add(int numA, int numB) {
        System.out.println("执行目标方法: add");
        return numA + numB;
    }

    @Override
    public int sub(int numA, int numB) {
        System.out.println("执行目标方法: sub");
        return numA - numB;
    }

    @Override
    public int multi(int numA, int numB) {
        System.out.println("执行目标方法: multi");
        return numA * numB;
    }

    @Override
    public int div(int numA, int numB) {
        System.out.println("执行目标方法: div");
        return numA / numB;
    }

    @Override
    public int mod(int numA, int numB) {
        System.out.println("执行目标方法: mod");

        int retVal = ((Calculate) AopContext.currentProxy()).add(numA, numB);
        return retVal % numA;
    }
}

3. Define the notification class

Advance notice

package com.lxl.www.aop.interfaceAop;

import org.springframework.aop.MethodBeforeAdvice;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

/**
 * 定义前置通知
 * 实现MethodBeforeAdvice接口
 */
public class BaseBeforeAdvice implements MethodBeforeAdvice {

    /**
     *
     * @param method 切入的方法
     * @param args 切入方法的参数
     * @param target 目标对象
     * @throws Throwable
     */
    @Override
    public void before(Method method, Object[] args, Object target) throws Throwable {
        System.out.println("===========进入beforeAdvice()============");
        System.out.println("前置通知--即将进入切入点方法");
        System.out.println("===========进入beforeAdvice() 结束============\n");
    }

}

Post notification

package com.lxl.www.aop.interfaceAop;

import org.aspectj.lang.annotation.AfterReturning;
import org.springframework.aop.AfterAdvice;
import org.springframework.aop.AfterReturningAdvice;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

/**
 * 后置通知
 * 实现AfterReturningAdvice接口
 */
public class BaseAfterReturnAdvice implements AfterReturningAdvice {

    /**
     *
     * @param returnValue 切入点执行完方法的返回值,但不能修改
     * @param method 切入点方法
     * @param args 切入点方法的参数数组
     * @param target 目标对象
     * @throws Throwable
     */
    @Override
    public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
        System.out.println("\n==========进入afterReturning()===========");
        System.out.println("后置通知--切入点方法执行完成");
        System.out.println("==========进入afterReturning() 结束=========== ");
    }

}

Surround notification

package com.lxl.www.aop.interfaceAop;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

/**
 * 环绕通知
 * 实现MethodInterceptor接口
 */
public class BaseAroundAdvice implements MethodInterceptor {

    /**
     * invocation :连接点
     */
    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
        System.out.println("===========around环绕通知方法 开始===========");
        // 调用目标方法之前执行的动作
        System.out.println("环绕通知--调用方法之前: 执行");
        // 执行完方法的返回值:调用proceed()方法,就会触发切入点方法执行
        Object returnValue = invocation.proceed();
        System.out.println("环绕通知--调用方法之后: 执行");
        System.out.println("===========around环绕通知方法  结束===========");
        return returnValue;
    }

}

Configuration class

package com.lxl.www.aop.interfaceAop;

import org.springframework.aop.framework.ProxyFactoryBean;
import org.springframework.context.annotation.Bean;

/**
 * 配置类
 */
public class MainConfig {

    /**
     * 被代理的对象
     * @return
     */
    @Bean
    public IBaseCalculate baseCalculate() {
        return new BaseCalculate();
    }

    /**
     * 前置通知
     * @return
     */
    @Bean
    public BaseBeforeAdvice baseBeforeAdvice() {
        return new BaseBeforeAdvice();
    }

    /**
     * 后置通知
     * @return
     */
    @Bean
    public BaseAfterReturnAdvice baseAfterReturnAdvice() {
        return new BaseAfterReturnAdvice();
    }

    /**
     * 环绕通知
     * @return
     */
    @Bean
    public BaseAroundAdvice baseAroundAdvice() {
        return new BaseAroundAdvice();
    }

    /**
     * 使用接口方式, 一次只能给一个类增强, 如果想给多个类增强, 需要定义多个ProxyFactoryBean
     * 而且, 曾增强类的粒度是到类级别的. 不能指定对某一个方法增强
     * @return
     */
    @Bean
    public ProxyFactoryBean calculateProxy() {
        ProxyFactoryBean proxyFactoryBean = new ProxyFactoryBean();
        proxyFactoryBean.setInterceptorNames("baseAfterReturnAdvice", "baseBeforeAdvice", "baseAroundAdvice");
        proxyFactoryBean.setTarget(baseCalculate());
        return proxyFactoryBean;
    }

}

As I said before, AOP relies on ioc, which must be registered as a bean to achieve AOP functionality

Method entry

package com.lxl.www.aop.interfaceAop;

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class InterfaceMainClass{

    public static void main(String[] args) {
        ApplicationContext context = new AnnotationConfigApplicationContext(MainConfig.class);
        IBaseCalculate calculate = context.getBean("calculateProxy", IBaseCalculate.class);
        System.out.println(calculate.getClass());
        calculate.add(1, 3);
    }

}

Results of the:

===========进入beforeAdvice()============
前置通知--即将进入切入点方法
===========进入beforeAdvice() 结束============

===========around环绕通知方法 开始===========
环绕通知--调用方法之前: 执行
执行目标方法: add
环绕通知--调用方法之后: 执行
===========around环绕通知方法  结束===========

==========进入afterReturning()===========
后置通知--切入点方法执行完成
==========进入afterReturning() 结束=========== 

Through observation, we found that the order of execution is: pre-notification --> front method of surrounding notification --> target logic --> rear method of surrounding notification --> rear notification.

So is the pre-notification performed first, or the pre-notification method of surrounding notifications? It depends on the configuration order of the configuration file

Here, we put the surround notification at the end, so the surround notification is executed after the preceding notification.

  @Bean
    public ProxyFactoryBean calculateProxy() {
        ProxyFactoryBean proxyFactoryBean = new ProxyFactoryBean();
        proxyFactoryBean.setInterceptorNames( "baseAfterReturnAdvice", "baseBeforeAdvice", "baseAroundAdvice");
        proxyFactoryBean.setTarget(baseCalculate());
        return proxyFactoryBean;
    }

So, if we put the surround notification before the pre-notification, the surround notification will be executed first

  @Bean
    public ProxyFactoryBean calculateProxy() {
        ProxyFactoryBean proxyFactoryBean = new ProxyFactoryBean();
        proxyFactoryBean.setInterceptorNames("baseAroundAdvice", "baseAfterReturnAdvice", "baseBeforeAdvice");
        proxyFactoryBean.setTarget(baseCalculate());
        return proxyFactoryBean;
    }

operation result

===========around环绕通知方法 开始===========
环绕通知--调用方法之前: 执行
===========进入beforeAdvice()============
前置通知--即将进入切入点方法
===========进入beforeAdvice() 结束============

执行目标方法: add

==========进入afterReturning()===========
后置通知--切入点方法执行完成
==========进入afterReturning() 结束=========== 
环绕通知--调用方法之后: 执行
===========around环绕通知方法  结束===========

The chain of responsibility was mentioned above, so what is a chain of responsibility? As shown in the figure below:

Spring AOP source code analysis

 

There is an assembly line. For example, a production line. There are many processes in it. Process 1 can be completed before process 2 can be carried out, and so on.

Combined with the demo above, let's look at a demo called by the chain of responsibility.

Above we have defined two methods. One is the forward notification BaseBeforeAdvice implements MethodBeforeAdvice, and the other is the surround notification BaseAroundAdvice implements MethodInterceptor. If you want to put these two notifications on a chain. Then they must implement the same interface. But , Is different now.

We know that the surround notification has two parts, one is the front notification of the surround notification, and the other is the rear notification of the surround notification. Therefore, we can regard the front notification as the front notification part of the surround notification.

package com.lxl.www.aop.interfaceAop.chainDemo;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.aop.MethodBeforeAdvice;

/**
 * 为什么 我们可以让MethodBeforeAdvice 前置通知继承自环绕通知的接口呢?
 * 主要原因是, 环绕通知的前半部分, 就是前置通知
 */
public class BeforeAdviceInterceptor implements MethodInterceptor {

  // 前置通知
  MethodBeforeAdvice methodBeforeAdvice;

  public BeforeAdviceInterceptor(MethodBeforeAdvice methodBeforeAdvice) {
    this.methodBeforeAdvice = methodBeforeAdvice;
  }

  /**
   * 使用了环绕通知的前半部分. 就是一个前置通知
   * @param invocation the method invocation joinpoint
   * @return
   * @throws Throwable
   */
  @Override
  public Object invoke(MethodInvocation invocation) throws Throwable {
    methodBeforeAdvice.before(invocation.getMethod(), invocation.getArguments(), invocation.getClass());
    return invocation.proceed();
  }
}

This code wraps the pre-notification and lets it be extended to implement the MethodInterceptor interface. This is a method that extends the interface.

Next we have to create a chain. This chain can be understood as each worker on the assembly line. Each worker handles a process. In order to be able to call in a unified way. All workers must implement the same interface. The definition of the responsibility chain is as follows:

    /**
     * 把一条链上的都初始化
     *
     * 有一条链, 这条链上都有一个父类接口 MethodInterceptor.
     * 也就是说, 链上都已一种类型的工人. 但每种工人的具体实现是不同的. 不同的工人做不同的工作
     *
     * 这里定义了一个责任链. 连上有两个工人. 一个是前置通知. 一个是环绕通知.
     * 前置通知和环绕通知实现的接口是不同的. 为了让他们能够在一条链上工作. 我们自定义了一个MethodBeforeAdviceInterceptor
     * 相当于为BaseBeforeAdvice()包装了一层MethodInterceptor
     */

    List<MethodInterceptor> list = new ArrayList<>();
    list.add(new BeforeAdviceInterceptor(new BaseBeforeAdvice()));
    list.add(new BaseAroundAdvice());

A responsibility chain is defined here. There are two workers connected. One is pre-notification. The other is surrounding notification.

The interfaces implemented by pre-notification and surrounding notification are different. In order to allow them to work in a chain. We have customized a MethodBeforeAdviceInterceptor, which is equivalent to wrapping a layer of MethodInterceptor for BaseBeforAdvice(), followed by the call of the responsibility chain.

/**
   * 责任链调用
   */
  public static class MyMethodInvocation implements MethodInvocation {

    // 这是责任链
    protected List<MethodInterceptor> list;
    // 目标类
    protected final BaseCalculate target;

    public MyMethodInvocation(List<MethodInterceptor> list) {
      this.list = list;
      this.target = new BaseCalculate();
    }

    int i = 0;

    public Object proceed() throws Throwable {
      if (i == list.size()) {
        /**
         * 执行到责任链的最后一环, 执行目标方法
         */
        return target.add(2, 2);
      }
      MethodInterceptor interceptor = list.get(i);
      i++;
      /**
       * 执行责任链调用
       * 这个调用链第一环是: 包装后的前置通知
       * 调用链的第二环是: 环绕通知.
       * 都执行完以后, 执行目标方法.
       */
      return interceptor.invoke(this);
    }

    @Override
    public Object getThis() {
      return target;
    }

    @Override
    public AccessibleObject getStaticPart() {
      return null;
    }

    @Override
    public Method getMethod() {
      try {
        return target.getClass().getMethod("add", int.class, int.class);
      } catch (NoSuchMethodException e) {
        e.printStackTrace();
      }
      return null;
    }

    @Override
    public Object[] getArguments() {
      return new Object[0];
    }
  }

}

Here we focus on the  proceed  () method. We cyclically get the notification of the list responsibility chain, and then execute the invoke() method

Spring AOP source code analysis

 

The proceed() method is a chain loop. At the beginning i=0, list(0) is the advance notice, when the advance notice is called, the BeforeAdviceInterceptor.invoke() method is called, and the invocation.proceed() method is called , Back to the MyMethodInvocation.proceed() method.

Then i=1, list(1) is the surrounding notification, when the surrounding notification is called, invocation.proceed() is called again; there is a return to the MyMethodInvocation.proceed() method.

This is already the last link of the list, and the invoke() method will not be called later. The second is to execute the target method. After the execution ends, the entire call ends.

This is a call chain.

There are two points about the chain of responsibility:

1. There must be a unified call, that is, a common abstract class.

2. Use loop or recursion to complete the call of the chain of responsibility

to sum up:

The above method uses the ProxyFactoryBean proxy bean factory method. It has two limitations:

public class ProxyFactoryBean extends ProxyCreatorSupport
        implements FactoryBean<Object>, BeanClassLoaderAware, BeanFactoryAware {
......
   @Override
    @Nullable
    public Object getObject() throws BeansException {
        /**
         * 初始化通知链: 将通知放入链中
         * 后面初始化的时候, 是通过责任链的方式调用这些通知链的的. 
         * 那么什么是责任链呢?
         */
        initializeAdvisorChain();
        if (isSingleton()) {
            /**
             * 创建动态代理
             */
            return getSingletonInstance();
        }
        else {
            if (this.targetName == null) {
                logger.info("Using non-singleton proxies with singleton targets is often undesirable. " +
                        "Enable prototype proxies by setting the 'targetName' property.");
            }
            return newPrototypeInstance();
        }
    }
......
}

1. Only one class can be enhanced at a time. If you enhance multiple classes, you need to define multiple ProxyFactoryBeans

2. The enhanced granularity can only be at the class level, and cannot be assigned to a method to enhance. This still has certain restrictions

3.2 The way based on the annotation @Aspect. This way is the simplest and most convenient. Although it is called AspectJ, it has nothing to do with AspectJ.

3.2.1 The analytical principle of @Aspect aspect

The first method above is a detailed study of the implementation principle of the interface method AOP. The annotation method of AOP, the last is to parse the @Befor, @After and other annotations in the @Aspect aspect class into an Advisor. The class with @Before will be parsed into one Advisor, classes with @After methods will also be parsed into an Advisor...other notified methods will also be parsed into Advisor. Enhanced logic is defined in Advisor, that is, logic such as @Befor and @After , And methods that need to be enhanced, such as the div method.

Let's analyze the implementation principle of using annotations @Aspect, @Before, @After. As mentioned above, it is to generate Advisor from @Before, @After

There are three parts here.

  • Part 1: Analyze the notification method with @Before etc. under @Aspect, and parse it as Advisor
  • Part 2: When creatingBean, create a dynamic proxy
  • The third part: call. When call, execute the responsibility chain, loop all the notifications. Finally output the result.

Below we analyze in accordance with these three parts.

The first step: parse the notification method with @Before etc. under @Aspect, and parse it as Advisor. As shown below:

Spring AOP source code analysis

 

When was the first step performed?

When creatingBean, many PostProcessor post processors will be called, and they will be executed when the first post processor is called. The process of execution is roughly as follows: Get all the BeanDefinitions and determine whether the class has @Aspect annotations. Then go to the methods annotated with @Aspect to find @Before, @After, @AfterReturning, @AfterThrowing, each notification will generate an Advisor

Step 2: When creatingBean, create a dynamic proxy

Spring AOP source code analysis

 

There are three stages in createBean. In which stage is the dynamic proxy created?

The overall process is:

When creatingBean, the bean's post processor is called after the initialization is completed. Get all the Advisors, loop through the Advisors, and then perform matches based on the expressions in the execution. Match with the currently created bean, and match , Create a dynamic proxy.

There are many types of pointcut. The above code mentioned are:

package com.lxl.www.aop.interfaceAop.chainDemo;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.aop.MethodBeforeAdvice;

/**
 * 为什么 我们可以让MethodBeforeAdvice 前置通知继承自环绕通知的接口呢?
 * 主要原因是, 环绕通知的前半部分, 就是前置通知
 */
public class BeforeAdviceInterceptor implements MethodInterceptor {

  // 前置通知
  MethodBeforeAdvice methodBeforeAdvice;

  public BeforeAdviceInterceptor(MethodBeforeAdvice methodBeforeAdvice) {
    this.methodBeforeAdvice = methodBeforeAdvice;
  }

  /**
   * 使用了环绕通知的前半部分. 就是一个前置通知
   * @param invocation the method invocation joinpoint
   * @return
   * @throws Throwable
   */
  @Override
  public Object invoke(MethodInvocation invocation) throws Throwable {
    methodBeforeAdvice.before(invocation.getMethod(), invocation.getArguments(), invocation.getClass());
    return invocation.proceed();
  }
}

And our annotations are matched in the way of execution expressions

Step 3: Call. When calling, execute the responsibility chain, loop all the notifications. Finally output the result.

Spring AOP source code analysis

 

3.2.2 Source code analysis of AOP aspect

Source code analysis is also divided into three parts

  • 1. Analytical aspects
  • 2. Create a dynamic proxy
  • 3. Call
    /**
     * 把一条链上的都初始化
     *
     * 有一条链, 这条链上都有一个父类接口 MethodInterceptor.
     * 也就是说, 链上都已一种类型的工人. 但每种工人的具体实现是不同的. 不同的工人做不同的工作
     *
     * 这里定义了一个责任链. 连上有两个工人. 一个是前置通知. 一个是环绕通知.
     * 前置通知和环绕通知实现的接口是不同的. 为了让他们能够在一条链上工作. 我们自定义了一个MethodBeforeAdviceInterceptor
     * 相当于为BaseBeforeAdvice()包装了一层MethodInterceptor
     */

    List<MethodInterceptor> list = new ArrayList<>();
    list.add(new BeforeAdviceInterceptor(new BaseBeforeAdvice()));
    list.add(new BaseAroundAdvice());

The entrance to source code analysis, AOP annotations:

package com.lxl.www.aop;

import org.springframework.beans.factory.annotation.Configurable;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

@Configurable
// 使用注解的方式引入AOP
@EnableAspectJAutoProxy
@ComponentScan("com.lxl.www.aop")
public class MainConfig {

}

To introduce AOP, we need to add @EnableAspectJAutoProxy proxy in the configuration file. Then if you want to remove the introduction of AOP, you only need to comment out this annotation. This annotation explains the entire AOP entry.

Next, enter the annotation class

/**
   * 责任链调用
   */
  public static class MyMethodInvocation implements MethodInvocation {

    // 这是责任链
    protected List<MethodInterceptor> list;
    // 目标类
    protected final BaseCalculate target;

    public MyMethodInvocation(List<MethodInterceptor> list) {
      this.list = list;
      this.target = new BaseCalculate();
    }

    int i = 0;

    public Object proceed() throws Throwable {
      if (i == list.size()) {
        /**
         * 执行到责任链的最后一环, 执行目标方法
         */
        return target.add(2, 2);
      }
      MethodInterceptor interceptor = list.get(i);
      i++;
      /**
       * 执行责任链调用
       * 这个调用链第一环是: 包装后的前置通知
       * 调用链的第二环是: 环绕通知.
       * 都执行完以后, 执行目标方法.
       */
      return interceptor.invoke(this);
    }

    @Override
    public Object getThis() {
      return target;
    }

    @Override
    public AccessibleObject getStaticPart() {
      return null;
    }

    @Override
    public Method getMethod() {
      try {
        return target.getClass().getMethod("add", int.class, int.class);
      } catch (NoSuchMethodException e) {
        e.printStackTrace();
      }
      return null;
    }

    @Override
    public Object[] getArguments() {
      return new Object[0];
    }
  }

}

This is, we see that the EnableAspectJAutoProxy class adds a @Import annotation class, we know that the Import annotation can add a bean to the IoC container.

Enter the AspectJAutoProxyRegistrar class below 

package org.springframework.context.annotation;

import org.springframework.aop.config.AopConfigUtils;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.type.AnnotationMetadata;

class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {

    /**
     * Register, escalate, and configure the AspectJ auto proxy creator based on the value
     * of the @{@link EnableAspectJAutoProxy#proxyTargetClass()} attribute on the importing
     * {@code @Configuration} class.
     */
    @Override
    public void registerBeanDefinitions(
            AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
    
        AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);

        AnnotationAttributes enableAspectJAutoProxy =
                AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
        if (enableAspectJAutoProxy != null) {
            if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
                AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
            }
            if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {
                AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
            }
        }
    }

}

We see that a BeanDefinition is registered using ImportBeanDefinitionRegistrar.

It should be remembered that ImportBeanDefinitionRegistrar is usually used in combination with @Import to register a BeanDefinition to the container.

How to register? See the specific implementation.

AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);

The registered name is AnnotationAwareAspectJAutoProxyCreator internalAutoProxyCreator

@Nullable
    public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(
            BeanDefinitionRegistry registry, @Nullable Object source) {

        /**
         * 注册一个AnnotationAwareAspectJAutoProxyCreator类型的bean定义
         */
        return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
    }

The above structure is as follows:

Spring AOP source code analysis

 

We see that the bean of the class AnnotationAwareAspectJAutoProxyCreator is registered. What kind of class is this? Let’s take a look at the structure of the class. The inheritance structure of this class is very huge, we only look at the inheritance structure related to this content

Spring AOP source code analysis

 

The analysis of aspects and the creation of dynamic proxies are all carried out in the post processor of the bean. The following is a comparison of the realization principle of AOP and the process of createBean (create bean).

Spring AOP source code analysis

 

The picture above shows the 9 post-processors called during the bean loading process. The InstantiationAwareBeanPostProcessor post-processor is called before the bean is created to determine whether an AOP needs to be created for this class, which is the process of analyzing the aspect. So the InstantiationAwareBeanPostProcessor is implemented in AnnotationAwareAspectJAutoProxyCreator The interface of the post processor. The postProcessBeforeInstantiation method has been rewritten.

After the third stage initialization of createBean, to create a dynamic proxy of AOP, call the BeanPostProcess post processor, AnnotationAwareAspectJAutoProxyCreator also implements the BeanPostProcess interface. Override postProcessAfterInitialization.

At the same time, it is also necessary to deal with the circular dependency of AOP. To deal with circular dependency, the SmartInstantiationAwareBeanPostProcessor post processor is called before the attribute assignment, and then the getEarlyBeanReference method is rewritten. We see that AnnotationAwareAspectJAutoProxyCreator also implements the SmartInstantiationAwareBeanPostProcessor interface. And rewrite the getEarlyBeanReference method.

Due to space limitations, only part of the content can be shared. Friends who need the full version can help forward + follow, thank you!

Guess you like

Origin blog.csdn.net/Ppikaqiu/article/details/112906786