SpringBoot -- 自动配置类AopAutoConfiguration解析、注册BeanDefinition过程 | Aop默认使用Cglib代理过程

SpringBoot 同时被 2 个专栏收录
6 篇文章 0 订阅
8 篇文章 0 订阅

 本版本源码为SpringBoot - 2.3.3.RELEASE,即spring-beans: 5.2.8.RELEASE
·
  在上一篇文章2.5.2.2节介绍了grouping.getImports()会获取所有符合的自动配置类名
·
 然后循环遍历调用processImports来对自动配置类进行处理

 本文以AopAutoConfiguration为栗子,对自动配置类的解析和注册再详细介绍一下

0. AopAutoConfiguration:

  先大概说明下@ConditionOnXXX原理:

  • 如果条件匹配,则条件结果对象ConditionOutcome的内部属性match为true,即该组件允许引入
@Configuration(proxyBeanMethods = false)
// 如果环境(配置文件)没有配置spring.aop.auto键值对,默认引入AopAutoConfiguration(因为 matchIfMissing = true,即上述match为true)
// 如果环境(配置文件)配置了spring.aop.auto键值对,如果value和havingValue相等,则上述match为true,即引入AopAutoConfiguration
@ConditionalOnProperty(prefix = "spring.aop", name = "auto", havingValue = "true", matchIfMissing = true)
public class AopAutoConfiguration {

	@Configuration(proxyBeanMethods = false)
	// 如果加载到Advice.class这个类,则上述match为true,就引入AspectJAutoProxyingConfiguration组件
	@ConditionalOnClass(Advice.class)
	static class AspectJAutoProxyingConfiguration {

		@Configuration(proxyBeanMethods = false)
		@EnableAspectJAutoProxy(proxyTargetClass = false)
		// 如果环境(配置文件)没有配置spring.aop.proxy-target-class键值对,默认不引入JdkDynamicAutoProxyConfiguration
		// 因为 matchIfMissing = false,即上述match为false)
		@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "false",
				matchIfMissing = false)
		static class JdkDynamicAutoProxyConfiguration {

		}

		@Configuration(proxyBeanMethods = false)
		@EnableAspectJAutoProxy(proxyTargetClass = true)
		// 如果环境(配置文件)没有配置spring.aop.proxy-target-class键值对,默认引入CglibAutoProxyConfiguration
		// 因为 matchIfMissing = true,即上述match为true)
		@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true",
				matchIfMissing = true)
		static class CglibAutoProxyConfiguration {

		}
	}

	@Configuration(proxyBeanMethods = false)
	// 如果加载不到org.aspectj.weaver.Advice这个类,则上述match为true,就引入ClassProxyingConfiguration组件
	@ConditionalOnMissingClass("org.aspectj.weaver.Advice")
	@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true",
			matchIfMissing = true)
	static class ClassProxyingConfiguration {

		ClassProxyingConfiguration(BeanFactory beanFactory) {
			if (beanFactory instanceof BeanDefinitionRegistry) {
				BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
				AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
				AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
			}
		}
	}
}


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

 通过上面条件注解的介绍,可以知道,在默认条件,即只引入spring-boot-starter-aop依赖,会引入三个组件Bean:

  • AopAutoConfiguration
  • AspectJAutoProxyingConfiguration
  • CglibAutoProxyConfiguration

1. processGroupImports

  在上一篇文章2.5.2.2节介绍处理自动配置类入口:循环遍历调用processImports来对自动配置类进行处理

 处理AopAutoConfiguration时,processImports入参将配置类名封装成SourceClass
·
 configurationClass为当前主配置类,也就是说通过该主配置类引入的AopAutoConfiguration

