更多请关注: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()
- 处理所有的InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation() 方法
- 处理使用BY_NAME、BY_TYPE方式注入的Bean的属性
- 处理普通的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方法中主要的几种情况:
- 如果所需类型是Optional、ObjectFactory都会单独进行处理
- 如果字段或者方法参数前有@Lazy注解,则生成一个代理对象,并返回。
生成代理对象,在用户使用该Bean的方法时,代理对象才会去找Bean的属性并进行注入
- 如果贴的注解时@Value,则根据@value的value给属性进行赋值
@Value有三种方式:字符串、${}占位符、#{}EL表达式 如@Value(“#{userService}”),字符串会直接赋值,占位符会从环境变量中取值,el表达式会根据表达式找Bean
- 如果字段是个Collection、map,spring会找到所有符合类型的Bean进行赋值,如Map:
@Autowire
Map<String,UserService> userservices; //对于map,key必须是String。最后的结果就是找到所有的UserService类型的Bean存入map
- 处理正常的使用@Autowire注解场景,先根据类型找Bean,最后确定一个Bean并赋值
根据类型找Bean,如果找到多个,会依次做以下处理:
判断有没有指定主Bean,使用@primary实现
判断有没有指定优先级,使用@priority实现
根据name确定用哪一个