Principle analysis of Spring AOP -- function analysis of @ EnableAspectJAutoProxy

catalogue

1, Overview

2, @ EnableAspectJAutoProxy principle

3, Summary

1, Overview

In the previous article, we introduced some related terms in Spring AOP and demonstrated how to use AOP. We have learned that to enable the Spring AOP function in the annotated version, we can add the @ EnableAspectJAutoProxy annotation on the configuration class, as follows:

@Configuration
// @EnableAspectJAutoProxy is used to enable the Spring AOP function of the annotated version, similar to < AOP: AspectJ AutoProxy > using XML
@EnableAspectJAutoProxy
@ComponentScan("com.wsh")
public class AopConfig {

}

Therefore, to analyze the principle of Spring AOP, naturally start with the @ EnableAspectJAutoProxy annotation. Let's take a look at what is done inside @ EnableAspectJAutoProxy?

2, @ EnableAspectJAutoProxy principle

Let's take a look at the source code of the @ EnableAspectJAutoProxy annotation, as follows:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
// Introduce aspectjauto proxyregister and register some beans with aspectjauto proxyregister
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {

	/**
	 * Controls whether a subclass based CGLIB dynamic proxy or an interface based JDK dynamic proxy is used
	 * The default value is false, that is, JDK dynamic proxy mode is used by default
	 */
	boolean proxyTargetClass() default false;

	/**
	 * Control the exposure mode of the proxy, and solve the scenario that the proxy cannot be used for calls between methods within the class
	 * The default value is false. If it is set to true, we can use aopcontext Currentproxy () can easily get the current proxy object
	 */
	boolean exposeProxy() default false;

}

As you can see, there are two attributes in the @ EnableAspectJAutoProxy annotation:

  • proxyTargetClass: controls whether to use cglib dynamic proxy inherited from subclass or JDK dynamic proxy based on interface. proxyTargetClass is false by default, that is, JDK dynamic proxy mode is used by default. If it is set to true, cglib dynamic proxy is forced to be used;
  • exposeProxy: controls the exposure method of the proxy. The default is false. If it is set to true, we can use aopcontext Currentproxy () can easily get the current proxy object, which is very useful in solving the method self invocation scenario of Spring transaction failure;

As can be seen from the source code, @ Import (aspectjautoproxyregister. Class) is marked on the @ EnableAspectJAutoProxy annotation, the aspectjautoproxyregister component is introduced with the @ Import annotation, and then some beans are registered with aspectjautoproxyregister.

@Import annotation: you can introduce a class and inject it into the Spring IOC container to be managed by the current Spring.

We continue to click on the source code of aspectjautoproxyregister class, as shown below:

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) {

		// 1. Inject bean definition information (annotation based automatic proxy creator) of AnnotationAwareAspectJAutoProxyCreator component into IOC container, and beanName = "org.springframework.aop.config.internalAutoProxyCreator"
		AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);

		// 2. Get the attribute information of @ EnableAspectJAutoProxy annotation
		AnnotationAttributes enableAspectJAutoProxy =
				AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
		if (enableAspectJAutoProxy != null) {
			// 3. Set Cglib dynamic proxy
			if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
				// To force the use of CGLIB dynamic proxy is actually to set the value of proxyTargetClass attribute of bean name = "org. Springframework. AOP. Config. Internalautoproxycreator" to true
				AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
			}

			// 4. Set the exposure method of the proxy, that is, force the proxy object of the Bean to be exposed to the AopContext
			if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {
				// In fact, the bean name = "org. Springframework. AOP. Config. Internalautoproxycreator" has its exposeProxy property set to true
				AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
			}
		}
	}

}

You can see that aspectjautoproxyregister implements the importbeandefinitionregister interface, which provides the registerBeanDefinitions() method, allowing us to inject some bean definition information into the IOC container.

The core of aspectjautoproxyregister#registerbeandefinitions() method is:

AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);

Let's look at its source code:

// org.springframework.aop.config.AopConfigUtils#registerAspectJAnnotationAutoProxyCreatorIfNecessary(org.springframework.beans.factory.support.BeanDefinitionRegistry)
public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry) {
    return registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry, null);
}