public void processGroupImports() {
			... ... ...
			try {
				// 遍历递归处理解析的配置类名取处理配置类,包括嵌套引入的组件配置类;比如@Bean之类
				// 入参将配置类名entry.getImportClassName()封装成ConfigurationClassParser.SourceClass
				// 在内部processConfigurationClass方法入参会将SourceClass转换成ConfigurationClass
				processImports(configurationClass, asSourceClass(configurationClass, exclusionFilter),
						Collections.singleton(asSourceClass(entry.getImportClassName(), exclusionFilter)),
						exclusionFilter, false);
			}
			... ... ... //异常捕获抛出
		});
	}
}

 1.1. processImports:

 对于AopAutoConfiguration,只有@Configuration、@ConditionalOnProperty注解,直接调用processConfigurationClass去处理

private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
		Collection<SourceClass> importCandidates, Predicate<String> exclusionFilter,
		boolean checkForCircularImports) {
	... ... ...

	if (checkForCircularImports && isChainedImportOnStack(configClass)) {
		this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
	}
	else {
		this.importStack.push(configClass);
		try {
			for (SourceClass candidate : importCandidates) {
				if (candidate.isAssignable(ImportSelector.class)) {
					... ... ...
				}
				else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
					... ... ...
				}
				else {
					this.importStack.registerImport(
							currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());
					// 不属于以上两种类型,当作配置类处理入参将自身转换为ConfigurationClass
					// 会将主配置类configClass添加到ConfigurationClass内部属性this.importedBy
					// 这表明引入的所属关系,即AopAutoConfiguration是通过主配置类引入的
					processConfigurationClass(candidate.asConfigClass(configClass), exclusionFilter);
				}
			}
		}
		... ... ..
}

 1.2. processConfigurationClass:

 先进行@ConditionOnXXX条件匹配,匹配成功,则调用doProcessConfigurationClass解析嵌套类和自身

	protected void processConfigurationClass(ConfigurationClass configClass, Predicate<String> filter) throws IOException {
		// shouldSkip主要时匹配@ConditionOnXXX的条件,匹配规则见上文,这里不跟源码了
		// 对于AopAutoConfiguration,默认匹配成功引入该组件,则不跳过,即shouldSkip返回false
		if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
			return;
		}

		... ... ... // 当前AopAutoConfiguration配置类没有重复解析,省略代码

		// 作为配置类,需要去解析是否有嵌套配置类,所以要封装成SourceClass
		SourceClass sourceClass = asSourceClass(configClass, filter);
		do {
			// 核心解析配置类方法,解析嵌套和自身
			sourceClass = doProcessConfigurationClass(configClass, sourceClass, filter);
		}
		while (sourceClass != null);
		// 配置类解析完,添加到configurationClasses,用于上述判断重复解析,以及后续注册
		this.configurationClasses.put(configClass, configClass);
	}

 1.3. doProcessConfigurationClass:

 核心解析配置类方法,对于AopAutoConfiguration,不涉及@ComponentScan、@Import、@Bean等注解
·
 所以此时只调用processMemberClasses进行嵌套类解析

	protected final SourceClass doProcessConfigurationClass(
			ConfigurationClass configClass, SourceClass sourceClass, Predicate<String> filter)
			throws IOException {

		if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
			// 内部嵌套类解析
			processMemberClasses(configClass, sourceClass, filter);
		}

		... ... ... // AopAutoConfiguration不涉及 @ComponentScan、@Import等注解,直接省略
		return null;
	}

 1.4. processMemberClasses:

 会获取当前配置类的嵌套类,对于当前AopAutoConfiguration,会获取到:

  • AspectJAutoProxyingConfiguration
  • ClassProxyingConfiguration
	private void processMemberClasses(ConfigurationClass configClass, SourceClass sourceClass,
			Predicate<String> filter) throws IOException {

		// 获取内部嵌套类并封装成SourceClass
		Collection<SourceClass> memberClasses = sourceClass.getMemberClasses();
		if (!memberClasses.isEmpty()) {
			List<SourceClass> candidates = new ArrayList<>(memberClasses.size());
			for (SourceClass memberClass : memberClasses) {
				// 判断嵌套类是否是配置类且不是自身
				if (ConfigurationClassUtils.isConfigurationCandidate(memberClass.getMetadata()) &&
						!memberClass.getMetadata().getClassName().equals(configClass.getMetadata().getClassName())) {
					candidates.add(memberClass);
				}
			}
			OrderComparator.sort(candidates);
			// 循环解析符合的嵌套类
			for (SourceClass candidate : candidates) {
				if (this.importStack.contains(configClass)) {
					this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
				}
				else {
					this.importStack.push(configClass);
					try {
						// 调用processConfigurationClass核心解析方法来解析						
						// 入参转换成ConfigurationClass,会将配置类configClass添加到ConfigurationClass内部属性this.importedBy
						// 即表明内部嵌套类是通过AopAutoConfiguration引入的
						processConfigurationClass(candidate.asConfigClass(configClass), filter);
					}
					finally {
						this.importStack.pop();
					}
				}
			}
		}
	}

 1.5. 循环递归处理:

 解析嵌套类就和解析AopAutoConfiguration一样,重复调用上述1.2 - 1.4的方法,整体如下:

