>>>> 😜😜😜 Making: 👉 github.com/black-ant

A. The preface

The last post talked about AOP initialization, how AOP creates AOP proxy classes through PostProcess,

2. AOP creates a starting point

AOP created

// In AbstractAutoProxyCreator # wrapIfNecessary, start the createProxy process to create a proxy class
 createProxy(bean.getClass(), beanName, specificInterceptors, newSingletonTargetSource(bean))Copy the code

2.1 AbstractAutoProxyCreator Create a Proxy class

C- AbstractAutoProxyCreator
protected Object createProxy(Class<? > beanClass,@Nullable String beanName,
            @Nullable Object[] specificInterceptors, TargetSource targetSource) {

    if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
        AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
    }

    // Create a ProxyFactory
    ProxyFactory proxyFactory = new ProxyFactory();
    proxyFactory.copyFrom(this);

    if(! proxyFactory.isProxyTargetClass()) {if (shouldProxyTargetClass(beanClass, beanName)) {
            proxyFactory.setProxyTargetClass(true);
        } else{ evaluateProxyInterfaces(beanClass, proxyFactory); }}// Build the notifier
    Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
    proxyFactory.addAdvisors(advisors);
    proxyFactory.setTargetSource(targetSource);
    customizeProxyFactory(proxyFactory);
    
    proxyFactory.setFrozen(this.freezeProxy);
    if (advisorsPreFiltered()) {
        proxyFactory.setPreFiltered(true);
    }
    
    // Get the proxy object -> 2.3 Aop object creation details
    // org.springframework.aop.framework.ProxyFactory
    return proxyFactory.getProxy(getProxyClassLoader());
}
Copy the code

[PIC] : Contents of specificInterceptors object

[Pro] AutoProxyUtils function

