与天地兮比寿,与日月兮齐光。这篇文章主要讲述老王读Spring IoC-5Spring IoC 小结——控制反转依赖注入相关的知识,希望能为你提供帮助。
@[TOC](Spring IoC 小结)
前言前面从源码的角度逐步分析了 Spring IoC 的实现原理和技术细节。现在对其特性进行总结。
(总结总是能更好的消化知识,形成体系)
版本约定Spring 5.3.9 (通过 SpringBoot 2.5.3 间接引入的依赖)
正文Spring IoC 具有两大功能:
- 控制反转
- 依赖注入
要实现" 控制反转" 的功能,Spring 需要扫描出 bean 的定义(即 BeanDefinition),并将其存放到容器中(即 BeanDefinitionRegistry)。
有了 BeanDefinition 元数据信息,Spring 就可以创建 bean 的实例了,从而实现了控制权的反转。
依赖注入依赖注入: 通过 @Autowired、@Resource 或者 xml 配置的方式定义 bean 的依赖,然后由 Spring 来注入依赖对象
要实" 现依赖注入" 的功能,Spring 需要解析出 bean 中的依赖属性(@Autowired、@Resource等标记的属性),然后通过 Spring " 控制反转" 的能力创建依赖 bean 的实例,最后对依赖赋值。
AbstractApplicationContext#refresh()在分析" 控制反转" 时,我们得知了 Spring 容器启动的入口是在
AbstractApplicationContext#refresh()
。经过对" 控制反转" 和" 依赖注入" 的分析后,我们也了解了实现该功能相应的入口方法,现在对其进行标记,便于我们从更高的角度来观察 Spring IoC 的实现:
// AbstractApplicationContext#refresh()
public void refresh() throws BeansException, IllegalStateException // 1. Prepare this context for refreshing.
prepareRefresh();
// 2. Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 3. Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);
// 4. Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);
// 5. Invoke factory processors registered as beans in the context.
// 执行 BeanFactoryPostProcessor。过程中会触发 BeanDefinition 的扫描注册。
// 关键类: ConfigurationClassPostProcessor
invokeBeanFactoryPostProcessors(beanFactory);
// 6. Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);
// 7. Initialize message source for this context.
initMessageSource();
// 8. Initialize event multicaster for this context.
initApplicationEventMulticaster();
// 9. Initialize other special beans in specific context subclasses.
onRefresh();
// 10. Check for listener beans and register them.
registerListeners();
// 11. Instantiate all remaining (non-lazy-init) singletons.
// 初始化所有非懒加载的 bean。(包括 bean 实例的创建和依赖属性填充)
finishBeanFactoryInitialization(beanFactory);
// 12. Last step: publish corresponding event.
finishRefresh();
所以,
控制反转
的前戏BeanDefinition 的扫描注册
的入口是在第 5 步 invokeBeanFactoryPostProcessors()
时触发的。依赖注入
的入口是在第 11 步 finishBeanFactoryInitialization()
时触发的,这里会初始化所有非懒加载的 bean,包括 bean 实例的创建和依赖属性的注入。IoC 的完整过程我们从上帝视角来看一下 IoC 的整个过程:
void ApplicationContext#refresh()
// 扫描出所有的 BeanDefinition
DefaultListableBeanFactory beanFactory = scanBeanDefinitions();
// 循环所有的 beanDefinitionNames
for(String beanName: beanFactory.beanDefinitionNames)
// 触发 bean 的实例化
getBean(beanName);
Object getBean()
// 创建 bean 的实例
createBeanInstance(beanName);
// 填充 bean 的依赖
// 填充依赖的 bean 时,又会触发依赖 bean 的实例化,即 getBean(依赖beanName)
populateBean(beanName);
上面使用伪代码的方式展现了整个 IoC 的粗略过程:
- 扫描出所有的 BeanDefinition,并注册到 BeanDefinitionRegistry 中
- 循环所有的 beanDefinitionNames,调用 getBean() 触发 bean 的实例化
- 创建 bean 的实例(通常是通过默认构造函数来创建)
- 填充 bean 的依赖(populateBean)
在填充依赖 bean 时,又会触发依赖 bean 的实例化,也就是通过 getBean() 来进行触发。
所以,这里会解决 bean 的连续依赖问题 和 循环依赖问题
AbstractApplicationContext#refresh()
。- 控制反转
" BeanDefinition 的扫描注册" 入口是在 refresh() 的第 5 步invokeBeanFactoryPostProcessors()
时触发的,关键类是ConfigurationClassPostProcessor
。
bean 实例的创建是在finishBeanFactoryInitialization()
时,加载 bean 时触发的。
- 依赖注入
依赖注入的入口是在 refresh() 的第 11 步finishBeanFactoryInitialization()
时触发的。关键方法是AbstractAutowireCapableBeanFactory#populateBean()
。populateBean()
方法会填充 bean 的依赖属性。
整个 IoC 的粗略过程如下:
- 扫描出所有的 BeanDefinition,并注册到 BeanDefinitionRegistry 中
- 循环所有的 beanDefinitionNames,调用 getBean() 触发 bean 的实例化
- 创建 bean 的实例(通常是通过默认构造函数来创建)
- 填充 bean 的依赖(populateBean)
在填充依赖 bean 时,又会触发依赖 bean 的实例化,也就是通过 getBean() 来进行触发。
所以,这里会解决 bean 的连续依赖问题 和 循环依赖问题
【老王读Spring IoC-5Spring IoC 小结——控制反转依赖注入】有关 Spring 源码方面的问题欢迎一起交流,备注:51cto (vx: Kevin-Wang001)
推荐阅读
- 第11篇-认识Stub与StubQueue
- Locust如何测试物联网MQTT
- #yyds干货盘点#JavaSE系列Java程序的封装——Java方法重载及递归
- #yyds干货盘点#Java面试经典100问
- 深入浅出 Java 中枚举的实现原理
- #yyds干货盘点#--docker容器快速入门
- 数仓建设保姆级教程,离线和实时一网打尽(理论+实战)
- xp系统如何转移我的文档保存资料的转移办法
- XP系统如何进行硬盘分区的简便设置