在这里插入图片描述

 递归循环处理后的结果就是会引入以下组件,并封装成ConfigurationClass类型

  • AopAutoConfiguration
  • AspectJAutoProxyingConfiguration
  • CglibAutoProxyConfiguration

 此外,在解析CglibAutoProxyConfiguration时,会引入AspectJAutoProxyRegistrar
·
 在processImports方法会实例化该对象,并添加到CglibAutoProxyConfiguration

private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
		Collection<SourceClass> importCandidates, Predicate<String> exclusionFilter,
		boolean checkForCircularImports) {
	... ... ...

	if (checkForCircularImports && isChainedImportOnStack(configClass)) {
		this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
	}
	else {
		this.importStack.push(configClass);
		try {
			for (SourceClass candidate : importCandidates) {
				if (candidate.isAssignable(ImportSelector.class)) {
					... ... ...
				}
				// AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar 条件成立
				else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
						Class<?> candidateClass = candidate.loadClass();
						// 获取AspectJAutoProxyRegistrar实例对象,但为进行BeanDefinition注册
						ImportBeanDefinitionRegistrar registrar =
								ParserStrategyUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class,
										this.environment, this.resourceLoader, this.registry);
						// 将AspectJAutoProxyRegistrar添加到所属配置类
						// 后面注册BeanDefinition时会调用
						configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
				}
				else {
		... ... ...
}

2. loadBeanDefinitionsForConfigurationClass

 在上一篇文章2.6节介绍了注册BeanDefinitions的入口,会循环调用loadBeanDefinitionsForConfigurationClass

private void loadBeanDefinitionsForConfigurationClass(
		ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator) {

	// 条件注解判断是否跳过这个配置类
	if (trackedConditionEvaluator.shouldSkip(configClass)) {
		String beanName = configClass.getBeanName();
		if (StringUtils.hasLength(beanName) && this.registry.containsBeanDefinition(beanName)) {
			// 如果跳过,Spring容器中移除bean的注册
			this.registry.removeBeanDefinition(beanName);
		}
		// 从importRegistry 中也移除
		this.importRegistry.removeImportingClass(configClass.getMetadata().getClassName());
		return;
	}
	// 如果这是一个通过import机制引入的配置类,也就是内部属性importedBy有所属的配置类
	// 比如AopAutoConfiguration是主配置(启动)类引入的,则importedBy存的就是主配置类,上文1.1. 也介绍了
	if (configClass.isImported()) {
		registerBeanDefinitionForImportedConfigurationClass(configClass);
	}
	for (BeanMethod beanMethod : configClass.getBeanMethods()) {
		// 现在把配置类里面@Bean注解的方法作为bean定义注册到容器
		loadBeanDefinitionsForBeanMethod(beanMethod);
	}

	// 从配置类导入的bean定义资源中获取bean定义信息并注册到容器,比如xml
	loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
	// 从配置类导入的ImportBeanDefinitionRegistrar中获取bean定义信息并注册到容器	
	loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
}

 2.1. registerBeanDefinitionForImportedConfigurationClass

 还是以AopAutoConfiguration为栗子,它是由主配置类引入的,所以条件成立会执行该方法

private void registerBeanDefinitionForImportedConfigurationClass(ConfigurationClass configClass) {
	// 获取当前配置类元数据
	AnnotationMetadata metadata = configClass.getMetadata();
	// 构建BeanDefinition,为AnnotatedGenericBeanDefinition类型
	// 会从元数据metadata获取className,然后给configBeanDef内部属性beanClass赋值
	AnnotatedGenericBeanDefinition configBeanDef = new AnnotatedGenericBeanDefinition(metadata);

	ScopeMetadata scopeMetadata = scopeMetadataResolver.resolveScopeMetadata(configBeanDef);
	// 设置Scope,默认singleton
	configBeanDef.setScope(scopeMetadata.getScopeName());
	// 解析出beanName,如果是自动配置类,则为beanClass(上文有赋值)
	// 如果是@Component(value = "beanName")这些注解定义有value ,会解析出value值给作beanName
	String configBeanName = this.importBeanNameGenerator.generateBeanName(configBeanDef, this.registry);
	// 这是会针对@Lazy、@Primary()、@DependsOn、@Role、@Description注解给当前BeanDefinition进行对应的赋值
	AnnotationConfigUtils.processCommonDefinitionAnnotations(configBeanDef, metadata);

	// 将BeanDefinition封装成持有者对象BeanDefinitionHolder
	BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(configBeanDef, configBeanName);
	definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
	// 会调用registerBeanDefinition进行BeanDefinition注册,最终会将组件包括嵌套的beanDefinition添加到beanDefinitionMap,以及beanDefinitionNames
	this.registry.registerBeanDefinition(definitionHolder.getBeanName(), definitionHolder.getBeanDefinition());
	// 给当前配置类也设置beanName
	configClass.setBeanName(configBeanName);

	if (logger.isTraceEnabled()) {
		logger.trace("Registered bean definition for imported class '" + configBeanName + "'");
	}
}

 最终会将组件包括嵌套的beanDefinition添加到beanDefinitionMap,以及beanDefinitionNames

在这里插入图片描述

 2.2. loadBeanDefinitionsForBeanMethod

 这个是处理@Bean的,其实也差不多,这里不展开介绍了
·
 都是构建BeanDefinition,然后根据条件赋值,之后通过registerBeanDefinition注册进去

 2.3. loadBeanDefinitionsFromRegistrars

 @EnableAspectJAutoProxy注解会引入AspectJAutoProxyRegistrar,在上文1.5也提到
·
 AspectJAutoProxyRegistrar重写了registerBeanDefinitions方法,这里便是调用重写后的方法注册

public void registerBeanDefinitions(
		AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {

	// 默认先创建一个AnnotationAwareAspectJAutoProxyCreator的BeanDefinition,然后注册进去
	// 注册的beanName为org.springframework.aop.config.internalAutoProxyCreator
	AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);

	// 获取@EnableAspectJAutoProxy的键值对
	AnnotationAttributes enableAspectJAutoProxy =
			AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
	if (enableAspectJAutoProxy != null) {
		// 对于默认引入的CglibAutoProxyConfiguration,其@EnableAspectJAutoProxy(proxyTargetClass = true)
		// 条件成立
		if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
			// 设置创建代理类的条件?
			AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
		}
		// 这个没怎么见过,不管了
		if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {
			AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
		}
	}
}


public static void forceAutoProxyCreatorToUseClassProxying(BeanDefinitionRegistry registry) {
	// 默认会注册有这个BeanDefinition,条件成立
	if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
		BeanDefinition definition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
		// 这个给PropertyValues添加proxyTargetClass = true
		// 创建internalAutoProxyCreator这个bean的时候会用到
		definition.getPropertyValues().add("proxyTargetClass", Boolean.TRUE);
	}
}

 到这里AopAutoConfiguration及其嵌套类解析、注册都介绍完了,这后的流程可以继续阅读上一篇文章

