In the previous article, I learned the source code of Spring Ioc, have a preliminary understanding of the Spring principle, so ready to strike while the iron is hot, the source code of SpringAop also look over, the next article will be around Aop

First, AOP principle

The principle of Aop is simply to use proxy patterns as target objects to produce proxy objects, enhancing the original method. It seems simple enough, but in Spring, there are a lot of details to be aware of. Such as:

  • How is AOP triggered?
  • When is the proxy object generated?
  • How do I find the target?
  • How do you determine which methods of the target object need to be enhanced?
  • How to implement pre notification, post notification, surround notification?
  • How to handle multiple section proxies in a method?

We can look at the source code with these questions to help us understand.

AOP terminology

AOP terminology there are many and very important, before looking at the source code or to understand the terminology, here is not an introduction, interested students can move to SpringAOP terminology

Third, the demo

Let’s start with a demo that implements AOP in an annotated manner, and then we’ll use this demo to analyze the source code.

@Aspect
@Component
@EnableAspectJAutoProxy
public class LogAspect {

	@Before("execution(* com.mydemo.work.StudentController.getName(..) )"
	public void doBefore(a) {
		System.out.println("========before");
	}

	@After("execution(* com.mydemo.work.StudentController.getName(..) )"
	public void doAfter(a) {
		System.out.println("========after"); }}Copy the code

This is a simple logging AOP for the StudentController class getName(..) Method to print different information before and after the method is executed.

Four, preparation,

As you can see, in the original demo project, to enable AOP functionality, I used an @enableAspectJAutoProxy annotation as follows:

@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}.
	 */
	True for CGLIB,false for JDK, and the default is 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 * /
	// Proxy exposure, which resolves internal calls that cannot use proxies. Default is false
	boolean exposeProxy(a) default false;

}
Copy the code

You can see that this annotation has two properties proxyTargetClass and exposeProxy. In addition also USES @ Import annotations introduced a configuration class AspectJAutoProxyRegistrar. Let’s take a look at this key class:

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>     // Register a Bean dedicated to managing AOP into the IOC container
	AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);

	// Get the @enableAspectJAutoProxy annotation
<2>	AnnotationAttributes enableAspectJAutoProxy =
			AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
	if(enableAspectJAutoProxy ! =null) {
		// Handle the two attributes of the annotation
		if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
			AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
		}
		if (enableAspectJAutoProxy.getBoolean("exposeProxy")) { AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry); }}}}Copy the code

This code doesn’t look too hard, we definitely need a code class that handles AOP logic, and in Spring we hand this class over to the Spring container to manage, hence step <1>. Let’s look at the detailed logic and trace it directly to the last call:

//AopConfigUtils.java

/** * The bean name of the internally managed auto-proxy creator. */
public static final String AUTO_PROXY_CREATOR_BEAN_NAME =
			"org.springframework.aop.config.internalAutoProxyCreator";

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

	Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
	
	// Check whether the Bean is already registered in the container
	if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
		/ / registered, judge whether the ClassName for AnnotationAwareAspectJAutoProxyCreator Bean
		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;
	}
	// If not registered, register
	//cls = AnnotationAwareAspectJAutoProxyCreator.class
	RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
	beanDefinition.setSource(source);
	beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
	beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
	registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
	return beanDefinition;
}
Copy the code

This code is the class the AnnotationAwareAspectJAutoProxyCreator registered to SpringIOC container, Actually AnnotationAwareAspectJAutoProxyCreator BeanName is org. This class springframework. Aop. Config. InternalAutoProxyCreator.

5. Register BeanPostProcessor

Now we have to deal with the AnnotationAwareAspectJAutoProxyCreator AOP classes, first look at this class inheritance graph:

As you can see, this class implements it indirectlyBeanPostProcessorInterface, which you are probably familiar with, is a Spring post-processor interface.

public interface BeanPostProcessor {

	// Callback before Bean initialization
	@Nullable
	default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
		return bean;
	}

	
	// Callback after Bean initialization
	@Nullable
	default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
		returnbean; }}Copy the code

BeanPostProcessor can be thought of as a factory hook of Spring, which provides a series of hooks such as Aware, InitializingBean, and DisposableBean. It is a powerful extension point to the object instantiation phase provided by Spring, allowing Spring to modify beans before and after they are instantiated, and is more commonly used to work with markup interface implementation classes or to provide a proxy implementation (such as AOP) for the current object. BeanFactory does not support automatic registration of BeanPostProcessor. You need to manually call addBeanostProcessor() to register BeanPostProcessor. As follows:

