[Spring] AOP implementation principle

Register AOP proxy creator

In the normal development process, if you want to enable AOP, you will generally use the @EnableAspectJAutoProxy annotation. In this way, when starting, it will register a proxy creator with the Spring container to create a proxy object. AOP uses AnnotationAwareAspectJAutoProxyCreator, which implements SmartInstantiationAwareBeanPostProcessor. It can be seen from the name that this is a Bean post-processor BeanPostProcessor. BeanPostProcessor is an extension point provided by Spring. It provides two methods, namely postProcessBeforeInitialization (before initialization) and postProcessAfterInitialization (after initialization). You can Before and after the Bean is initialized, perform some operations (such as setting property values for the Bean).

Regarding the use of post-processors, please refer to: [Spring] BeanPostProcessor post-processor

  • Advisor: For aspect encapsulation, classes annotated with @AspectJ will be encapsulated into Advisor by Spring.

The implementation of AOP is mainly in the postProcessAfterInitialization method of the proxy creator:

  • postProcessAfterInitialization: A method executed after the bean is initialized. At this time, the bean has been instantiated. The wrapIfNecessary method will be called here to determine whether it is necessary to generate an AOP proxy object for the bean. If there is no need to create an AOP proxy object, just return directly. On the contrary, Advisors will be obtained, and then a proxy object of AOP will be created, replacing the originally generated Bean.
// Implemented in the parent class AbstractAutoProxyCreator of AnnotationAwareAspectJAutoProxyCreator
public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport
        implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware {<!-- -->

    /**
     * Method executed after bean initialization
     */
    @Override
    public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {<!-- -->
        if (bean != null) {<!-- -->
            //Build cache Key
            Object cacheKey = getCacheKey(bean.getClass(), beanName);
            if (this.earlyProxyReferences.remove(cacheKey) != bean) {<!-- -->
                // Is it necessary to create an AOP proxy object?
                return wrapIfNecessary(bean, beanName, cacheKey);
            }
        }
        return bean;
    }
}

AOP proxy condition judgment

Spring needs to know which classes require AOP proxy and which ones need to skip AOP proxy. For example, the aspect class annotated with @Aspect is just a normal bean and does not require AOP proxy. However, our target class requires proxy. So this step will be judged.

In one of the following situations, AOP proxy is not required and will be skipped:

  1. If it is the Advice, Pointcut, Advisor, AopInfrastructureBean class itself and its subclasses, the creation will be skipped. These are the basic classes of Spring and do not require AOP proxy;
  2. If there is an Aspect annotation and the class is not compiled through Ajc, this is the aspect class annotated with @Aspect, and AOP is not required for proxy;
  3. The function of this judgment condition is the same as above, except that this judgment is mainly used to configure aspects through the aop:aspect tag form in XML. Spring will generate a corresponding AspectJPointcutAdvisor, and the Java class corresponding to the aspect itself does not need to be proxied. , so a judgment is added to skip the Java class corresponding to the aspect itself. The implementation is different when using annotations and using the aop:aspect tag, so another conditional judgment is added here;

Get Advisor

Beans in the above situation will be skipped. The remaining beans need to obtain all Advisors first and find out the Advisor applicable to the current Bean. If found, it means that the current Bean needs AOP proxy, and still return the original Bean object.

Spring will package the aspect defined using the @AspectJ annotation into an Advisor to determine whether there is an Advisor matching the current bean. The determination method is as follows:

  1. Match the class according to the getClassFilter method of the pointcut pointcut to determine whether the class of the current Bean matches;

  2. Obtain the MethodMatcher method matcher based on the pointcut Pointcut, and use the MethodMatcher to match each method in the current Bean, that is, use the configured pointcut expression to match the method;

After this step of processing, if the Bean’s Advisor is matched, it means that the current Bean needs AOP proxy, and the Advisor collection applicable to the current Bean will be returned, and then an AOP proxy object will be created for the Bean.

Create AOP proxy object

Create proxy object

Prerequisite knowledge: JDK dynamic proxy, please refer to [Java] JDK dynamic proxy implementation principle

Spring provides two ways to create proxy objects, namely JDK dynamic proxy and Cglib. Using JDK dynamic proxy requires the proxy object to implement the interface, otherwise use Cglib.

