依赖查找的来源
先理解一个问题:Spring 到哪里找 Bean?
当我们调用下面的方法时,Spring 需要根据 Bean 名称或类型找到一个对象:
1 | applicationContext.getBean("user"); |
这就是依赖查找。Spring 主要从 IoC 容器中已经登记的两类对象里查找:
- BeanDefinition 创建的 Bean:容器根据 BeanDefinition 描述,创建并管理 Bean 实例。
- 手动注册的单例对象:已经存在的普通 Java 对象,被直接注册到容器中。
简单来说,依赖查找的范围可以概括为:
先在 BeanDefinition 创建的 Bean 中查找,再在容器登记的单例对象中查找。
BeanDefinition 创建的 Bean
BeanDefinition 是 Bean 的“定义信息”,描述了 Bean 的类型、名称以及创建方式。Spring 根据这些信息创建 Bean,并将 Bean 放入 IoC 容器中。
常见的定义方式有:
1 | <bean id="user" class="xxx.xxx.User" /> |
1 |
|
也可以通过 BeanDefinitionBuilder 以编程方式创建 BeanDefinition,再通过 BeanDefinitionRegistry#registerBeanDefinition 注册。
Spring 内置的 BeanDefinition
除了我们自己定义的 Bean,Spring 还会注册一些用于支撑框架运行的 BeanDefinition。例如:
| Bean 名称 | Bean 实例 | 作用 |
|---|---|---|
internalConfigurationAnnotationProcessor |
ConfigurationClassPostProcessor |
处理 Spring 配置类 |
internalAutowiredAnnotationProcessor |
AutowiredAnnotationBeanPostProcessor |
处理 @Autowired 和 @Value |
internalCommonAnnotationProcessor |
CommonAnnotationBeanPostProcessor |
处理 @PostConstruct 等 JSR-250 注解 |
internalEventListenerProcessor |
EventListenerMethodProcessor |
处理 @EventListener 标注的方法 |
这些对象本身也是容器中的 Bean,因此也可以通过依赖查找获取。不过,日常开发中通常不需要直接使用它们。
了解一下得了,面试里还没有遇到过这些问题。
手动注册的单例对象
除了让 Spring 根据 BeanDefinition 创建 Bean,也可以把一个已经创建好的对象直接注册到容器中:
1 | singletonBeanRegistry.registerSingleton("user", user); |
注册完成后,就可以通过 getBean("user") 查找到这个对象。由于对象是在注册前就已经创建好的,Spring 不负责它的创建过程,也不会完整管理它的生命周期。
Spring 内置的单例对象
Spring 也会向容器中注册一些常用的单例对象,例如:
| Bean 名称 | Bean 实例 | 作用 |
|---|---|---|
environment |
Environment |
读取外部化配置和 Profiles |
systemProperties |
java.util.Properties |
读取 Java 系统属性 |
systemEnvironment |
java.util.Map |
读取操作系统环境变量 |
messageSource |
MessageSource |
提供国际化消息 |
applicationEventMulticaster |
ApplicationEventMulticaster |
发布 Spring 应用事件 |
因此,像 Environment 这样的对象,也可以直接从 Spring 容器中查找:
1 | Environment environment = applicationContext.getBean(Environment.class); |
Spring BeanDefinition 作为依赖来源
- 元数据:
BeanDefinition - 注册:
BeanDefinitionRegistry#registerBeanDefinition - 类型:延迟和非延迟
- 顺序:Bean 生命周期顺序按照注册顺序
单例对象作为依赖来源
- 要素
- 来源:外部普通 Java 对象(不一定是 POJO)
- 注册:
SingletonBeanRegistry#registerSingleton
- 限制
- 无生命周期管理
- 无法实现延迟初始化 Bean
非 Spring 对象容器管理对象作为依赖来源
- 要素
- 注册:
ConfigurableListableBeanFactory#registerResolvableDependency
- 注册:
- 限制
- 无生命周期管理
- 无法实现延迟初始化 Bean
- 无法通过依赖查找
外部化配置作为依赖来源
- 要素
- 类型:非常规 Spring 对象依赖来源
- 限制
- 无生命周期管理
- 无法实现延迟初始化 Bean
- 无法通过依赖查找
问题
注入和查找的依赖来源是否相同?
- 否,依赖查找的来源仅限于 Spring
BeanDefinition以及单例对象,而依赖注入的来源还包括 Resolvable Dependency 以及@Value所标注的外部化配置
单例对象能在 IoC 容器启动后注册吗?
- 可以的,单例对象的注册与
BeanDefinition不同,BeanDefinition会被ConfigurableListableBeanFactory#freezeConfiguration()方法影响,从而冻结注册,单例对象则没有这个限制。
Spring 依赖注入的来源有哪些?
- Spring
BeanDefinition - 单例对象
- Resolvable Dependency
@Value外部化配置
参考资料
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 coder-xuyong!
评论