beanFactory.addBeanPostProcessor(BeanPostProcessor beanPostProcessor)
Copy the code

The registered BeanPostProcessor applies to all beans created by the BeanFactory, but the ApplicationContext can automatically detect all BeanPostProcessors in its bean definition and automatically complete the registration. Apply them to any beans you create later.

In this case our container is ApplicationContext, so all BeanPostProcessors are automatically detected and registered. Let’s look at the logic of automatic registration.

We all know that there is an important method refresh() in ApplicationContext that is executed when the container is started, as follows:

//AbstractApplicationContext.java

public void refresh(a) throws BeansException, IllegalStateException {
	synchronized (this.startupShutdownMonitor) {
	// Prepare this context for refreshing.
	//1, call the spring container ready to refresh method, get the container at that time, and set the container synchronization flag
	prepareRefresh();

	// Tell the subclass to refresh the internal bean factory.
	// create and initialize BeanFactory ----> get IOC container
	ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

	// Prepare the bean factory for use in this context.
	//3. Populate the BeanFactory function. Configure container features, such as class loaders, event handlers, and so on
	prepareBeanFactory(beanFactory);

	try {
		// Allows post-processing of the bean factory in context subclasses.
		// Provide additional handling for subclass overrides, i.e. subclasses handle custom BeanFactoryPostProcess
		postProcessBeanFactory(beanFactory);

		// Invoke factory processors registered as beans in the context.
		// Activate various BeanFactory processors. Call all registered BeanFactoryPostProcessor beans
		invokeBeanFactoryPostProcessors(beanFactory);

		// Register bean processors that intercept bean creation.
		//6. Register BeanPostProcessor.
		/ / AutowiredAnnotationBeanPostProcessor (processing is decorated the @autowired annotation of bean and injection)
		/ / RequiredAnnotationBeanPostProcessor (processing is @ the Required annotations modified method)
		/ / CommonAnnotationBeanPostProcessor (processing @ PreDestroy, @ PostConstruct, @ the Resource such as the role of the more annotations), etc
		//AutoProxyCreator (AOP proxy @aspect)
		registerBeanPostProcessors(beanFactory);

		// Initialize message source for this context.
		//7. Initialize the information source, which is related to internationalization.
		initMessageSource();

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

		// Initialize other special beans in specific context subclasses.
		Call some special Bean initialization methods of subclasses
		onRefresh();

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

		// Instantiate all remaining (non-lazy-init) singletons.
		// Initialize the remaining singleton Bean(non-lazy-loaded)
		finishBeanFactoryInitialization(beanFactory);

		// Last step: publish corresponding event.
		Initialize the container's lifecycle event handler and publish the container's lifecycle events
		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.
		//13. Destroy the created Bean
		destroyBeans();

		// Reset 'active' flag.
		//14. Cancel the refresh operation and reset the container synchronization 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...
		Reset the public cacheresetCommonCaches(); }}}Copy the code

Code is very long, other temporary regardless, direct look at step 6 registerBeanPostProcessors (the beanFactory), is we need to focus on this line of code, it is the method to automatically register BeanPostProcessors.

//PostProcessorRegistrationDelegate.java

public static void registerBeanPostProcessors( ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {<1>	// Get all the BeanPostProcessor names in the container
	String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true.false);

	// Register BeanPostProcessorChecker that logs an info message when
	// a bean is created during BeanPostProcessor instantiation, i.e. when
	// a bean is not eligible for getting processed by all BeanPostProcessors.
	int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length;
	// Register BeanPostProcessorChecker into the container
	beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount));

	// Separate between BeanPostProcessors that implement PriorityOrdered,
	// Ordered, and the rest.
	List<BeanPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
	List<BeanPostProcessor> internalPostProcessors = new ArrayList<>();
	List<String> orderedPostProcessorNames = new ArrayList<>();
	List<String> nonOrderedPostProcessorNames = new ArrayList<>();
