7. Spring's in-depth understanding of AOP source code

Keywords: Java JDK Spring

Spring's in-depth understanding of AOP source code

In the last blog post, we have a preliminary understanding of AOP, so next we will conduct in-depth analysis on the implementation principle of AOP.

In the AOP sample code written before, there is such a note: @ EnableAspectJAutoProxy. The purpose of this note is to enable the AOP function, so we will introduce the analysis of AOP source code from this note.

@EnableAspectJAutoProxy

Take a look at its source code:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class)
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() 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.
     * @since 4.3.1
     */
    boolean exposeProxy() default false;
}

English annotation is very detailed. Here are two parameters:

  • proxyTargetClass() is used to control the specific implementation of AOP. If it is true, CGLIB will be used. If it is false, JDK's dynamic proxy will be used
  • exposeProxy() is used to control the exposure mode of the proxy. It solves the situation that the proxy cannot be used for internal calls. The default value is false

The core here is @ import (aspectjautoproxyregister. Class) to annotate the container with aspectjautoproxyregister:

class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
    AspectJAutoProxyRegistrar() {
    }

    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);
            }
        }

    }
}

Through the source code, we can see that this class implements the importbeandefinitionregister interface, which shows that this class is used to inject beans into the container, specifically what beans are injected? We can observe it through debugging:

Register aspect annotation autoproxycreatorifnecessary: what exactly does this method inject into the container

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

        Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
        //Determine whether the container contains auto? Proxy? Creator? Bean? Name (it must not be included in the first run)
        if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
            BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
            if (!cls.getName().equals(apcDefinition.getBeanClassName())) {
                int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());
                int requiredPriority = findPriorityForClass(cls);
                if (currentPriority < requiredPriority) {
                    apcDefinition.setBeanClassName(cls.getName());
                }
            }
            return null;
        }
        //Create a new bean definition without
        RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
        beanDefinition.setSource(source);
        //set priority
        beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
        beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
        //Register the bean in the container with the id of auto? Proxy? Creator? Bean? Name
        registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
        return beanDefinition;
    }

Here, annotation @ enableaaspectjautoproxy enables AOP function. It introduces the aspectjautoproxyregister component, which registers the definition information of a component AnnotationAwareAspectJAutoProxyCreator named org.springframework.aop.config.internalAutoProxyCreator for the container.

Next, we just need to focus on the AnnotationAwareAspectJAutoProxyCreator class.

Hierarchical diagram of AnnotationAwareAspectJAutoProxyCreator class

We found that AnnotationAwareAspectJAutoProxyCreator implements both BeanPostProcessor and BeanFactoryAware. So we need to find out what AnnotationAwareAspectJAutoProxyCreator did as BeanPostProcessor and BeanFactoryAware, and then we will have a general understanding of AOP process.

Next, we find the symbolic methods about BeanPostProcessor and BeanFactoryAware in AnnotationAwareAspectJAutoProxyCreator and its parent class:

AbstractAutoProxyCreator:
//About BeanFactoryAware
@Override
public void setBeanFactory(BeanFactory beanFactory) {
    this.beanFactory = beanFactory;
}

//About BeanPostProcessor
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
    Object cacheKey = getCacheKey(beanClass, beanName);

    if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
        if (this.advisedBeans.containsKey(cacheKey)) {
            return null;
        }
        if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
            this.advisedBeans.put(cacheKey, Boolean.FALSE);
            return null;
        }
    }

    // Create proxy here if we have a custom TargetSource.
    // Suppresses unnecessary default instantiation of the target bean:
    // The TargetSource will handle target instances in a custom fashion.
    TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
    if (targetSource != null) {
        if (StringUtils.hasLength(beanName)) {
            this.targetSourcedBeans.add(beanName);
        }
        Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
        Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
        this.proxyTypes.put(cacheKey, proxy.getClass());
        return proxy;
    }

    return null;
}

//About BeanPostProcessor
@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
    if (bean != null) {
        Object cacheKey = getCacheKey(bean.getClass(), beanName);
        if (this.earlyProxyReferences.remove(cacheKey) != bean) {
            return wrapIfNecessary(bean, beanName, cacheKey);
        }
    }
    return bean;
}

