Spring Framework version 5.3.x

1. Basic concepts

AOP is short for Aspect-Oriented Programming. Aspect is a modularity mechanism used to describe cross-cutting concerns that are scattered across objects, classes, and functions.

  • Base: object to be enhanced or target object
  • Facets: Contains enhanced applications to the base
  • Configuration: You can think of it as a kind of weaving, by providing this configuration environment in an AOP architecture that combines the base and aspect to achieve the weaving implementation of the aspect to the target object
  • Advice: Defines what to do at the join point to provide the woven interface for section enhancement. In Spring AOP, it mainly describes the aspect behavior of Spring AOP injection around method calls.
  • Pointcut: Determines which join point Advice should act on, that is, defines the set of methods that need to be enhanced through the Pointcut.
  • Advisor: After you have designed the advice and concerns for the target method, you need an object to combine them. This is the Advisor. With the Advisor, you can define which advice should be used and on which concerns.

2. Source code analysis

Source code parsing is annotated for analysis

Turn AOP on with the @enableAspectJAutoProxy annotation:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {

	/** * false: Java proxy * true: Cglib proxy */
	boolean proxyTargetClass(a) default false;

	/** * Proxy exposure to resolve internal calls that cannot use proxies, the default is false */
	boolean exposeProxy(a) default false;
}
Copy the code

Annotations using the @ Import annotations AspectJAutoProxyRegistrar class is introduced, the next track AspectJAutoProxyRegistrar class

2.1 AspectJAutoProxyRegistrar source code parsing

class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
	@Override
	public void registerBeanDefinitions( AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
		
        / / register AnnotationAwareAspectJAutoProxyCreator
		AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
		
        // Read the configured annotation EnableAspectJAutoProxy property
		AnnotationAttributes enableAspectJAutoProxy =
				AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
		if(enableAspectJAutoProxy ! =null) {
			if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
				AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
			}
			if (enableAspectJAutoProxy.getBoolean("exposeProxy")) { AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry); }}}}Copy the code

Through the source code found AspectJAutoProxyRegistrar ImportBeanDefinitionRegistrar interface is achieved, At the time of the Spring container startup will call ImportBeanDefinitionRegistrar# registerBeanDefinitions method to inject AnnotationAwareAspectJAutoProxyCreator

AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
Copy the code

Registered Bean name is: the org. Springframework. Aop. Config. InternalAutoProxyCreator

Final call is AopConfigUtils# registerOrEscalateApcAsRequired method

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

	Assert.notNull(registry, "BeanDefinitionRegistry must not be null");

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

	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

Here AnnotationAwareAspectJAutoProxyCreator class registration completed. Then look AnnotationAwareAspectJAutoProxyCreator is how to create the proxy class.

2.2 AnnotationAwareAspectJAutoProxyCreator source code parsing

Let’s look at the class inheritance:

Through inheritance relationship found that implements SmartInstantiationAwareBeanPostProcessor BeanFactoryAware, InstantiationAwareBeanPostProcessor, BeanPostProcessor. Here’s how the interface works:

AbstractAutoProxyCreator rewrite the BeanPostProcessor# postProcessAfterInitialization method And InstantiationAwareBeanPostProcessor# postProcessBeforeInstantiation method, the detailed analysis of the two methods:

2.2.1 AbstractAutoProxyCreator# postProcessBeforeInstantiation
	@Override
	public Object postProcessBeforeInstantiation(Class
        beanClass, String beanName) {
		// Get the bean's key
        Object cacheKey = getCacheKey(beanClass, beanName);
		// Determine if the bean has already been processed, which will be placed in targetSourcedBeans
		if(! StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
			// Determine whether advise is included
            if (this.advisedBeans.containsKey(cacheKey)) {
				return null;
			}
            // Determine the type and whether it should be skipped
			if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
				this.advisedBeans.put(cacheKey, Boolean.FALSE);
				return null;
			}
		}
		
		TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
		if(targetSource ! =null) {
			if (StringUtils.hasLength(beanName)) {
				this.targetSourcedBeans.add(beanName);
			}
            // Get notifications and notifiers
			Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
			// Create the proxy
            Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
			this.proxyTypes.put(cacheKey, proxy.getClass());
			return proxy;
		}

		return null;
	}
Copy the code
2.2.1 AbstractAutoProxyCreator# postProcessAfterInitialization

Take a look at the call chain for this method:

Look at the below AbstractAutoProxyCreator# postProcessAfterInitialization method:

@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
	if(bean ! =null) {
		Object cacheKey = getCacheKey(bean.getClass(), beanName);
		if (this.earlyProxyReferences.remove(cacheKey) ! = bean) {// Wrap the proxy class
			returnwrapIfNecessary(bean, beanName, cacheKey); }}return bean;
}
Copy the code

The main method for generating proxy classes is wrapIfNecessary.

protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
    
   	// Create a front checksum detection for the proxy class
	if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
		return bean;
	}
	if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
		return bean;
	}
    // Determine whether to generate a proxy object
	if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
		this.advisedBeans.put(cacheKey, Boolean.FALSE);
		return bean;
	}

	// Get notifications and notifiers
	Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
	if(specificInterceptors ! = DO_NOT_PROXY) {this.advisedBeans.put(cacheKey, Boolean.TRUE);
        // Create a proxy object
		Object proxy = createProxy(
				bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
		this.proxyTypes.put(cacheKey, proxy.getClass());
		return proxy;
	}

	this.advisedBeans.put(cacheKey, Boolean.FALSE);
	return bean;
}
Copy the code

GetAdvicesAndAdvisorsForBean method invocation is eventually AbstractAdvisorAutoProxyCreator# getAdvicesAndAdvisorsForBean Methods, is further call * * AbstractAdvisorAutoProxyCreator# findEligibleAdvisors * * methods:

protected List<Advisor> findEligibleAdvisors(Class
        beanClass, String beanName) {
    // Find candidate advisors
	List<Advisor> candidateAdvisors = findCandidateAdvisors();
    // Filter out the available ones
	List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
	extendAdvisors(eligibleAdvisors);
	if(! eligibleAdvisors.isEmpty()) { eligibleAdvisors = sortAdvisors(eligibleAdvisors); }return eligibleAdvisors;
}
Copy the code
  • findCandidateAdvisors

    # AnnotationAwareAspectJAutoProxyCreator implementation class@Override
    protected List<Advisor> findCandidateAdvisors(a) {
    	// Find all Spring Advisors according to the superclass rules
    	List<Advisor> advisors = super.findCandidateAdvisors();
    	
    	if (this.aspectJAdvisorsBuilder ! =null) {
            // Find all aspects (annotated @aspect beans) and parse
    		advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
    	}
    	return advisors;
    }
    Copy the code
  • findAdvisorsThatCanApply

    protected List<Advisor> findAdvisorsThatCanApply( List
             
               candidateAdvisors, Class
               beanClass, String beanName)
              {
    
    	ProxyCreationContext.setCurrentProxiedBeanName(beanName);
    	try {
    		return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
    	}
    	finally {
    		ProxyCreationContext.setCurrentProxiedBeanName(null); }}Copy the code

So that completes the analysis of these two methods. When the notification and notifier are obtained, the proxy object is created

2.2.2 AbstractautoProxyCreate #createProxy Create a proxy class
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 proxy factory
	ProxyFactory proxyFactory = new ProxyFactory();
	proxyFactory.copyFrom(this);

    // Determine whether to use JDK proxy or CGLIB proxy
	if (proxyFactory.isProxyTargetClass()) {
		// Explicit handling of JDK proxy targets (for introduction advice scenarios)
		if (Proxy.isProxyClass(beanClass)) {
			// Must allow for introductions; can't just set interfaces to the proxy's interfaces only.
			for(Class<? > ifc : beanClass.getInterfaces()) { proxyFactory.addInterface(ifc); }}}else {
		// No proxyTargetClass flag enforced, let's apply our default checks...
		if (shouldProxyTargetClass(beanClass, beanName)) {
			proxyFactory.setProxyTargetClass(true);
		}
		else{ evaluateProxyInterfaces(beanClass, proxyFactory); }}// Add the notifier
	Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
	proxyFactory.addAdvisors(advisors);
	proxyFactory.setTargetSource(targetSource);
	customizeProxyFactory(proxyFactory);

	proxyFactory.setFrozen(this.freezeProxy);
	if (advisorsPreFiltered()) {
		proxyFactory.setPreFiltered(true);
	}

	// Use original ClassLoader if bean class not locally loaded in overriding class loader
	ClassLoader classLoader = getProxyClassLoader();
	if (classLoader instanceofSmartClassLoader && classLoader ! = beanClass.getClassLoader()) { classLoader = ((SmartClassLoader) classLoader).getOriginalClassLoader(); }// Create a proxy object
	return proxyFactory.getProxy(classLoader);
}
Copy the code

3. Spring’s easy process for creating beans

Beans are acquired primarily by the BeanFactory, but are created primarily by the BeanPostProcessor. The creation of the proxy class is implemented through the AbstractautoXyCreator class

Methods and postProcessAfterInitialization postProcessBeforeInstantiation methods to create objects to change and to strengthen the implementation agent object.

4. To summarize

The entire startup process of Spring AOP:

  • Create BeanFactoryAdvisorRetrievalHelperAdapter class (notification retrieves adapter) and BeanFactoryAspectJAdvisorsBuilderAdapter class
  • All call AbstractAutoProxyCreator# postProcessBeforeInstantiation method to find the Advisor and aspect, will cut build into Advisor
  • All call AbstractAutoProxyCreator# postProcessAfterInitialization method, from the cache will all enhancer, create agent factory, and woven into the intensifier, create a proxy object

Tips: mainly through to realize postProcessBeforeInstantiation and postProcessAfterInitialization these two methods to determine whether to create a proxy object and how to create the agent