Taking JDK dynamic proxy as an example, the process of creating proxy objects is in JdkDynamicAopProxy, which implements InvocationHandler. When creating objects through JDK’s dynamic proxy, this InvocationHandler is needed. AOP proxy objects can be created through Proxy’s newProxyInstance:

final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable {<!-- -->

    @Override
    public Object getProxy(@Nullable ClassLoader classLoader) {<!-- -->
        if (logger.isTraceEnabled()) {<!-- -->
            logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource());
        }
        Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
        findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
        // Generate proxy object, proxiedInterfaces is the target proxy class, this is InvocationHandler, which is the current JdkDynamicAopProxy
        return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
    }
}
Execute target method

After the AOP proxy object is created, this proxy object will be used to replace the Bean in the original container. The Bean obtained during the development process is this AOP proxy object. When the target method is executed, the invoke method of the proxy object will first be entered. (The invoke method in JdkDynamicAopProxy, the invoke method is defined in InvocationHandler, JdkDynamicAopProxy implements the InvocationHandler interface, so this method will be implemented):

For AOP, in the invoke method, all interceptors of the target method will be obtained first. Spring will convert the Advisor applicable to the current method into a method interceptor, and then use the chain of responsibility mode to call the interceptors one by one. Of course, if There is no corresponding interceptor for the current method that needs to be executed. Just execute the target method directly through reflection.

Because there can be multiple interceptors, executing the interceptor chain method is a recursive calling process (implemented in ReflectiveMethodInvocation), which uses a variable currentInterceptorIndex to record the index of the current interceptor:

  1. Determine whether the currentInterceptorIndex is consistent with the size of the interceptor chain. If they are consistent, it means that the last interceptor has been reached. After the interceptor has finished, the target method can be executed. At this time, the target method will be executed through reflection;
  2. If the interceptor chain has not been completed, currentInterceptorIndex will be increased by 1, the next interceptor will be obtained, and execution will continue;

Give an example
For example, if an aspect is defined and two notifications are set in it, namely pre-notification and surround notification, if you want to apply this aspect to a certain target method and perform some operations before and after the method is executed, Spring will encapsulate the aspect and notification as interception. When executing the target method, there will be two interceptors in the interceptor chain. The first interceptor is executed first, which is a pre-notification. After the pre-notification method is executed, it will be pushed backwards to the next step. An interceptor:

The second interceptor is executed, which is a surround notification. First, the pre-operation in the surround notification is executed (before the target method in the surround notification is executed). After the execution is completed, the method will not end and will continue to enter the interceptor chain. Processing logic, wait for the target method to be executed before continuing to perform post-operations (operations after the target method is executed in the surrounding notification):

It is already the last one in the interceptor chain, so the target method can be executed at this time. After executing the target method, the logic of the interceptor chain has been executed, so for the second interceptor, it will return to the surrounding notification. Process logic and start executing post-operations after the target method is executed.

Summary
(1) When AOP is turned on, it will register an AOP proxy object creator with the container. It is a post-processor. After each Bean in the Spring container is instantiated, it will enter before and after initialization. In the method corresponding to the post-processor, AOP creates the proxy object and replaces the original Bean in the post-processor’s postProcessAfterInitialization method.

(2) Before creating an AOP proxy, you will first determine whether you need to create a proxy object for the current bean, because not all beans need to be created. Only the beans where the methods to be intercepted in the aspect need to create AOP. Proxy object, so some Spring basic classes, aspects themselves marked with @Aspect and other beans will be skipped.

(3) After the above steps, all Advisors will be obtained. Spring will package the created aspects into Advisors, so it can be understood as getting all the defined aspects and finding out whether there are aspects matching the current Bean. If Some people say that it is necessary to create an AOP proxy for the Bean. Then it will be decided based on the Bean’s information, such as whether it implements the interface, to use JDK dynamic proxy or Cglib to create a proxy object. After the proxy object is created, the original Bean will be replaced and the proxy object will be replaced. return.

(4) After the proxy object is created, when the target method is executed, the business logic of the proxy object will be entered, where all Advisors (such as pre-notifications, post-notifications, etc.) that match the current target method will be obtained. It is converted into an interceptor chain, and then the interceptor chain is executed. When each interceptor chain is executed, the method in the corresponding notification will be executed. When the interceptor chain is executed, the real target method will be executed through reflection.