AbstractAdvisorAutoProxyCreator: 
//Override the method of the parent class, which is called at run time
@Override
public void setBeanFactory(BeanFactory beanFactory) 
{
    super.setBeanFactory(beanFactory);
    if (!(beanFactory instanceof ConfigurableListableBeanFactory)) {
        throw new IllegalArgumentException(
            "AdvisorAutoProxyCreator requires a ConfigurableListableBeanFactory: " + beanFactory);
    }
    //This method is overridden in a subclass
    initBeanFactory((ConfigurableListableBeanFactory) beanFactory);
}

AnnotationAwareAspectJAutoProxyCreator: 
@Override
protected void initBeanFactory(ConfigurableListableBeanFactory beanFactory) {
    super.initBeanFactory(beanFactory);
    if (this.aspectJAdvisorFactory == null) {
        this.aspectJAdvisorFactory = new ReflectiveAspectJAdvisorFactory(beanFactory);
    }
    this.aspectJAdvisorsBuilder =
        new BeanFactoryAspectJAdvisorsBuilderAdapter(beanFactory, this.aspectJAdvisorFactory);
}

We can set breakpoints for the above methods and run them in Debug mode to track the running process of the program (the test example is in the previous blog)

Creation of IOC container

We follow up the source code of the container:

Let's take a look at the refresh method

@Override
public void refresh() throws BeansException, IllegalStateException {
    synchronized (this.startupShutdownMonitor) {
        // Prepare this context for refreshing.
        // Prepare context before refresh and load
        prepareRefresh();

        // Tell the subclass to refresh the internal bean factory.
        //Tell the subclass to refresh the internal bean factory
        ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

        // Prepare the bean factory for use in this context.
         // bean factory to be used in this context
        prepareBeanFactory(beanFactory);

        try {
            // Allows post-processing of the bean factory in context subclasses.
            //Register the corresponding BeanPostProcessor interface
            postProcessBeanFactory(beanFactory);

            // Invoke factory processors registered as beans in the context.
            invokeBeanFactoryPostProcessors(beanFactory);

            // Register bean processors that intercept bean creation.
            // Register the bean processor created by the intercepting bean (the postprocessor of the bean)
            registerBeanPostProcessors(beanFactory);

            // Initialize message source for this context.
            initMessageSource();

            // Initialize event multicaster for this context.
            initApplicationEventMulticaster();

            // Initialize other special beans in specific context subclasses.
            onRefresh();

            // Check for listener beans and register them.
            registerListeners();

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

            // Last step: publish corresponding event.
            finishRefresh();
        }

        catch (BeansException ex) {
            if (logger.isWarnEnabled()) {
                logger.warn("Exception encountered during context initialization - " +
                            "cancelling refresh attempt: " + ex);
            }

            // Destroy already created singletons to avoid dangling resources.
            destroyBeans();

            // Reset 'active' flag.
            cancelRefresh(ex);

            // Propagate exception to caller.
            throw ex;
        }

        finally {
            // Reset common introspection caches in Spring's core, since we
            // might not ever need metadata for singleton beans anymore...
            resetCommonCaches();
        }
    }
}
Creation of post processor of BeanPostProcessors

Let's focus on the method of register bean post processors

Register beanpostprocessors method source code:

