Enable Aspect JAuto Proxy for Springboot Source Analysis

Summary:

The two core technologies of Spring Framwork are IOC and AOP. AOP is widely used in Spring's product line. If reflection is the basis for your access to advanced level, then the agent is the base for you to stabilize the advanced level. The essence of AOP is also known as CGLIB dynamic proxy technology. It must have been used more or less in daily work, but the secret behind it is worth pondering. This paper mainly introduces a running process of Spring AOP from the running process of Spring AOP, combined with a certain source code as a whole. Knowing what it is and why it is, we can better control this core technology.

    @Target({ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Import({AspectJAutoProxyRegistrar.class})
    public @interface EnableAspectJAutoProxy {
        //Indicates whether this class uses CGLIB proxy or JDK dynamic proxy
        boolean proxyTargetClass() default false;
         /**
         * @since 4.3.1 Exposure of proxies: Resolve situations where internal calls cannot use proxies by default: false denotes no processing
         * true: This proxy can get a copy of the proxy object (inside ThreadLocal) through AopContext.currentProxy(), so that we can easily get the current proxy object in the context of the Spring framework (which is very convenient when dealing with transactions).
         * You must be true to call the AopContext method, otherwise an error is reported: Cannot find current proxy: Set'exposeProxy'property on Advised to'true' to make it available.
         */
        boolean exposeProxy() default false;
    }

All EnableXXX driver technology depends on his @Import, so the most important sentence above is @Import (AspectJAuto Proxy Registrar. class). Let's look at it below.

    class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
        AspectJAutoProxyRegistrar() {
        }
        public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
            //Register an annotation-based automatic proxy creator, AopConfigUtils. registerAspectJAnnotation AutoProxy Creator If Necessary;
            AnnotationAttributes enableAspectJAutoProxy = AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
            if (enableAspectJAutoProxy != null) {
                  //Represents a mandatory specification for using CGLIB
                if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
                    AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
                }
              //Force Exposure of Bean Proxy Objects to AopContext
                if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {
                    AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
                }
            }
        }
    }

AspectJAuto Proxy Registrar is an automatic proxy creator for container registration

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

Note: Annotation Aware Aspect JAuto Proxy Creator for spring container

    @Nullable
        private static BeanDefinition registerOrEscalateApcAsRequired(Class<?> cls, BeanDefinitionRegistry registry, @Nullable Object source) {
            Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
          //Here, if we define such an automatic proxy creator ourselves, we use our custom proxy creator.
            if (registry.containsBeanDefinition("org.springframework.aop.config.internalAutoProxyCreator")) {
                BeanDefinition apcDefinition = registry.getBeanDefinition("org.springframework.aop.config.internalAutoProxyCreator");
                if (!cls.getName().equals(apcDefinition.getBeanClassName())) {
                    int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());
                  /** 
                   *User registered creator must be Infrastructure Advisor AutoProxy Creator
                   *AspectJAwareAdvisorAutoProxyCreator,AnnotationAwareAspectJAutoProxyCreator One of
                  */
                    int requiredPriority = findPriorityForClass(cls);
                    if (currentPriority < requiredPriority) {
                        apcDefinition.setBeanClassName(cls.getName());
                    }
                }
                return null;
            } 
          //If the user does not have a definition, use the default Annotation Aware Aspect JAuto Proxy Creator
          RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
              beanDefinition.setSource(source);
          //Note here that an attribute has been added: highest priority execution, which will play a key role later when used with the @Async annotation
            beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
            beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
            registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
            return beanDefinition;
        }

We successfully injected a Bean: Annotation Aware Aspect JAuto Proxy Creator annotation-based automatic proxy Creator

Automatic Creation of Agents in Spring

As you can see, Spring uses BeanPost Processor to automatically generate agents. Based on the implementation class of BeanPostProcessor's automatic proxy creator, proxy instances are generated for matching beans when beans are instantiated in containers according to some rules.

AbstractAutoProxyCreator is an abstract implementation of the automatic proxy creator. Most importantly, it implements the SmartInstantiationAwareBeanPostProcessor interface, thus involving the Spring IoC container Bean instantiation process.

Smart Instantiation AwareBeanPostProcessor inherits Instantiation AwareBeanPostProcessor, so its main responsibility is to execute all Instantiation AwareBeanPostProcessor postProcessBeforeInstantiation before the bean is initialized. Whoever returns the first Bean that is not null will not execute later. Then BeanPostProcessor#postProcessAfterInitialization will be executed

    protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
            Object exposedObject = bean;
            if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
                for (BeanPostProcessor bp : getBeanPostProcessors()) {
                    if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
                        SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
                        exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
                    }
                }
            }
            return exposedObject;
        }

Description: This method is part of spring's three-tier cache. When you call Object earlySingleton Reference = getSingleton (bean Name, false); it triggers, in fact, there is a place exposedObject = initializeBean (bean Name, exposed Object, mbd); it also triggers to return a proxy object.

    protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
            if (System.getSecurityManager() != null) {
                AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
                    invokeAwareMethods(beanName, bean);
                    return null;
                }, getAccessControlContext());
            }
            else {
                invokeAwareMethods(beanName, bean);
            }
            Object wrappedBean = bean;
            if (mbd == null || !mbd.isSynthetic()) {
                wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
            }
            try {
                invokeInitMethods(beanName, wrappedBean, mbd);
            }
            catch (Throwable ex) {
                throw new BeanCreationException(
                        (mbd != null ? mbd.getResourceDescription() : null),
                        beanName, "Invocation of init method failed", ex);
            }
            if (mbd == null || !mbd.isSynthetic()) {
                wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
            }
            return wrappedBean;
        }

Emphasis: Although both places have post-enhancement effects, the AsyncAnnotationBeanPostProcessor used by @Async is not an implementation class of Smart InstantiationAwareBeanPostProcessor, so this leads to inconsistency between @Transactional and @Async in handling cyclic dependencies. There will be separate chapters to share on cyclic dependencies.

AbstractAdvisorAutoProxyCreator

How to create proxy objects is analyzed in subsequent articles.

Keywords: Java Spring less JDK Attribute

Added by lepass_7 on Thu, 22 Aug 2019 17:44:19 +0300