3. applyPropertyValues

 在创建internalAutoProxyCreator时候,在属性填充populateBean时,会调用applyPropertyValues方法
·
 会将上文的PropertyValues属性填充到创建的bean

protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
	... ... //省略
	
	PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);

	... ... //省略
	// 将PropertyValues设置(填充)到当前bean里
	if (pvs != null) {
		applyPropertyValues(beanName, mbd, bw, pvs);
	}

 在方法执行前pvs中proxyTargetClass为true,internalAutoProxyCreator这个bean的proxyTargetClass为false

在这里插入图片描述

 方法调用后,internalAutoProxyCreator这个bean的proxyTargetClass为true

在这里插入图片描述

4. 代理类创建

 4.1.举个栗子:

@Aspect
@Component
public class AopAspectConfiguration {
    //此处写具体切点. 具体写法可以百度 路径一定要正确
    @Pointcut("execution(public * com.aop.AopTestController.*(..))")
    public void pointcut() {
    }

    @Before("pointcut()")
    public void deBefore(JoinPoint joinPoint) throws Throwable {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        // 记录下请求内容  路径 ip 请求方法名  请求参数等等
        System.out.println("URL : " + request.getRequestURL().toString());
        System.out.println("ARGS : " + Arrays.toString(joinPoint.getArgs()));
    }
}