/**
* Here, all the methods that implement the BeanPostProcessor interface are registered in a certain order
* 1.Register the BeanPostProcessor that implements PriorityOrdered
* 2.Register BeanPostProcessor to implement Ordered
* 3.Register all other beanpostprocessors until they no longer appear
* Finally, re register the ApplicationListenerDetector as the postprocessor to detect that the internal bean implements the ApplicationListener interface, and move it to the end of the processor chain
*/
public static void registerBeanPostProcessors(
    ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {
    String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);

    
    int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length;
    beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount));

    List<BeanPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
    List<BeanPostProcessor> internalPostProcessors = new ArrayList<>();
    List<String> orderedPostProcessorNames = new ArrayList<>();
    List<String> nonOrderedPostProcessorNames = new ArrayList<>();
    for (String ppName : postProcessorNames) {
        if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
            BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
            priorityOrderedPostProcessors.add(pp);
            if (pp instanceof MergedBeanDefinitionPostProcessor) {
                internalPostProcessors.add(pp);
            }
        }
        else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
            orderedPostProcessorNames.add(ppName);
        }
        else {
            nonOrderedPostProcessorNames.add(ppName);
        }
    }


    sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
    registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);

    List<BeanPostProcessor> orderedPostProcessors = new ArrayList<>();
    for (String ppName : orderedPostProcessorNames) {
        BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
        orderedPostProcessors.add(pp);
        if (pp instanceof MergedBeanDefinitionPostProcessor) {
            internalPostProcessors.add(pp);
        }
    }
    sortPostProcessors(orderedPostProcessors, beanFactory);
    registerBeanPostProcessors(beanFactory, orderedPostProcessors);

    List<BeanPostProcessor> nonOrderedPostProcessors = new ArrayList<>();
    for (String ppName : nonOrderedPostProcessorNames) {
        BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
        nonOrderedPostProcessors.add(pp);
        if (pp instanceof MergedBeanDefinitionPostProcessor) {
            internalPostProcessors.add(pp);
        }
    }
    registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors);

    sortPostProcessors(internalPostProcessors, beanFactory);
    registerBeanPostProcessors(beanFactory, internalPostProcessors);

    beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext));
}

Because it seems unclear to write explanatory notes in the source code, take a screenshot directly:

Note here that the acquired beanpostprocessors are not initialized, and there is only their definition information in the container.

So what is the injection of AnnotationAwareAspectJAutoProxyCreator, an important component of AOP, into the container? Let's move on

Specifically, trace how it gets the bean instance by name

Call deGetBean

Cannot get, so create a new bean

Continue to follow up to see how it creates AnnotationAwareAspectJAutoProxyCreator

In fact, the method of doCreateBean is called to create the bean, assign a value to the property, and initialize the bean.

//These methods are called separately in doCreateBean

//Create an instance of the bean
instanceWrapper = createBeanInstance(beanName, mbd, args);
//Assign values to bean properties
populateBean(beanName, mbd, instanceWrapper);
//Initialize the bean
exposedObject = initializeBean(beanName, exposedObject, mbd);

One of the most important is the method of initializing the bean. The source code is as follows:

protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
    if (System.getSecurityManager() != null) {
        AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
            //Handle the method callback of the Aware interface. For example, our AnnotationAwareAspectJAutoProxyCreator is an instance of the BeanFactoryAware interface. It will call the interface method, that is, pass the BeanFactory value to the component
            invokeAwareMethods(beanName, bean);
            return null;
        }, getAccessControlContext());
    }
    else {
        invokeAwareMethods(beanName, bean);
    }

    Object wrappedBean = bean;
    if (mbd == null || !mbd.isSynthetic()) {
        //Returns a wrapped bean (calling the BeanPostProcessorsBeforeInitialization method of the postprocessor)
        wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
    }

    try {
        //Execute custom initialization method 
        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()) {
        //Returns a wrapped bean (calling the BeanPostProcessorsAfterInitialization method of the postprocessor)
        wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
    }

    return wrappedBean;
}

Detailed description of the method screenshot above

invokeAwareMethods:

