SpringBoot之集成SpringAOP分析(续)

Posted 木叶之荣

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SpringBoot之集成SpringAOP分析(续)相关的知识,希望对你有一定的参考价值。

这里我们先对上一篇文章的内容做一个总结,原谅我再次贴一下AopAutoConfiguration 这个类的代码

@Configuration
@ConditionalOnClass( EnableAspectJAutoProxy.class, Aspect.class, Advice.class,
		AnnotatedElement.class )
@ConditionalOnProperty(prefix = "spring.aop", name = "auto", havingValue = "true", matchIfMissing = true)
public class AopAutoConfiguration 
	@Configuration
	@EnableAspectJAutoProxy(proxyTargetClass = false)
	@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "false", matchIfMissing = false)
	public static class JdkDynamicAutoProxyConfiguration 
	
	@Configuration
	@EnableAspectJAutoProxy(proxyTargetClass = true)
	@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true", matchIfMissing = true)
	public static class CglibAutoProxyConfiguration 
	

根据我们在上一篇文章中分析
1、在SpringBoot启动的过程中会调AutoConfigurationImportSelector#selectImports的方法,在这个方法中会从所有类路径下的spring.factories中加载key为org.springframework.boot.autoconfigure.EnableAutoConfiguration的配置项信息,并从spring-autoconfigure-metadata.properties中加载所有的配置项信息,接着判断EnableAutoConfiguration所对应的value是否能被当前类加载器所加载,判断的逻辑是循环EnableAutoConfiguration对应的value+.ConditionalOnClass然后从spring-autoconfigure-metadata.properties中找对应的value,然后判断能否加载这个value,如果我们这里EnableAutoConfiguration对应的是org.springframework.boot.autoconfigure.aop.AopAutoConfiguration这个配置项,在spring-autoconfigure-metadata.properties中org.springframework.boot.autoconfigure.aop.AopAutoConfiguration.ConditionalOnClass所对应的value是:org.springframework.context.annotation.EnableAspectJAutoProxy,org.aspectj.lang.annotation.Aspect,org.aspectj.lang.reflect.Advice,org.aspectj.weaver.AnnotatedElement。当我们在引入spring-boot-starter-aop这个Maven依赖的时候:Aspect、Advice、AnnotatedElement这三个类所在的jar同时被引入进来。
2、接着会调用ConfigurationClassParser#processConfigurationClass这个方法,调用信息如下:

首先会判断是否要跳过对这个类的解析,由于AopAutoConfiguration满足继续往下执行的条件,接下来会判断当前类是否被解析过了,最后会调用doProcessConfigurationClass这个方法对AopAutoConfiguration进行解析
3、在doProcessConfigurationClass中会调用processMemberClasses方法,对所传入的内部类进行处理,在这里对应的内部类是:JdkDynamicAutoProxyConfiguration和CglibAutoProxyConfiguration这两个内部类。其对应的处理信息如下所示:

4、接着会继续调用processConfigurationClass这个方法进行内部类的处理:

我们上面说了在AopAutoConfiguration中有两个内部类JdkDynamicAutoProxyConfiguration和CglibAutoProxyConfiguration,这两个类是不会被同时解析的,因为这两个类代表着不同的代理模式,那么在我们什么都没有配置的情况下默认会使用哪种代理模式呢?答案就在这两个类的@ConditionalOnProperty这个注解上面。对于JdkDynamicAutoProxyConfiguration来说,它的@ConditionalOnProperty(prefix = “spring.aop”, name = “proxy-target-class”, havingValue = “false”, matchIfMissing = false),从这个注解上面我们可以看到如果只有配置项为spring.aop.proxy-target-class为false的话,这个类会生效。我们再来看看CglibAutoProxyConfiguration这个类,它的@ConditionalOnProperty(prefix = “spring.aop”, name = “proxy-target-class”, havingValue = “true”, matchIfMissing = true),从这个注解上我们可以看到如果spring.aop.proxy-target-class为true或者什么都不配置的话,CglibAutoProxyConfiguration这个类会生效,即***默认的是Cglib动态代理***。最后又是调用到了doProcessConfigurationClass这里
5、对于CglibAutoProxyConfiguration来说,这个类只是一个标识性的类,我们需要关注的是@EnableAspectJAutoProxy(proxyTargetClass = true)这个注解。

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy 
	boolean proxyTargetClass() default false;
	boolean exposeProxy() default false;

在EnableAspectJAutoProxy这个类上有@Import(AspectJAutoProxyRegistrar.class),同样在doProcessConfigurationClass这个方法中有这样一段代码:

//在getImports这个方法中会获取到AspectJAutoProxyRegistrar这个类,然后调用processImports
//这个方法进行处理
processImports(configClass, sourceClass, getImports(sourceClass), true);

因为CglibAutoProxyConfiguration只是一个标识性的接口,所以我们直接关注上面那一段代码即可。processImports这个方法也是非常重要的一个方法。关于这个方法的内容我们先不展开的,主要说一下这个方法把传入的Import分为了三种类型进行处理:实现ImportSelector接口的类、实现了ImportBeanDefinitionRegistrar接口的类,不属于前两种类型的。AspectJAutoProxyRegistrar这个接口是实现了ImportBeanDefinitionRegistrar这个接口。对应的处理是:

else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) 
	// Candidate class is an ImportBeanDefinitionRegistrar ->
	// delegate to it to register additional bean definitions
	//先加载一下类
	Class<?> candidateClass = candidate.loadClass();
	//实例化AspectJAutoProxyRegistrar 已经支持Kotlin
	ImportBeanDefinitionRegistrar registrar = BeanUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class);
	//设置BeanClassLoaderAware BeanFactoryAware EnvironmentAware ResourceLoaderAware
	ParserStrategyUtils.invokeAwareMethods(registrar, this.environment, this.resourceLoader, this.registry);
	//放入configClass中 后续会用到
	configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());

6、调用AspectJAutoProxyRegistrar#registerBeanDefinitions的调用链如下所示:

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

如果你看过前面几篇文章关于AOP的分析的话,看到上面的代码应该会有熟悉的感觉了,这里就不再多说了。好了,SpringBoot继承AOP的过程到此就分析完了。

以上是关于SpringBoot之集成SpringAOP分析(续)的主要内容,如果未能解决你的问题,请参考以下文章

SpringBoot之集成SpringAOP分析(续)

SpringBoot之集成SpringAOP分析(续)

Spring系列之Spring框架和SpringAOP集成过程分析

Spring系列之Spring框架和SpringAOP集成过程分析

Spring系列之Spring框架和SpringAOP集成过程分析

Springboot源码分析之EnableAspectJAutoProxy