spring依赖处理过程

本文详细剖析了Spring框架中的@Autowired注解在bean初始化过程中的作用,包括`AutowiredAnnotationBeanPostProcessor`类的`postProcessMergedBeanDefinition`和`postProcessProperties`方法,展示了如何查找依赖字段并进行注入。
摘要由CSDN通过智能技术生成

今天我们来聊一聊spring依赖处理的过程
关于依赖处理比较重要的类就是org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor
于是我们着重看看这个类里的两个方法,分别是

postProcessMergedBeanDefinitionpostProcessProperties,我们一个方法一个方法来看

1.依赖处理经过的第一个方法:postProcessMergedBeanDefinition

@Override
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
	/*
	 * 查找需要注入字段的类所需注入的字段
	 * 这里方法的参数 beanDefinition、beanType、beanName 
	 * 均与需要注入的对象有关
	 * 这里的如果没有父类,RootBeanDefinition就是自己
	 */
	InjectionMetadata metadata = findAutowiringMetadata(beanName, beanType, null);
	/*
	 * 检验,非重点代码
	 */
	metadata.checkConfigMembers(beanDefinition);
}

每个bean都要经过postProcessMergedBeanDefinition() 方法,当bean被merge(合并)后,就产生这个方法的回调

postProcessMergedBeanDefinition() 的第一步就是先找到需要注入字段的类所需要注入的字段(也就是标注了 @Autowire 的字段)

findAutowiringMetadata()

private InjectionMetadata findAutowiringMetadata(String beanName, Class<?> clazz, @Nullable PropertyValues pvs) {
		// 首先获取缓存key,一般来说key就是beanName
		String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
		// 首先从缓存中获取,由于是第一次调用这个方法缓存内必然没有信息
		InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);
		// 判断该metedata需不需要刷新,具体逻辑跳过
		if (InjectionMetadata.needsRefresh(metadata, clazz)) {
			synchronized (this.injectionMetadataCache) {
				metadata = this.injectionMetadataCache.get(cacheKey);
				if (InjectionMetadata.needsRefresh(metadata, clazz)) {
					if (metadata != null) {
						metadata.clear(pvs);
					}
					// 构建元信息
					metadata = buildAutowiringMetadata(clazz);
					this.injectionMetadataCache.put(cacheKey, metadata);
				}
			}
		}
		return metadata;
	}

可以看出,findAutowiringMetadata() 方法里首先是对缓存进行判断,然后再根据其他条件来判断要不要重新构建元信息

我们来看看 buildAutowiringMetadata(clazz) 构建元信息方法

private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz) {
		do {
			final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>();
			
			ReflectionUtils.doWithLocalFields(targetClass, field -> {
				// 这里会递归去查找上层字段(父类字段)
				MergedAnnotation<?> ann = findAutowiredAnnotation(field);
				if (ann != null) {
					// 过滤static字段
					if (Modifier.isStatic(field.getModifiers())) {
						if (logger.isInfoEnabled()) {
							logger.info("Autowired annotation is not supported on static fields: " + field);
						}
						return;
					}
					boolean required = determineRequiredStatus(ann);
					// 找到后加入到元信息里
					currElements.add(new AutowiredFieldElement(field, required));
				}
			});
		}
		while (targetClass != null && targetClass != Object.class);

		return InjectionMetadata.forElements(elements, clazz);
	}

这里我们由于我们只关心 doWithLocalFields 方法,所以其他代码省略
doWithLocalFields方法里,它先会递归去查找上层(也就是父类)主要注入的字段和自己的字段,同时过滤掉static字段(这也是为什么spring不支持static字段的注入),接着加入到元信息中,返回给上层

至此,postProcessMergedBeanDefinition基本上分析完毕

2.依赖处理经过的方法:postProcessProperties

@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
	//首先还是先执行findAutowiringMetadata()方法,这里上面已经提到过
	InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
	try {
		metadata.inject(bean, beanName, pvs);
	}
	catch (BeanCreationException ex) {
		throw ex;
	}
	catch (Throwable ex) {
		throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);
	}
	return pvs;
}

postProcessMergedBeanDefinition() 方法调用完后,其系统内部会通过回调的方式来调用 postProcessProperties() 方法

首先还是先调用 findAutowiringMetadata() 方法,不过与第一次不同的地方在于,由于他是第二次调用这个方法,因此里面会有缓存,通常情况下会直接从缓存中获取数据

public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
	element.inject(target, beanName, pvs);
}
@Override
protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
	Field field = (Field) this.member;
	Object value;
	// 依赖查找过程
	value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);

	if (value != null) {
		ReflectionUtils.makeAccessible(field);
		// 查找出value后进行反射注入
		field.set(bean, value);
	}
}

然后进入inject() 方法,该方法的主要作用是根据前面所查到的字段,先进行依赖查找,当value不为空则以反射的方式设置属性,随后pojo类的set方法将被触发

至此依赖处理过程分析完毕

其中resolveDependency方法的分析在我spring依赖查找这篇文章里

3.总结

  • spring在进行依赖处理的时候首先是经过 postProcessMergedBeanDefinition() 方法,该方法是查找类所需要注入的对象
  • 然后以某种回调的方式调用 postProcessProperties() 方法,该方法会对bean做依赖查找以及反射方式注入的工作
  • postProcessProperties() 完成后,pojo类的set方法也被调用了
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值