//The interface method to judge the type of bean and execute Aware
private void invokeAwareMethods(final String beanName, final Object bean) {
    if (bean instanceof Aware) {
        if (bean instanceof BeanNameAware) {
            ((BeanNameAware) bean).setBeanName(beanName);
        }
        if (bean instanceof BeanClassLoaderAware) {
            ClassLoader bcl = getBeanClassLoader();
            if (bcl != null) {
                ((BeanClassLoaderAware) bean).setBeanClassLoader(bcl);
            }
        }
        if (bean instanceof BeanFactoryAware) {
            ((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
        }
    }
}

applyBeanPostProcessorsBeforeInitialization:

//Get all the beanpostprocessors and execute their interface methods
@Override
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
    throws BeansException {

    Object result = existingBean;
    for (BeanPostProcessor processor : getBeanPostProcessors()) {
        Object current = processor.postProcessBeforeInitialization(result, beanName);
        if (current == null) {
            return result;
        }
        result = current;
    }
    return result;
}

Here, you have finished adding all the beanpostprocessors to the container. Maybe you may feel a bit confused, because there is a complex call relationship between methods. I will add the BeanPostProcessor to the operation process of the container below to summarize:

  1. First, get all the beanpostprocessors defined in the IOC container that need to be created
  2. Register BeanPostProcessor in container according to priority
  3. To register the BeanPostProcessor is actually to create the BeanPostProcessor object and save it in the container
    • Create bean instance
    • Assign values to bean properties
    • Initialize bean
      • invokeInitMethods():Aware interface method callback
      • Call the postprocessor applybeanpostprocessor sbeforeinitialization method
      • Call the custom initialization method invokeInitMethods
      • Call the postprocessor applyBeanPostProcessorsAfterInitialization method

4. Inject BeanPostProcessor into the container

When we inject the AnnotationAwareAspectJAutoProxyCreator component into the container, the interface method of its BeanPostProcessor will be called when we create other beans later. Let's take a look at annotationawareaspectjauto proxycreator

What do I do next as a postprocessor?

finishBeanFactoryInitialization initializes all single instance beans

Before that, we return to the refresh method of creating the container. After the operation of adding the BeanPostProcessor to the container, it performs this important operation:

 //Complete the initialization of BeanFactory
finishBeanFactoryInitialization(beanFactory);

Enter the method preinstitutionsingletons (instantiate all single instance non lazy loaded beans)

The next step is actually the bean creation process

This process is similar to the bean creation process above, because the postprocessor also exists in the container as a bean. The process behind the getBean method refers to the screenshot of the BeanPostProcessor created above

Let's take a look at the resolvebeforeinstance method in the createBean method of bean creation

Source code of createBean method:

@Override
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
    throws BeanCreationException {

    if (logger.isTraceEnabled()) {
        logger.trace("Creating instance of bean '" + beanName + "'");
    }
    RootBeanDefinition mbdToUse = mbd;

    // Make sure bean class is actually resolved at this point, and
    // clone the bean definition in case of a dynamically resolved Class
    // which cannot be stored in the shared merged bean definition.
    Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
    if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
        mbdToUse = new RootBeanDefinition(mbd);
        mbdToUse.setBeanClass(resolvedClass);
    }

    // Prepare method overrides.
    try {
        mbdToUse.prepareMethodOverrides();
    }
    catch (BeanDefinitionValidationException ex) {
        throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
                                               beanName, "Validation of method overrides failed", ex);
    }

    try {
        // Give BeanPostProcessors a chance to return a proxy instead of the target bean instance
        -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
        //We hope that the postprocessor can return a proxy object here. If it can return a proxy object, we will use it. If not, we will call doCreateBean()
        Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
        if (bean != null) {
            return bean;
        }
    }
    catch (Throwable ex) {
        throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
                                        "BeanPostProcessor before instantiation of bean failed", ex);
    }

    try {
        //Here it is----------------------------------------------------------------
        //This is the real way to create bean s
        Object beanInstance = doCreateBean(beanName, mbdToUse, args);
        if (logger.isTraceEnabled()) {
            logger.trace("Finished creating instance of bean '" + beanName + "'");
        }
        return beanInstance;
    }
    catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
        // A previously detected exception with proper bean creation context already,
        // or illegal singleton state to be communicated up to DefaultSingletonBeanRegistry.
        throw ex;
    }
    catch (Throwable ex) {
        throw new BeanCreationException(
            mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);
    }
}

Resolvebeforeinstance source code:

Enter the applybeanpostprocessorsbeforeinstance method

Here, we recall the AnnotationAwareAspectJAutoProxyCreator component injected into the container after the AOP function was enabled. It is a postprocessor that implements the instantiaawarebaanpostprocessor interface, so its interface method will be executed here.

