Spring源码学习(四) 依赖注入

更多请关注:https://t.zsxq.com/fhroW

spring创建Bean时进行依赖注入,大概流程就是找注入点、进入属性赋值

概念

  • 注入点:
    添加了@Autowire、@Value、@Resource的字段或者set方法称为注入点
  • pvs
    不算是概念,是spring源码中经常出现的一个命名,指BeanDefinition的PropertyValues属性,在依赖注入功能中主要的体现就是如果在MergedBeanDefinitionPostProcessors.postProcessMergedBeanDefinition()方法中指定了某个字段的值(即在pvs中添加键值对,key为字段名),则依赖注入时不会再进行处理
  • 环境变量(Environment):spring配置文件中的内容、启动命令中指定的参数都会存到环境变量中,@Value(“${}”)就是从环境变量中获取值

流程

依赖注入是在Bean创建过程中进行的,调用的位置是实例化后,初始化前。方法名:populateBean()

createBean{
	1:加载类
	2:InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation() 可以在此自己定义实例化规则,如果返回对象,则不做后面的处理了
	3:doCreateBean(){
		1:实例化Bean,经过这一步,就有对象了,但是对象属性没有值
		2:处理MergedBeanDefinitionPostProcessors.postProcessMergedBeanDefinition()方法  主要是对RootBeanDefinition的属性做操作,比如指定初始化方法等
		3:属性填充populateBean(){  
			1:处理InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation()  此时对象已经实例化但是没有属性,在此方法中可以自己进行依赖注入
			2:处理spring自带的依赖注入
			3:调用InstantiationAwareBeanPostProcessor.postProcessProperties() 去处理@Autowire、@Resource、@Value.经过这一步,对象已经有属性了
		}
		4:初始化initializeBean(){
			1:初始化前,处理BeanPostProcessor.postProcessBeforeInitialization()方法
			2:执行初始化方法,就是RootBeanDefinition中指定的初始化方法
			3:初始化后,处理BeanPostProcessor.postProcessAfterInitialization()方法,也是AOP主要实现的位置
		}
	}
}

populateBean()

  1. 处理所有的InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation() 方法
  2. 处理使用BY_NAME、BY_TYPE方式注入的Bean的属性
  3. 处理普通的Bean属性(这里会给属性赋值),通过InstantiationAwareBeanPostProcessor.postProcessProperties()方法
    之前说过BeanPostProcessor的处理逻辑,就是在某个时刻把所有的processor拿出来执行其中的某个方法,依赖注入和AOP就是通过这个机制实现的,这里InstantiationAwareBeanPostProcessor有多个子接口,比如AutowiredAnnotationBeanPostProcessor就是专门处理@Autowire注解的,还有处理@Resource注解的等
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
	...

	// 实例化之后,属性设置之前 处理所有的InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation() 方法
	...
	
	PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
	int resolvedAutowireMode = mbd.getResolvedAutowireMode();

	//如果该类标明使用BY_NAME或者BY_TYPE的注入方式,则在这里处理(这两种方式已经过期)
	if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {...}

	//遍历所有的InstantiationAwareBeanPostProcessor,执行其中的postProcessProperties方法
	for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
		// 这里会调用AutowiredAnnotationBeanPostProcessor的postProcessProperties()方法
		PropertyValues pvsToUse = bp.postProcessProperties(pvs,bw.getWrappedInstance(), beanName);
		...
	}
	...
	// 如果当前Bean中的BeanDefinition中设置了PropertyValues,那么最终将是PropertyValues中的值,覆盖@Autowired
	...
}

以Autowire注解的postProcessorProperties()方法为例

  • findAutowiringMetadata找到所有注入点
  • inject处理注入点,进行赋值
@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
	// 找注入点(所有被@Autowired注解了的Field或Method)
	InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
	metadata.inject(bean, beanName, pvs);
	return pvs;
}
找注入点

spring内部的方法可能在不同场景会被调用很多次,所以经常看到这样的逻辑:先判断缓存中是否存在,如果存在则返回,不存在则创建并存入缓存。

  • buildAutowiringMetadata()方法去找注入点
  • 注入点找到后被封装为InjectionMetadata类型,并存入缓存
private InjectionMetadata findAutowiringMetadata(String beanName, Class<?> clazz, @Nullable PropertyValues pvs) {
	// Fall back to class name as cache key, for backwards compatibility with custom callers.
	String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
	// Quick check on the concurrent map first, with minimal locking.
	InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);
	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;
}
buildAutowiringMetadata()方法

源码位置:org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor#buildAutowiringMetadata

  • 判断该注入点需不需要赋值,如果是基本类型就不进行处理
  • 遍历所有字段,检查是不是有@Autowire、@Value、@Inject注解
  • 遍历所有方法,检查是不是有这三个注解
  • 最终返回诸如点列表

注意:

  • 判断是不是基本类型的方式:判断该类的全限定名是不是"java. "开头
  • static修饰的方法和字段不会被添加注入点列表中
inject()方法:处理注入点,进行赋值

InstantiationAwareBeanPostProcessor多个实现类中inject方法的实现都不一样,这里依然以处理@Autowire注解的实现类为例。

inject方法中主要的几种情况:

  1. 如果所需类型是Optional、ObjectFactory都会单独进行处理
  2. 如果字段或者方法参数前有@Lazy注解,则生成一个代理对象,并返回。

生成代理对象,在用户使用该Bean的方法时,代理对象才会去找Bean的属性并进行注入

  1. 如果贴的注解时@Value,则根据@value的value给属性进行赋值

@Value有三种方式:字符串、${}占位符、#{}EL表达式 如@Value(“#{userService}”),字符串会直接赋值,占位符会从环境变量中取值,el表达式会根据表达式找Bean

  1. 如果字段是个Collection、map,spring会找到所有符合类型的Bean进行赋值,如Map:
@Autowire
Map<String,UserService> userservices; //对于map,key必须是String。最后的结果就是找到所有的UserService类型的Bean存入map
  1. 处理正常的使用@Autowire注解场景,先根据类型找Bean,最后确定一个Bean并赋值
根据类型找Bean,如果找到多个,会依次做以下处理:
判断有没有指定主Bean,使用@primary实现
判断有没有指定优先级,使用@priority实现
根据name确定用哪一个
  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值