C-autoproxyutils: Tool class m-shouldProxyTargetClass: determines whether a given bean should be proxied using the target class instead of the interface m-determinetargetClass: Determine the original target class of the specified bean, otherwise return to the general getType lookup m-ExposeTargetClass: Determine whether a given bean name indicates "original instance" based on ORIGINAL_INSTANCE_SUFFIXstatic void exposeTargetClass(
    ConfigurableListableBeanFactory beanFactory, @NullableString beanName, Class<? > targetClass) {

    if(beanName ! =null && beanFactory.containsBeanDefinition(beanName)) {
        // ORIGINAL_TARGET_CLASS_ATTRIBUTE => org.springframework.aop.framework.autoproxy.AutoProxyUtils.originalTargetClassbeanFactory.getMergedBeanDefinition(beanName).setAttribute(ORIGINAL_TARGET_CLASS_ATTRIBUTE, targetClass); }}// PS: the Attribute Attribute is set here, and we will see how this Attribute is used.


    
Copy the code

[Pro] ProxyFactory

This class provides a simple way to get and configure an INSTANCE of an AOP proxy in custom user code: Create a ProxyFactory Mc-proxyfactory (Object target) : create a ProxyFactory(Class<? >... ProxyFactory(Class<? > proxyInterface, Interceptor Interceptor) : a convenient method for creating a proxy for a single Interceptor Mc-proxyfactory (Class<? > proxyInterface, TargetSource TargetSource) : create a ProxyFactory for the specified TargetSource, and make the proxy implement the specified interface m-getProxy () : Create a new proxy based on the factory Settings, repeatedly calling m-getProxy (@Nullable ClassLoader classLoader) : 
    M- getProxy(Class<T> proxyInterface, Interceptor interceptor)
    M- getProxy(Class<T> proxyInterface, TargetSource targetSource)
    M- getProxy(TargetSource targetSource)  
        
P- proxyInterface : 
P- Interceptor :  
P- TargetSource :
    
Copy the code

(Pro) Advisor

The basic interface that holds AOP Advice (actions to take at join points) and the filters that determine the applicability of Advice (such as pointcuts), the Advisor interface allows support for different types of Advice, such as Before Advice and After Advice c-Advisor: Notificator m-getAdvice () m-isperInstance ()When the Advisor was called >>>
Copy the code

2.2 buildAdvisors Creates notification objects

C- AbstractAutoProxyCreator
protected Advisor[] buildAdvisors(@Nullable String beanName, @Nullable Object[] specificInterceptors) {
    // 2-2-1: resolves the specified interceptor name to an Advisor object
    Advisor[] commonInterceptors = resolveInterceptorNames();

    List<Object> allInterceptors = new ArrayList<>();
    if(specificInterceptors ! =null) {
        allInterceptors.addAll(Arrays.asList(specificInterceptors));
        if (commonInterceptors.length > 0) {
            if (this.applyCommonInterceptorsFirst) {
                allInterceptors.addAll(0, Arrays.asList(commonInterceptors));
            } else {
                allInterceptors.addAll(Arrays.asList(commonInterceptors));
            }
        }
    }

    Advisor[] advisors = new Advisor[allInterceptors.size()];
    for (int i = 0; i < allInterceptors.size(); i++) {
            // 2-2-2: resolves the specified interceptor name to the Advisor object
        advisors[i] = this.advisorAdapterRegistry.wrap(allInterceptors.get(i));
    }
    return advisors;
}


// 2-2-1: resolves the specified interceptor name to an Advisor object
    private Advisor[] resolveInterceptorNames() {
        BeanFactory bf = this.beanFactory;
        ConfigurableBeanFactory cbf = (bf instanceof ConfigurableBeanFactory ? (ConfigurableBeanFactory) bf : null);
        List<Advisor> advisors = new ArrayList<>();
         // Get the generic Interceptor object, which can be set by setInterceptorNames
        for (String beanName : this.interceptorNames) {
            if (cbf == null| |! cbf.isCurrentlyInCreation(beanName)) { Object next = bf.getBean(beanName); advisors.add(this.advisorAdapterRegistry.wrap(next)); }}return advisors.toArray(new Advisor[0]);
    }


 // 2-2-2: resolves the specified interceptor name to the Advisor object
C- DefaultAdvisorAdapterRegistry
public Advisor wrap(Object adviceObject) throws UnknownAdviceTypeException {
    if (adviceObject instanceof Advisor) {
        return (Advisor) adviceObject;
    }
    if(! (adviceObjectinstanceof Advice)) {
        throw new UnknownAdviceTypeException(adviceObject);
    }
    Advice advice = (Advice) adviceObject;
    if (advice instanceof MethodInterceptor) {
        // So well-known it doesn't even need an adapter.
        return new DefaultPointcutAdvisor(advice);
    }
    for (AdvisorAdapter adapter : this.adapters) {
        // Check that it is supported.
        if (adapter.supportsAdvice(advice)) {
            return newDefaultPointcutAdvisor(advice); }}throw new UnknownAdviceTypeException(advice);
}
    

Copy the code

3. Creation process of Aop proxy class

The previous section initiated the creation of a proxy with CreateProxy. This section describes the process of creating a ProxyFactory

Step 1: Obtain the main process of proxy class => ProxyFactory

// Class structure ===================
C- ProxyFactory
    E- ProxyCreatorSupport
    
public Object getProxy(@Nullable ClassLoader classLoader) {
    // createAopProxy() => org.springframework.aop.framework.ObjenesisCglibAopProxy
    return createAopProxy().getProxy(classLoader);
}    

// ProxyCreatorSupport is the parent class of ProxyFactory. CreateAopProxy calls this class method
protected final synchronized AopProxy createAopProxy(a) {
    if (!this.active) {
        // Activate the proxy configuration
        activate();
    }
    // getAopProxyFactory() => org.springframework.aop.framework.DefaultAopProxyFactory
    return getAopProxyFactory().createAopProxy(this);
}



Copy the code

Step 2: AOP agent factory selection

// Aop is based on Proxy, AopProxy interface, AopProxy create interface class AopProxyFactory, AopProxy
public interface AopProxyFactory {

    /** * Create AopProxy */ for a given AOP configuration
    AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException;

}

// The Aop proxy factory defaults to DefaultAopProxyFactory
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
    Config.isoptimize () : Returns whether the agent should perform active optimization
    / / config. IsProxyTargetClass () : returns are direct agent for the target class and any interface
    / / hasNoUserSuppliedProxyInterfaces (config) : to determine whether AdvisedSupport provided only specifies the SpringProxy interface (or no specified proxy interface)
    if(config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) { Class<? > targetClass = config.getTargetClass();if (targetClass == null) {
            throw new AopConfigException("TargetSource cannot determine target class: " +
                        "Either an interface or a target is required for proxy creation.");
        }
        if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
            return new JdkDynamicAopProxy(config);
        }
        return new ObjenesisCglibAopProxy(config);
    } else {
        return newJdkDynamicAopProxy(config); }}// PS: Spring classes use JdkDynamicAopProxy by default. Custom AOP classes usually use CglibAopProxyYou can configure it in the following ways:// Option 1: You can switch configurations when building beans. For example:
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(ExecutableValidator.class)
@ConditionalOnResource(resources = "classpath:META-INF/services/javax.validation.spi.ValidationProvider")
@Import(PrimaryDefaultValidatorPostProcessor.class)
public class ValidationAutoConfiguration {
    
    @Bean
    @ConditionalOnMissingBean
    public static MethodValidationPostProcessor methodValidationPostProcessor(Environment environment,
            @Lazy Validator validator) {
        MethodValidationPostProcessor processor = new MethodValidationPostProcessor();
         // Set proxy target object
        boolean proxyTargetClass = environment.getProperty("spring.aop.proxy-target-class", Boolean.class, true);
        processor.setProxyTargetClass(proxyTargetClass);
        processor.setValidator(validator);
        returnprocessor; }}// Method 2: configure the AOP proxy mode
1.Enable EnableAspectJAutoProxy2.Through the property spring.aop.proxy-target-classconfigureCopy the code

Step 3-1: CglibAopProxy Create a proxy class


C- CglibAopProxy
public Object getProxy(@Nullable ClassLoader classLoader) {

        try{ Class<? > rootClass =this.advised.getTargetClass(); Class<? > proxySuperClass = rootClass;// String CGLIB_CLASS_SEPARATOR = "$$";
             / / contains $$
            if(rootClass.getName().contains(ClassUtils.CGLIB_CLASS_SEPARATOR)) { proxySuperClass = rootClass.getSuperclass(); Class<? >[] additionalInterfaces = rootClass.getInterfaces();for(Class<? > additionalInterface : additionalInterfaces) {this.advised.addInterface(additionalInterface); }}// Check whether the supplied Class has been validated, and if not, verify it
            validateClassIfNecessary(proxySuperClass, classLoader);

            // Configure CGLIB enhancement -> RPO31001
            Enhancer enhancer = createEnhancer();
            if(classLoader ! =null) {
                enhancer.setClassLoader(classLoader);
                if (classLoader instanceof SmartClassLoader &&
                        ((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) {
                    enhancer.setUseCache(false);
                }
            }
            enhancer.setSuperclass(proxySuperClass);
            enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));
            enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
            enhancer.setStrategy(newClassLoaderAwareGeneratorStrategy(classLoader)); Callback[] callbacks = getCallbacks(rootClass); Class<? >[] types =newClass<? >[callbacks.length];for (int x = 0; x < types.length; x++) {
                types[x] = callbacks[x].getClass();
            }
            // fixedInterceptorMap only populated at this point, after getCallbacks call above
            enhancer.setCallbackFilter(new ProxyCallbackFilter(
                    this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));
            enhancer.setCallbackTypes(types);

            // Generate the proxy class and create the proxy instance
            return createProxyClassAndInstance(enhancer, callbacks);
        }
        catch (CodeGenerationException | IllegalArgumentException ex) {
            throw new AopConfigException("Could not generate CGLIB subclass of " + this.advised.getTargetClass() +
                    ": Common causes of this problem include using a final class or a non-visible class",
                    ex);
        }
        catch (Throwable ex) {
            // TargetSource.getTarget() failed
            throw new AopConfigException("Unexpected AOP exception", ex); }}protected Object createProxyClassAndInstance(Enhancer enhancer, Callback[] callbacks) {
    enhancer.setInterceptDuringConstruction(false);
    enhancer.setCallbacks(callbacks);
    // Each is created by whether there is a construct parameter
    return (this.constructorArgs ! =null && this.constructorArgTypes ! =null ?
        enhancer.create(this.constructorArgTypes, this.constructorArgs) :
        enhancer.create());
}

// RPO31001 adds: Enhancer roleThe common way to Proxy is through a Proxy class, and Enhancer is also a method Proxy class. Proxy is an interface based Proxy, and Enhancer is an inheritance based ProxyCopy the code

Step 3-2 : JdkDynamicAopProxy

// JdkDynamicAopProxy builds the proxy class
public Object getProxy(@Nullable ClassLoader classLoader) { Class<? >[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
    findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
    // Create a proxy class
    return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}
Copy the code

AopProxy Proxy system

Proxy classes in Spring usually have2CglibAopProxy/JdkDynamicAopProxy// [Pro] : How to switch AopProxy type
     
Copy the code

4. Go deep

4.1 Use of the ORIGINAL_TARGET_CLASS_ATTRIBUTE attribute

// Step 1 : AbstractApplicationContext # refresh
public void refresh(a) throws BeansException, IllegalStateException {
    synchronized (this.startupShutdownMonitor) {
        try {
            / /...

            // Instantiate all remaining (non-lazy-init) singletons
            finishBeanFactoryInitialization(beanFactory);

            // Last step: publish corresponding event.
            finishRefresh();
        }
        / /...}}// PS: You can see that in the penultimate step of the main process,

/ / EventListenerMethodProcessor: method of marking the @ EventListener parsing, and then converted to a ApplicationListener
// Step 2: C- EventListenerMethodProcessor # afterSingletonsInstantiated
public void afterSingletonsInstantiated(a) {
        ConfigurableListableBeanFactory beanFactory = this.beanFactory;
        String[] beanNames = beanFactory.getBeanNamesForType(Object.class);
        for (String beanName : beanNames) {
            if(! ScopedProxyUtils.isScopedTarget(beanName)) { Class<? > type =null;
                try {
                      // Determines the original target class of the specified bean
                      // Step 2-1: Obtain originalTargetClass
                      // beanName -> org.springframework.context.annotation.internalConfigurationAnnotationProcessor
                      // type -> org.springframework.context.annotation.ConfigurationClassPostProcessor
                    type = AutoProxyUtils.determineTargetClass(beanFactory, beanName);
                }
                catch (Throwable ex) {
                    / /...
                }
                if(type ! =null) {
                    if (ScopedObject.class.isAssignableFrom(type)) {
                        try{ Class<? > targetClass = AutoProxyUtils.determineTargetClass( beanFactory, ScopedProxyUtils.getTargetBeanName(beanName));if(targetClass ! =null) { type = targetClass; }}catch (Throwable ex) {
                            / /...}}try {
                          // Step 2-3: Obtain originalTargetClass
                        processBean(beanName, type);
                    }
                    catch (Throwable ex) {
                        / /...
                    }
                }
            }
        }
}

// Step 2-1: Get originalTargetClass from BeanDefinition
String ORIGINAL_TARGET_CLASS_ATTRIBUTE = Conventions.getQualifiedAttributeName(AutoProxyUtils.class, "originalTargetClass"); BeanDefinition bd = beanFactory.getMergedBeanDefinition(beanName); Class<? > targetClass = (Class<? >) bd.getAttribute(ORIGINAL_TARGET_CLASS_ATTRIBUTE);// Step 2-2: Look for the original target class. You can see that the class to be queried usually starts with internalXXX and is created in beanDefinitionNames
public staticClass<? > determineTargetClass( ConfigurableListableBeanFactory beanFactory,@Nullable String beanName) {

        if (beanName == null) {
            return null;
        }
        if(beanFactory.containsBeanDefinition(beanName)) { BeanDefinition bd = beanFactory.getMergedBeanDefinition(beanName); Class<? > targetClass = (Class<? >) bd.getAttribute(ORIGINAL_TARGET_CLASS_ATTRIBUTE);if(targetClass ! =null) {
                returntargetClass; }}return beanFactory.getType(beanName);
}


// Step 2-3: This method is omitted, which is mainly for the EventListener annotation processing, and has nothing to do with the main process
private void processBean(final String beanName, finalClass<? > targetType) 


Copy the code

4.2 AOP Cglib configuration process

Usually the basic AOP proxy is through

org.springframework.boot.autoconfigure.aop.AopAutoConfiguration$AspectJAutoProxyingConfiguration$CglibAutoProxyConfiguration
    
public void registerBeanDefinitions( AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {

    AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
    
    // h
    AnnotationAttributes enableAspectJAutoProxy =
                AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
    // 
    if(enableAspectJAutoProxy ! =null) {
        if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
            AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
        }
        if (enableAspectJAutoProxy.getBoolean("exposeProxy")) { AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry); }}}public static void forceAutoProxyCreatorToUseClassProxying(BeanDefinitionRegistry registry) {
    // AUTO_PROXY_CREATOR_BEAN_NAME => org.springframework.aop.config.internalAutoProxyCreator
    if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
        BeanDefinition definition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
        definition.getPropertyValues().add("proxyTargetClass", Boolean.TRUE); }}Copy the code