The differences between instantiaawarebeanpostprocessor and BeanPostProcessor are as follows:

  • BeanPostProcessor is called before and after initialization of Bean object creation.

  • The InstantiationAwareBeanPostProcessor is called when the postprocessor attempts to return an object with a postprocessor before the Bean instance is created

    Here is a summary of the process of finishing beanfactoryinitialization to finish BeanFactory initialization:

    1. Traverse to get all the beans in the container, and then create the object getbean() - > dogetbean()
    2. Create Bean
      • 1) obtain the current Bean from the cache first. If it can be obtained, the Bean has been created before (the Bean will be added to the cache after creation). Otherwise, create the Bean again.
      • 2) in createBean(), the resolvebeforeinstance() method expects the postprocessor to return a proxy object. If it cannot return, it calls doCreateBean().
      • 3) the resolvebeforeinstance() method actually intercepts each Bean before it is created by the postprocessor that implements the interface of instantiaawarebeanpostprocessor.

So far, to start calling the postprocessbeforeinstance method of AnnotationAwareAspectJAutoProxyCreator, we need to pay attention to what its interface method has done.

Postprocessbeforeinstance source code:

@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
    Object cacheKey = getCacheKey(beanClass, beanName);

    if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
        //Determine whether the current bean is in the advisedBeans, and save all the beans that need to be enhanced in the advisedBeans. This is the first time we have created a bean, so it certainly does not exist.
        if (this.advisedBeans.containsKey(cacheKey)) {
            return null;
        }
        //Isinstructionclass (bean class) determines whether the current bean implements the Advice, PointCut, Advisor, aopinstructurebean interface, or marks @ Aspect
        //shouldSkip(beanClass, beanName) determines whether to skip
        if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
            this.advisedBeans.put(cacheKey, Boolean.FALSE);
            return null;
        }
    }

    // Create proxy here if we have a custom TargetSource.
    // Suppresses unnecessary default instantiation of the target bean:
    // The TargetSource will handle target instances in a custom fashion.
    TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
    if (targetSource != null) {
        if (StringUtils.hasLength(beanName)) {
            this.targetSourcedBeans.add(beanName);
        }
        Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
        Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
        this.proxyTypes.put(cacheKey, proxy.getClass());
        return proxy;
    }

    return null;
}

postProcessAfterInitialization source code:

@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
    if (bean != null) {
        Object cacheKey = getCacheKey(bean.getClass(), beanName);
        if (this.earlyProxyReferences.remove(cacheKey) != bean) {
            //Return the bean to be wrapped
            return wrapIfNecessary(bean, beanName, cacheKey);
        }
    }
    return bean;
}

Returns the wrapper object of the current bean


Find the enhancer that can be used in the current bean (that is, find out which notification methods need to be cut into the current bean)

How to find out: use the pointcut expression (@ PointCut) in the tangent class (@ Aspect) to match

Create a proxy object for the current bean:

Create AOP proxy object source code:

@Override
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
    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 the class has an implementation interface, use the JDK dynamic proxy
        if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
            return new JdkDynamicAopProxy(config);
        }
        //No interface is implemented, Cglib dynamic proxy is used
        return new ObjenesisCglibAopProxy(config);
    }
    else {
        return new JdkDynamicAopProxy(config);
    }
}

When the wrapIfNecessary(bean, beanName, cacheKey) method is completed step by step, the Cglib enhanced proxy object is returned to the current container for the current component.

AnnotationAwareAspectJAutoProxyCreator summary:

  1. Before each Bean is created, call postprocessbeforeinstance()
    • Determine whether the current Bean is in the advisedBeans
    • Determine whether the current Bean is the Advice, PointCut, Advisor, aopinfracturebean of the basic type, or the facet of the @ Aspect annotation
    • Determine whether to skip
  2. Create the object, call postProcessAfterInitialization(), in which the wrapIfNecessary() method returns the wrapper object of a bean
    • Get all the enhancers of the current Bean (notification method)
      • ① find the candidate enhancer (which notification methods need to cut into the current Bean method)
      • ② get the enhancer that can be used by the Bean again
      • ③ sequence the intensifiers
    • Save the current Bean in the advisedBeans
    • If the current Bean needs to be enhanced, create the enhanced proxy object of the Bean
  3. The proxy object of this Bean will be obtained from the container later. When the target method is executed, the proxy object will execute the notification method process.