@Controller
public class AopTestController {

    @RequestMapping("/testaop")
    @ResponseBody
    public String testAop(@RequestParam("key") String KeyName) {
        return "testaop";
    }
}

 当spring容器创建aopTestController这个bean时,在bean生命周期的initializeBean进行实例化处理
·
 即调用后置处理器的postProcessAfterInitialization方法,默认会调用internalAutoProxyCreator来创建代理类
·
 beanName为internalAutoProxyCreator,bean类型为AnnotationAwareAspectJAutoProxyCreator

 4.2.AbstractAutoProxyCreator#postProcessAfterInitialization

 这里只关注Spring是如何默认创建Cglib代理的,其他细节暂时忽略

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

protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
	... ... ... // 省略
	
	Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
	if (specificInterceptors != DO_NOT_PROXY) {
		this.advisedBeans.put(cacheKey, Boolean.TRUE);
		// 创建代理的方法
		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;
}

 4.3.createProxy

 这里会创建代理工厂ProxyFactory,然后给工厂设置advisors、target等,然后调用getProxy来创建代理类

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

		ProxyFactory proxyFactory = new ProxyFactory();
		// 将this的一些属性赋值给proxyFactory,this为AnnotationAwareAspectJAutoProxyCreator
		// 经过copyFrom后proxyFactory的proxyTargetClass为true
		proxyFactory.copyFrom(this);
		... ... // 省略,ProxyFactory一些设置,比如advisors
	
		return proxyFactory.getProxy(getProxyClassLoader());
	}

 4.4.proxyFactory.getProxy

 先来看看代理工厂的类图:

在这里插入图片描述

 方法调用链:getProxy → createAopProxy

protected final synchronized AopProxy createAopProxy() {
	if (!this.active) {
		activate();
	}
	// this就是代理工厂ProxyFactory
	return getAopProxyFactory().createAopProxy(this);
}

// 入参config就是ProxyFactory
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
	// 这里就会根据proxyTargetClass来判断创建Cglib还是Jdk代理
	// 由上面的分析可见,默认proxyTargetClass为true, config.isProxyTargetClass()成立
	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.");
		}
		// 对于代理目标对象是接口,则还是用Jdk代理,什么栗子会触发?
		if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
			return new JdkDynamicAopProxy(config);
		}
		// Class默认创建Cglib代理
		return new ObjenesisCglibAopProxy(config);
	}
	else {
		return new JdkDynamicAopProxy(config);
	}
}

 4.5. 小结:

  • Spring容器通过proxyTargetClass属性值来判断使用Cglib还Jdk代理,默认使用Cglib(如果对于代理目标对象是接口,则还是用Jdk代理)
  • 可以在配置文件设置spring.aop.proxy-target-class为false控制使用Jdk代理(因为@EnableAspectJAutoProxy(proxyTargetClass = false))
  • 0
    点赞
  • 0
    评论
  • 0
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

©️2021 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值