public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(
    BeanDefinitionRegistry registry, @Nullable Object source) {
    // Registering the AnnotationAwareAspectJAutoProxyCreator component
    return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
}

private static BeanDefinition registerOrEscalateApcAsRequired(
    Class<?> cls, BeanDefinitionRegistry registry, @Nullable Object source) {

    Assert.notNull(registry, "BeanDefinitionRegistry must not be null");

    // Judge whether the automatic proxy Creator with beanName="org.springframework.aop.config.internalAutoProxyCreator" (i.e. user-defined AnnotationAwareAspectJAutoProxyCreator) already exists in the IOC container
    if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
        BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
        // If an automatic proxy creator already exists, judge whether the name of the cls object is equal to the beanClassName of the apcDefinition. If not, obtain the priority of the apcDefinition and the cls. If the priority of the apcDefinition is less than the priority of the cls, set the beanClassName of the apcDefinition to the name value of the cls
        if (!cls.getName().equals(apcDefinition.getBeanClassName())) {
            int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());
            int requiredPriority = findPriorityForClass(cls);
            if (currentPriority < requiredPriority) {
                apcDefinition.setBeanClassName(cls.getName());
            }
        }
        return null;
    }

    // Encapsulate the annotation awareaspectjautoproxycreator to be registered as RootBeanDefinition
    RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
    beanDefinition.setSource(source);
    // Have the highest priority
    beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
    beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
    // Inject annotationawareaspectjautoproxycreator into IOC container with the name "org.springframework.aop.config.internalAutoProxyCreator"
    registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
    return beanDefinition;
}

As can be seen from the source code, the general processing process of registerorexcalateapcasrequired() is as follows:

  1. Judge whether the automatic agent Creator with beanName="org.springframework.aop.config.internalAutoProxyCreator" (i.e. user-defined AnnotationAwareAspectJAutoProxyCreator) already exists in the IOC container;
  2. If an automatic proxy creator already exists, judge whether the name of the cls object is equal to the beanClassName of the apcDefinition. If not, obtain the priority of the apcDefinition and the cls. If the priority of the apcDefinition is less than the priority of the cls, set the beanClassName of the apcDefinition to the name value of the cls;
  3. Encapsulate the annotation awareaspectjautoproxycreator to be registered as RootBeanDefinition;
  4. Inject the annotation awareaspectjautoproxycreator component into the IOC container, and the name is "org.springframework.aop.config.internalAutoProxyCreator";

After analysis, we have already understood the function of @ EnableAspectJAutoProxy annotation:

Import aspectjautoproxyregister through @ import. Aspectjautoproxyregister inherits importbeandefinitionregister. Use aspectjautoproxyregister to register the annotation awareaspectjautoproxycreator definition information in the IOC container, and the name is "org.springframework.aop.config.internalAutoProxyCreator".

3, Summary

Through the previous analysis, we can roughly understand that the @ EnableAspectJAutoProxy annotation finally injects the AnnotationAwareAspectJAutoProxyCreator component into the container, which is actually the core of AOP. The relevant functions of AOP are carried out around AnnotationAwareAspectJAutoProxyCreator.

Let's take a look at the class diagram of AnnotationAwareAspectJAutoProxyCreator:

As can be seen from the class diagram, AnnotationAwareAspectJAutoProxyCreator has several characteristics:

  • A series of Aware interfaces are implemented, such as beanfactory Aware and BeanClassLoaderAware;
  • It indirectly implements the BeanPostProcessor interface, which allows us to modify the bean before and after bean initialization, or generate a bean proxy object. We need to focus on the processing of AnnotationAwareAspectJAutoProxyCreator and the postProcessBeforeInitialization() and postProcessAfterInitialization() methods in its parent classes;
  • It indirectly implements the instantiawarebeanpostprocessor interface, so we also need to focus on the implementation of AnnotationAwareAspectJAutoProxyCreator and postprocessbeforeinstance() and postprocessafterinstance() methods in its parent classes;

The following figure briefly describes the processing process of @ EnableAspectJAutoProxy:

Keywords: Spring

Added by gls2ro on Fri, 14 Jan 2022 09:35:59 +0200