Supplement 1: EnableAspectJAutoProxy

public @interface EnableAspectJAutoProxy {

    /**
     * Indicate whether subclass-based (CGLIB) proxies are to be created as opposed
     * to standard Java interface-based proxies. The default is {@code false}.
     */
    boolean proxyTargetClass(a) default false;

    /**
     * Indicate that the proxy should be exposed by the AOP framework as a {@code ThreadLocal}
     * for retrieval via the {@link org.springframework.aop.framework.AopContext} class.
     * Off by default, i.e. no guarantees that {@code AopContext} access will work.
     * @since4.3.1 * /
    boolean exposeProxy(a) default false;

}
Copy the code

Supplement 2: AopAutoConfiguration Automatic configuration class

@Configuration(proxyBeanMethods = false)
@ConditionalOnProperty(prefix = "spring.aop", name = "auto", havingValue = "true", matchIfMissing = true)
public class AopAutoConfiguration {

    @Configuration(proxyBeanMethods = false)
    @ConditionalOnClass(Advice.class)
    static class AspectJAutoProxyingConfiguration {

        @Configuration(proxyBeanMethods = false)
        @EnableAspectJAutoProxy(proxyTargetClass = false)
        @ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "false", matchIfMissing = false)
        static class JdkDynamicAutoProxyConfiguration {}@Configuration(proxyBeanMethods = false)
        @EnableAspectJAutoProxy(proxyTargetClass = true)
        @ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true", matchIfMissing = true)
        static class CglibAutoProxyConfiguration {}}@Configuration(proxyBeanMethods = false)
    @ConditionalOnMissingClass("org.aspectj.weaver.Advice")
    @ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true", matchIfMissing = true)
    static class ClassProxyingConfiguration {

        ClassProxyingConfiguration(BeanFactory beanFactory) {
            if (beanFactory instanceofBeanDefinitionRegistry) { BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory; AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry); AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry); }}}}Copy the code

Add 3: org. Springframework. Aop. Config. InternalAutoProxyCreator role

C- AopConfigUtils # String AUTO_PROXY_CREATOR_BEAN_NAME = "org.springframework.aop.config.internalAutoProxyCreator"? - The bean name of the internally managed automatic proxy creatorCopy the code

conclusion

To be fair, this article is not well written, many places are not clear now, limited energy can not be detailed and in-depth, generally speaking, it is a semi-finished product, later time is sufficient, let’s have a deeper look

Core concepts:

  • AbstractAutoProxyCreator # createProxy Initiates the creation of a proxy class
  • AutoProxyUtils is a utility class for some common action handling of the original class and the proxy
  • Use AopProxyFactory to create proxy classes. There are two types: ObjenesisCglibAopProxy and JdkDynamicAopProxy