前面我们分析了 IoC 之 BeanDefinition 的扫描注册,那么接下来要解决的问题就是依赖关系的注入。
通过 IoC之BeanDefinition扫描注册 的分析,我们知道 BeanDefinition 注册阶段,bean 的实例是没有产生的,
它只是将 BeanDefinition 注册到了 BeanDefinitionRegistry 中。
那么 bean 依赖的属性又是在什么时候注入到 bean 的实例中的呢?
Spring 5.3.9 (通过 SpringBoot 2.5.3 间接引入的依赖)
前面分析 BeanDefinition注册 时,我们知道依赖的注入是通过 InjectionMetadata.InjectedElement#inject() 来完成的。那么,我们就以这个点做为突破口。
AutowiredFieldElement 是来处理 @Autowired 属性类型注入的,所以,我们将断点打在 AutowiredFieldElement#inject() 上。
更多 InjectedElement 的知识请移步 @Resource与@Autowired的区别
我们可以看到,依赖的注入发生在 AbstractApplicationContext#finishBeanFactoryInitialization() 阶段,进行 populateBean
的时候。
查看 DefaultListableBeanFactory#preInstantiateSingletons() 的源码可以发现,Spring 会去循环所有的 beanDefinitionNames,逐个调用 getBean() 来初始化 bean。
// DefaultListableBeanFactory#preInstantiateSingletons()
public void preInstantiateSingletons() throws BeansException {
// Iterate over a copy to allow for init methods which in turn register new bean definitions.
// While this may not be part of the regular factory bootstrap, it does otherwise work fine.
List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
// Trigger initialization of all non-lazy singleton beans...
for (String beanName : beanNames) {
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
if (isFactoryBean(beanName)) {
Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
if (bean instanceof FactoryBean) {
FactoryBean<?> factory = (FactoryBean<?>) bean;
boolean isEagerInit;
if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
isEagerInit = AccessController.doPrivileged(
(PrivilegedAction<Boolean>) ((SmartFactoryBean<?>) factory)::isEagerInit,
getAccessControlContext());
} else {
isEagerInit = (factory instanceof SmartFactoryBean &&
((SmartFactoryBean<?>) factory).isEagerInit());
}
if (isEagerInit) {
getBean(beanName);
}
}
} else {
getBean(beanName);
}
}
}
......
}
从调用堆栈中,我们可以看到 inject() 之前做了两个重要的动作:doCreateBean() 和 populateBean()
doCreateBean(): 创建 bean 的实例
populateBean(): 填充 bean 依赖的属性
所以,依赖的注入是发生在创建 bean 的实例后,为 bean 的实例填充属性的时候(populateBean)。
AutowiredFieldElement#inject() 的代码比较简单,最关键的代码就是从 beanFactory 中将依赖解析出来:
Object value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
解析依赖的详细逻辑在 DefaultListableBeanFactory#doResolveDependency()
中:
DependencyDescriptor#resolveCandidate() 方法会触发依赖 bean 的加载动作,里面会调用 BeanFactory#getBean(),从而触发依赖 bean 的加载流程。
// DependencyDescriptor#resolveCandidate()
public Object resolveCandidate(String beanName, Class<?> requiredType, BeanFactory beanFactory)
throws BeansException {
return beanFactory.getBean(beanName);
}
依赖解析时的逻辑和顺序如下:
普通依赖的注入流程也就是 getBean() 的流程
可以看出,Spring 能处理的依赖类型有多种:
@Value 也是做为一种依赖类型在处理的。
也就是说: bean 里面被 @Value、@Component、@Autowired、@Resource 标记的属性都会被当作依赖进行注入。
划重点:依赖注入的过程,可以认为是 bean 中属性填充的过程。
Spring 对依赖的注入 AbstractApplicationContext#finishBeanFactoryInitialization
阶段。
这个时候,会遍历所有的 beanDefinitionNames,为每一个 BeanDefinition 去创建实例。
创建 BeanDefinition 的实例时,会先实例化 bean,然后再为 bean 的实例填充属性(populateBean),填充属性的过程也就是依赖注入的过程。
具体的注入动作是由 InjectionMetadata.InjectedElement#inject() 来完成的。
依赖解析时的逻辑和顺序如下:
课程 | 地址 |
---|---|
SpringIoC源码解读由浅入深 | https://edu.51cto.com/sd/68e86 |
如果本文对你有所帮助,欢迎点赞收藏!
源码测试工程下载:
老王读Spring IoC源码分析&测试代码下载
老王读Spring AOP源码分析&测试代码下载
公众号后台回复:下载IoC 或者 下载AOP 可以免费下载源码测试工程…
阅读更多文章,请关注公众号: 老王学源码
系列博文:
【老王读Spring IoC-0】Spring IoC 引入
【老王读Spring IoC-1】IoC 之控制反转引入
【老王读Spring IoC-2】IoC 之 BeanDefinition 扫描注册
【老王读Spring IoC-3】Spring bean 的创建过程
【老王读Spring IoC-4】IoC 之依赖注入原理
【老王读Spring IoC-5】Spring IoC 小结——控制反转、依赖注入
相关阅读:
【Spring源码三千问】@Resource 与 @Autowired 的区别
【Spring源码三千问】bean name 的生成规则
【Spring源码三千问】BeanDefinition详细分析
【Spring源码三千问】Spring 是怎样解决循环依赖问题的?
【Spring源码三千问】哪些循环依赖问题Spring解决不了?
【Spring源码三千问】@Lazy为什么可以解决特殊的循环依赖问题?
【Spring源码三千问】BeanDefinition注册、Bean注册、Dependency注册有什么区别?
【Spring源码三千问】Bean的Scope有哪些?scope=request是什么原理?
【Spring源码三千问】为什么要用三级缓存来解决循环依赖问题?二级缓存行不行?一级缓存行不行?