前言
IOC容器的一个强大功能就是可以实现自动注入,本节就来看一下自动注入的原理,并且看一下循环依赖是如何解决的。由于当前主要使用注解版本的Spring,我们来看下@Autowired注解的使用。
@Autowired注解可以写在:
1、属性上:先根据属性类型去找Bean,如果找到多个再根据属性名确定一个。
2、构造方法上:先根据方法参数类型去找Bean,如果找到多个再根据属性名确定一个。
3、set方法上:先根据方法参数类型去找Bean,如果找到多个再根据属性名确定一个。
正文
最常用的自动注入是下面这种形式,一种是使用@Value注解给基本类型注入值,另一种是使用@Autowired注解给持有的对象自动注入想要的类型。
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component
public class JimmyController {
@Value("Jimmy")
private String name;
@Autowired
private JimmyService jimmyService;
}
import org.springframework.stereotype.Component;
@Component
public class JimmyService {
}
1、寻找属性注入的点
在Bean生命周期过程中,后置处理器AutowiredAnnotationBeanPostProcessor的postProcessMergedBeanDefinition()方法会找到需要进行属性注入的点并缓存,流程如下:
1、遍历当前类所有的属性字段Field
2、检查字段上是否存在@Autowired、@Value、@Inject任意一个注解,存在则认为是一个注入的点
3、如果字段是static的,则不注入
4、获取到@Autowired的required属性的值
5、将字段信息构造成一个AutowiredFieldElement对象,并加到List集合currElements中
6、遍历当前类的所有方法Method
7、判断当前Method是否是桥接方法,如果是则找到原方法
8、检查方法上是否存在@Autowired、@Value、@Inject任意一个注解,存在则认为是一个注入的点
9、如果方法是static的,则不进行注入
10、获取到@Autowired的required属性的值
11、将字段信息构造成一个AutowiredMethodElement对象,并加到List集合currElements中
12、遍历完当前类的字段和方法后,将遍历父类,知道没有父类
13、将所有找到的注入点封装成集合并返回
以上过程有兴趣可以debug跟踪一下。
自动注入过程是在bean的生命周期中的populateBean()方法中完成的,我们来看一下。
2、属性注入
接下来实现属性注入就是依次遍历上面已经找到的属性,并通过反射进行注入。接下来看看源码。
首先,refresh()方法刷新容器,一路走到getBean()方法,这个方法便是产生bean实例的入口。
然后一路追踪到populateBean()方法里面,我们在这个方法里面看到这样一段代码,这段代码是将很多InstantiationAwareBeanPostProcessor类型的后置处理器找出来,然后执行其postProcessProperties()方法。
接下来进入AutowiredAnnotationBeanPostProcessor的**postProcessProperties()**这个方法看看:
@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
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;
}
我们可以看到,首先会读取到目标类中需要自动注入的所有属性,然后再一个一个进行注入。
我们先来看String类型属性的注入,跟踪代码,会在inject()方法中执行如下代码,箭头指的方法就是真正处理依赖的方法。
方法最终进入下面这个函数,会获取到依赖的类型和值,然后根据不同的类型做出不同的注入处理。将依赖的值返回给inject()方法,inject()方法再去反射给属性注入值。
下面就是inject()方法中典型的使用反射给属性注入值。
if (value != null) {
ReflectionUtils.makeAccessible(field);
field.set(bean, value);
}
上面看了String类型的属性注入,接下来看类类型的属性注入。会获得Service类型,并且第一次并没有得到具体的value,代码继续跟踪。
如果是类类型,就走到这个方法进行处理。
再进去这个方法,代码就很明显了,递归调用getBean()方法来实例化依赖的bean实例,并返回Object给inject()方法,反射注入属性。
至此,IOC容器的自动注入源码的核心部分就讲完了,接下来我们来看一个知识点,就是循环依赖。