Analysis of SpringAOP principle

There are mainly two core modules in Spring, one of which is AOP (Aspect Programming). Usually when we use the SpringAOP annotation version, we define an aspect class, define the entry point, and then the defined entry point can be processed by @Before pre-notification, @After post-notification processing, @AfterReturning return notification processing, @AfterThrowing exception notification processing, @Around surrounds the notification processing, and finally adds @EnableAspectJAutoProxy annotation to the configuration class (or usually our startup class in SpringBoot), so that our AOP configuration in Spring is configured.

 What does the @EnableAspectJAutoProxy annotation do?

As the name suggests, this annotation is the meaning of opening AOP aspect programming. Many annotations like @EnableXXX are used in SpringBoot. Most of these annotations are used to enable a certain function. In fact, most of them are packaged with @Import annotations. . The function of @Import annotation is to import a component into the IOC container. There are three ways to import components

  1. Import in the form of a class object, such as @Import (Car.Class) This is equivalent to importing a Car object into the container
  2. Customize a class inherited from ImportSelect, override the selectImports method inside to return the full class name of the component that needs to be imported into the container
  3. Customize a class inherited from ImportBeanDefinitionRegistrar, rewrite the registerBeanDefinitions method inside, and use the parameter BeanDefinitionRegistry.registerBeanDefinition("book", new RootBeanDefinition(Book.class)) to import the component into the container,

 Then we click into the @EnableAspectJProxy annotation to have a look

Sure enough, the @Import annotation is also used inside, and then look at the classes in the @Import annotation

It can be found that the third way is used to import the components, so which bean is imported here? Let’s go deep into the registerAspectJAnnotationAutoProxyCreatorIfNecessary method

So we can know here that the imported component is the AnnotationAwareAspectJAutoProxyCreator class, and its id is org.springframework.aop.config.internalAutoProxyCreator.

What does AnnotationAwareAspectJAutoProxyCreator do?

1. Register AnnotationAwareAspectJAutoProxyCreator

First of all, we need to know the role of this class, first go to this class to look at its inheritance structure, to see if this class inherits some special classes so that there are special treatments when the Spring container is initialized.

Go into this class and find that the inheritance level of this class is higher. The inheritance structure of this class is given below:

AnnotationAwareAspectJAutoProxyCreator
->AspectJAwareAdvisorAutoProxyCreator
  ->AbstractAdvisorAutoProxyCreator
    ->AbstractAutoProxyCreator(上面还有父类)
      implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware

It can be found that two interfaces are also implemented in its parent class AbstractAutoProxyCreator. They are SmartInstantiationAwareBeanPostProcessor related to initializing Bean and BeanFactoryAware related to initializing BeanFactory. Then we can find the methods of these two interfaces in AnnotationAwareAspectJAutoProxyCreator and its parent class, and hit a breakpoint by the way. We can find that the AbstractAdvisorAutoProxyCreator class rewrites the setBeanFactory method of BeanFactoryAware, and then calls an initBeanFactory method, which is also overwritten by the AnnotationAwareAspectJAutoProxyCreator class, so we set a breakpoint on the setBeanFactory of AbstractAdvisorAutoProxyCreator, and The postProcessBeforeInstantiation method of AbstractAutoProxyCreator breaks. Then we can debug to see how the methods are called.

As soon as we started the project, we found that the program came to the setBeanFactory method, and then we can look at the method call stack in the lower left corner to see how to get to the setBeanFactory method step by step.

First of all, we need to initialize our container at the beginning, so we come to the refresh method to refresh the container.

In the refresh method, there is a method used to register the BeanPostProcessor, which is actually the process of creating a BeanPostProcessor object and storing it in the container. And the AnnotationAwareAspectJAutoProxyCreator class we are concerned about also indirectly implements the BeanPostProcessor interface, so the work inside has a great relationship with our AnnotationAwareAspectJAutoProxyCreator.

Then all the way to the registerBeanPostProcessors method of PostProcessorRegistrationDelegate, we can put a breakpoint in this method to see what work is done inside:

Come to the first step to get the full class name of all BeanPostProcessor

The next logic is almost the same, that is, to get the BeanPostProcessor instance to determine the priority, because our AnnotationAwareAspectJAutoProxyCreator implements the Ordered interface, so we came to the judgment branch of Ordered, and added the full class name of the Ordered BeanPostProcessor to the Ordered In the List collection, then the following is the BeanPostProcessor instance corresponding to the initialization of the traversal of the collection, which specifically refers to AnnotationAwareAspectJAutoProxyCreator

Then we went deep into the beanFactory.getBean method, came to the doCreateBean() method, and executed it to the initializeBean method

Dive into this method

So this comes to the place where we interrupted, we can look at the following initialization operations, and finish the entire initializeBean method.

Finally, add each BeanPostProcessor to the BeanFactory