So far, we have started with the @ EnableAspectJAutoProxy annotation to analyze step by step to create the AOP proxy object of Bean, including the creation of IOC container, the creation of BeanPostProcessor and the creation of all beans.

Implementation of the target method

Now that we know how Bean's AOP proxy object is created, why do we execute the notification methods in order when executing the target methods of proxy objects? Please see the following analysis process.

We set a breakpoint for the target method of the sample code, and Debug runs:

Ignore the class loading method of JDK, and we come to the intercept() method of CglibAopProxy

@Override
@Nullable
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
    Object oldProxy = null;
    boolean setProxyContext = false;
    Object target = null;
    TargetSource targetSource = this.advised.getTargetSource();
    try {
        if (this.advised.exposeProxy) {
            oldProxy = AopContext.setCurrentProxy(proxy);
            setProxyContext = true;
        }
        target = targetSource.getTarget();
        Class<?> targetClass = (target != null ? target.getClass() : null);
        //Get the chain of interceptors from the agent factory that will execute the target method
        List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
        Object retVal;
        //If there is no blocker chain, directly execute the target method
        if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
            Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
            retVal = methodProxy.invoke(target, argsToUse);
        }
        //If there is an interceptor chain, pass in the target object, target method, interceptor chain and other information to be executed to create a CglibMethodInvocation, and call proceed()
        else {
            retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
        }
        retVal = processReturnType(proxy, target, method, retVal);
        return retVal;
    }
    finally {
        if (target != null && !targetSource.isStatic()) {
            targetSource.releaseTarget(target);
        }
        if (setProxyContext) {
            AopContext.setCurrentProxy(oldProxy);
        }
    }
}

How to get the interceptor chain

Every notification method is wrapped as a methodinterceptor. When a method of the target object is called, it can be controlled before, during and after the method is called.

After the blocker chain is generated, it and other information wrappers will be called CglibMethodInvocation, and then the proceed() method of CglibMethodInvocation will be called, from which we can know the execution process of the target method and the notification method.

Source code:

public Object proceed() throws Throwable {
    //  We start with an index of -1 and increment early.
    
    if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
        return invokeJoinpoint();
    }

    Object interceptorOrInterceptionAdvice =
        this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
    if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
        // Evaluate dynamic method matcher here: static part will already have
        // been evaluated and found to match.
        InterceptorAndDynamicMethodMatcher dm =
            (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
        Class<?> targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass());
        if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) {
            return dm.interceptor.invoke(this);
        }
        else {
            // Dynamic matching failed.
            // Skip this interceptor and invoke the next in the chain.
            return proceed();
        }
    }
    else {
        // It's an interceptor, so we just invoke it: The pointcut will have
        // been evaluated statically before this object was constructed.
        return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
    }
}

Summary of  processed() method: get each interceptor by chain. The interceptor executes the invoke method. Each interceptor waits for the next interceptor to finish execution and return before execution. Because the interceptor (the wrapped enhancer) in the interceptor chain has priority, the correct execution order of the notification method and the target method can be guaranteed.

AOP concludes:

  1. @Enable aspectjautoproxy to enable AOP function;
  2. @EnableAspectJAutoProxy registers a component AnnotationAwareAspectJAutoProxyCreator with the container;
  3. Annotation awareaspectjautoproxycreator is a post processor;
  4. Container creation process:
    • Register bean processor (beanfactory) registers the postprocessor to create the AnnotationAwareAspectJAutoProxyCreator object.
    • finishBeanFactoryInitialization(beanFactory) initializes the remaining single instance beans:
      • Create business logic components and aspect components
      • AnnotationAwareAspectJAutoProxyCreator intercepts the creation of components
      • After the component creation, judge whether the component needs to be enhanced: if it needs to be enhanced, package the aspect notification method as an advisor, and create a proxy object for the business logic component
  5. Implementation target method:
    • Proxy object execution target method
    • CglibAopProxy.intercept() method to intercept:
      • Get the interceptor chain of the target method (the enhancer is packaged as an interceptor)
      • By using the interceptor chain mechanism, each interceptor can execute the method in turn

Posted by dgreenhouse on Sat, 02 Nov 2019 13:07:35 -0700