<2>	// Iterate over all BeanPostProcessor names
	for (String ppName : postProcessorNames) {
		// Check whether the current BeanPostProcessor implements the PriorityOrdered interface
		if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
			BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
			priorityOrderedPostProcessors.add(pp);
			if (pp instanceofMergedBeanDefinitionPostProcessor) { internalPostProcessors.add(pp); }}// Determine whether the current BeanPostProcessor implements the Ordered interface
		else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
			orderedPostProcessorNames.add(ppName);
		}
		else{ nonOrderedPostProcessorNames.add(ppName); }}// First, register the BeanPostProcessors that implement PriorityOrdered.
<3>	// Sort BeanPostProcessors implementing the PriorityOrdered interface
	sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
	/ / register
	registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);

	// Next, register the BeanPostProcessors that implement Ordered.
	List<BeanPostProcessor> orderedPostProcessors = new ArrayList<>();
	for (String ppName : orderedPostProcessorNames) {
		BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
		orderedPostProcessors.add(pp);
		if (pp instanceofMergedBeanDefinitionPostProcessor) { internalPostProcessors.add(pp); }} <4>	// Order BeanPostProcessors implementing the Ordered interface
	sortPostProcessors(orderedPostProcessors, beanFactory);
	/ / register
	registerBeanPostProcessors(beanFactory, orderedPostProcessors);

	// Now, register all regular BeanPostProcessors.
	List<BeanPostProcessor> nonOrderedPostProcessors = new ArrayList<>();
	for (String ppName : nonOrderedPostProcessorNames) {
		BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
		nonOrderedPostProcessors.add(pp);
		if (pp instanceofMergedBeanDefinitionPostProcessor) { internalPostProcessors.add(pp); }} <5>	// Register BeanPostProcessors that don't implement the sorting interface
	registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors);

	// Finally, re-register all internal BeanPostProcessors.
<6>	// Sort and register internal BeanPostProcessors
	sortPostProcessors(internalPostProcessors, beanFactory);
	registerBeanPostProcessors(beanFactory, internalPostProcessors);

	// Re-register post-processor for detecting inner beans as ApplicationListeners,
	// moving it to the end of the processor chain (for picking up proxies etc).
	beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext));
	}
Copy the code
//PostProcessorRegistrationDelegate.java

// Specific registration method
private static void registerBeanPostProcessors( ConfigurableListableBeanFactory beanFactory, List
       
         postProcessors)
        {

	for (BeanPostProcessor postProcessor : postProcessors) {
	        / / corebeanFactory.addBeanPostProcessor(postProcessor); }}Copy the code

This code looks long, but it’s actually quite simple.

  • <1> first get all BeanName of type BeanPostProcessors from the container. In the previous step we registered the Bean-> InternalAutoXyCreator that handles AOP into the container via the @enableAspectJAutoProxy annotation, so it is available here.

  • <2>, all BeanName were traversed and classified into 4 categories.

    • Implement BeanPostProcessors to the PriorityOrdered interface
    • Implement BeanPostProcessors to the Ordered interface
    • No BeanPostProcessors that implement the sorting interface
    • BeanPostProcessors inside Spring

    InternalAutoProxyCreator, which we registered with the @enableaspectjautoproxy annotation, belongs to class 2.

  • <3>, sort and register BeanPostProcessors implementing the PriorityOrdered interface

  • <4>, sort and register BeanPostProcessors that implement the Ordered interface

  • <5> register BeanPostProcessors that don’t implement the sorting interface

  • <6>, sort and register BeanPostProcessors inside Spring

Now that we’ve registered all BeanPostProcessors with the container ApplicationContext, including our own dedicated AOP processors, we’re ready to use them.

conclusionCopy the code

To summarize the steps so far:

  • through@EnableAspectJAutoProxyAnnotations register AOP specific beans into the IOC container
  • throughApplicationContext.refresh()Method to register BeanPostProcessors, which specialize in AOP, with the IOC container.

So what’s the connection between these two steps?

  • First, we’ll register our AOP specific beans into the IOC container and hand them over to Spring to manage. –>@EnableAspectJAutoProxy

  • Then, by the IOC container getBean () method to generate instances AnnotationAwareAspectJAutoProxyCreator. –>refresh()

  • Finally, because the instance realized BeanPostProcessors indirectly, and BeanPostProcessors remind of, have to call the beanFactory. AddBeanPostProcessor () method to register into the container. –>refresh()

Next article we will analyze AnnotationAwareAspectJAutoProxyCreator class is how to play a role.