At this point, the registration process of AnnotationAwareAspectJAutoProxyCreator is probably over. Let's summarize the registration process of AnnotationAwareAspectJAutoProxyCreator:

  1. Get the full class names of all BeanPostProcessors that have been defined in the IOC container, including the AnnotationAwareAspectJAutoProxyCreator components that need to be imported for our @EnableAspectJAutoProxy annotation
  2. Add another BeanPostProcessor to the container
  3. Register the BeanPostProcessor that implements the PriorityOrdered interface first
  4. Then register the BeanPostProcessor that implements the Ordered interface
  5. Finally register the ordinary BeanPostProcessor
  6. Call the getBean method to register (create) the BeanPostProcessor object according to the full class name and save it in the container. This specifically refers to the creation of the AnnotationAwareAspectJAutoProxyCreator BeanPostProcessor. In this process, it includes creating a Bean instance, populateBean()->giving various attributes to the Bean Assignment, handle the callback of the Aware interface, apply postProcessBeforeInitialization(), execute a custom init method, apply postProcessAfterInitialization() of the post processor
  7. Add the registered BeanPostProcessor to the BeanFactory -> beanFactory.addBeanPostProcessor(postProcessor)

2. The role of AnnotationAwareAspectJAutoProxyCreator

Above we talked about the registration (creation) process of AnnotationAwareAspectJAutoProxyCreator in the container, so what is the effect of creating this component? In fact, we can find that this class is indirectly the implementation class of the InstantiationAwareBeanPostProcessor interface, and this interface inherits the BeanPostProcessor interface

So the AnnotationAwareAspectJAutoProxyCreator we created is a BeanPostProcessor of InstantiationAwareBeanPostProcessor, and what is the special role of the BeanPostProcessor that implements this interface? In fact, when the Spring refresh method initializes the container, one step is to initialize the remaining Bean method. This method is to actually initialize our usual custom classes. Let's look at this method below, because when initializing these classes , BeanPostProcessor that implements the InstantiationAwareBeanPostProcessor interface will work in it.

We rewrite the postProcessBeforeInstantiation method of the InstantiationAwareBeanPostProcessor interface in AbstractAutoProxyCreator and put a breakpoint to see which methods this process has gone through

The first one that comes is the finishBeanFactoryInitialization method in the refresh method.

 Go all the way to the getBean method

Go ahead and come to the following method

If the bean returned by the resolveBeforeInstantiation method is not null, return directly, and the creation is successful, otherwise, use the doCreateBean method to create the bean

Let’s go deep into the resolveBeforeInstantiation method

In-depth applyBeanPostProcessorsBeforeInstantiation method

You can see that this is the role of the InstantiationAwareBeanPostProcessor interface. Before creating a Bean instance, you will get all the BeanPostProcessors first. If the BeanPostProcessor you traversed implements the InstantiationAwareBeanPostProcessor interface, then use this BeanPostProcessor to call its rewritten postProcessBeforeInstantiation method. Try to return a Bean instance, if it can return, then return directly, if the return is null, then use doCreateBean (this process is consistent with the process of creating BeanPostProcessor above) to create a Bean instance. So here we can also know that components that directly implement the BeanPostProcessor interface will work before and after all Bean instances are created, and components that implement the InstantiationAwareBeanPostProcessor interface will have an interception before all Bean instances are created, which is to try to return the Bean Instance. In other words, our AnnotationAwareAspectJAutoProxyCreator will try to return a proxy object before all other Bean instances are created.

3. Create AOP proxy object

Since we will go through the postProcessBeforeInstantiation method of AbstractAutoProxyCreator (the parent class of AnnotationAwareAspectJAutoProxyCreator) to try to get an instance before creating a Bean instance, let's take a look at this method here.

Since we are here to look at the creation of AOP objects, we put the breakpoint to the creation of these AOP objects, let’s talk about the Demo’s AOP class first

Objects to be proxied:

Enhancement method:

Configuration class:

Well, the above is about the AOP class, we continue to look at the postProcessBeforeInstantiation method of AbstractAutoProxyCreator

First, determine whether the bean that needs to be initialized is in adviseBeans, and secondly, determine whether the bean is a basic type of Advice, PointCut, Advisor, AopInfrastructureBean or Aspect. If the class we are going to initialize is the Calculate that needs to be enhanced, then we will return False, because this class is not one of the above types.

There is also a shouldSkip method, which has been rewritten by AnnotationAwareAspectJAutoProxyCreator

The shouldSkip method of the parent class AbstractAutoProxyCreator returns false directly

So in summary, the result of the shouldSkip call here should always return false.

Then look at the following judgment

Since null is returned, our container needs to create this Bean. After creating this Bean, it will go through the postProcessAfterInitialization method of our BeanPostProcessor (AbstractAutoProxyCreator)

The main logic in it is in the wrapIfNecessary method. This method is mainly to create proxy objects, so let's go in and see how it is created.

Then look below

Here is one to find all enhancers that can be applied to the currently created Bean, take a closer look

 Above we got all the applicable enhancers, and then look at

The key point is the createProxy method. You can see from the name that this is the method to create a proxy object. Let’s take a closer look.

Going deep into the method of returning the proxy object, come to the createAopProxy method

In the end, what we get is a dynamic proxy object created by cglib or jdk. The summary of the process is that in the process of creating an AOP proxy, after we initialize the Bean (postProcessAfterInitialization method), we will find the corresponding enhancement method according to the Bean, and if there is a corresponding enhancement method, we will create a dynamic proxy for the object. Object, if there is no object, return the object directly, so what we get in the container afterwards is the proxy object of this component.

4. Get the interceptor chain MethodInterceptor

First, let's put a breakpoint debug on the method that the target needs to be enhanced.

You can see that an intercept method has arrived at this time. Listening to the name, you probably know that this method is to intercept the execution of the target method. The focus is on the logic of creating an interceptor chain below.

So next we mainly look at how the interceptor chain is created, and enter the method of creating an interceptor chain

Here is just some logic about caching, the main creation of the interceptor chain is the method getInterceptorsAndDynamicInterceptionAdvice, enter the method

First of all, we can see that the main logic is in this for loop, and the collection of advisors is traversed. In this collection, there is a default ExposeInvocationInterceptor and our 4 enhancers. And then it is probably to convert every advisor into an interceptor

If it is a MethodInterceptor type, add it to the collection, if not, use the corresponding AdvisorAdapter to convert it into a MethodInterceptor and add it to the collection. So traverse each advisor, and then each advisor gets the corresponding interceptor chain array, and then puts the array in the interceptor container.

5. Chain call notification method

So we got the interceptor chain above, how to call the notification method in this interceptor chain? From the above, we know that when the interceptor chain we get is not empty, that is, there is an enhanced method acting on the target method, then a new CglibMethodInvocation is needed to call proceed to execute the enhanced method. Let's take a look at how this proceed method is executed

First of all, the above is to first determine if the current interceptor chain is empty or the coordinate index of the currently coming interceptor is equal to the last one in the interceptor chain, then the target method is directly executed, and then the interceptor chain is obtained according to currentInterceptorIndex The corresponding interceptor (I got the ExposeInvocationInterceptor for the first time). Then we look at the following key ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this) this line of code, note that the current ReflectiveMethodInvocation object is passed here, and then we go in and take a look

Here we call the proceed method with the passed ReflectiveMethodInvocation object again, that is, at this time we are back to the proceed method, and now we get the second interceptor from the interceptor chain, so this is equivalent to one layer one To call the invoke method of the next interceptor layer by layer, then we will directly look at the last interceptor MethodBeforeAdviceInterceptor

 We can see that before the proceed method is executed, there is a before method. In fact, this method is used to execute the pre-notification, and then we will execute the proceed after the pre-notification is executed.

At this point, the judgment condition at the beginning of the proceed method can determine that the current interceptor is the last interceptor in the interceptor chain, then the target method is directly executed, so we can see that the log meets the result of the pre-notification

 Then since the invoke method of our interceptor is called layer by layer, when the last interceptor has executed the invoke method, it continues to return to the invoke method of the penultimate interceptor. Here we can pass a picture To draw the call flow of the invoke method

 6. AOP process summary

First of all, the @EnableAspectJAutoProxy annotation at the beginning enables the AOP function. The purpose is to import the AnnotationAwareAspectJAutoProxyCreator component into the container, and this component is a BeanPostProcessor. During the initialization of the Spring container, there is a registerBeanPostProcessors method in the refresh method of Spring. This method is Create all BeanPostProcessors, so the AnnotationAwareAspectJAutoProxyCreator component is created here, and then come to the finishBeanFactoryInitialization method to create the remaining single-instance Bean, at this time the business logic components in our program, including our aspect components, will be created, and Before and after these components are created, the BeanPostProcessor that has been created in the container will be intercepted and processed. Among them, our AnnotationAwareAspectJAutoProxyCreator component will try to return a Bean before creating the Bean. If it cannot return, it will execute normally to create the Bean. After creating the Bean, AnnotationAwareAspectJAutoProxyCreator will use the postProcessAfterInitialization method (called after the Bean is created) to determine whether the Bean needs to create a proxy object. Here, you can use JDK dynamic proxy or cglib dynamic proxy according to whether the class implements the interface. If it needs to be enhanced, that is, to create a proxy object, then wrap the pointcut and all the notification methods of the pointcut into an advisor enhancer, and then create a proxy object. When executing the target method, first get the interceptor chain of the target method, and use the chain call mechanism of the interceptor to enter each interceptor at a time to execute the enhancement method.

 

Guess you like

Origin blog.csdn.net/weixin_37689658/article/details/101173206