Spring IoC 依赖来源
本章节参考模块:dependency-source
一、依赖查找的来源
-
查找来源
来源 配置源数据 Spring BeanDefinition @Bean public User user(){} BeanDefinitionBuilder 单例来源 Api实现 -
Spring 内建BeanDefinition
Bean名称 Bean实例 使用场景 org.springframework.context.annotation.internalConfigurationAnnotationProcessor ConfigurationClassPostProcessor对象 处理Spring配置类 org.springframework.context.annotation.internalAutowiredAnnotationProcessor AutowiredAnnotationBeanPostProcessor对象 处理@Autowired以及@Value注解 org.springframework.context.annotation.internalCommonAnnotationProcessor CommonAnnotationBeanPostProcessor对象 (条件激活)处理JSR-250注解,如@PostCustruct注解 org.springframework.context.event.internalEventListenerProcessor EventListenerMethodProcessor对象 处理标注@EventListener的Spring事件监听方法 -
Bean内建单例对象
Bean名称 | Bean实例 | 使用场景 |
---|---|---|
environment | Environment对象 | 外部化配置以及Profiles |
systemProperties | java.util.Properties对象 | Java 系统属性 |
systemEnvironment | java.util.Map对象 | 操作系纺环境变量 |
messageSource | MessageSource对象 | 国际化文案 |
LifecycleProcessor | LifecycleProcessor对象 | Lifecycle Bean处理器 |
ApplicationEnventMutlicaster | ApplicationEnventMutlicaster对象 | Spring事件广播器 |
主要由org.springframework.context.annotation.AnnotationConfigUtils#registerAnnotationConfigProcessors(org.springframework.beans.factory.support.BeanDefinitionRegistry, java.lang.Object) 加载
二、 依赖注入的来源
- 注入来源
来源 | 配置源数据 |
---|---|
Spring BeanDefinition | |
@Bean public User user(){} | |
BeanDefinitionBuilder | |
单例来源 | Api实现 |
非Spring管理对象 |
org.springframework.context.support.AbstractApplicationContext#refresh#prepareBeanFactory
applicationContext上下文启动时,默认注入了4种Bean(两个对象:beanFactory以及this)
三、 Spring容器管理和游离对象
- 依赖对象
来源 | Spring Bean对象 | 生命周期对象 | 配置元信息 | 使用场景 |
---|---|---|---|---|
Spring BeanDefintion | 是 | 是 | 有 | 依赖查找、依赖注入 |
单体对象 | 是 | 否 | 无 | 依赖查找、依赖注入 |
ResolvableDependency | 否 | 否 | 无 | 依赖注入 |
四、 Spring BeanDefinition作为来源对象
- 要素
- 元数据:BeanDefinition
- 注册:BeanDefinitionRegistry#registerBeanDefintion
- 类型:延迟和非延迟
- 顺序:Bean生命周期顺序按照注册顺序
阅读源码:org.springframework.beans.factory.support.DefaultListableBeanFactory#registerBeanDefinition
BeanDefinitionRegistry 为了确保注册顺序,冗余一个字段beanDefintionNames帮忙我们在未来的初始化过程中按照顺序加载
五、单例对象作为依赖来源
-
要素
- 来源:外部普通Java对象(不一定是POJO)
- 注册:SingletonBeanRegistry#registerBeginDefinition
- 限制
- 无生命周期
- 无法实现延迟初始化Bean
之前代码中演示:com.forjson.spring.bean.definition.SingletonBeanRegisterDemo 注册外部类
AbstractBeanFactory#getBean时,会优先从SingletonBeanRegistry中查找,若查找到Bean,则直接返回
getBean源码:org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean
// Eagerly check singleton cache for manually registered singletons. Object sharedInstance = getSingleton(beanName); if (sharedInstance != null && args == null) { if (logger.isTraceEnabled()) { if (isSingletonCurrentlyInCreation(beanName)) { logger.trace("Returning eagerly cached instance of singleton bean '" + beanName + "' that is not fully initialized yet - a consequence of a circular reference"); } else { logger.trace("Returning cached instance of singleton bean '" + beanName + "'"); } } bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
六、非Spring容器管理对象作为来源对象
-
要素
- 注册:ConfigurableListableBeanFactory#registerResolvableDependency
- 限制
- 无生命周期管理
- 无法实现延迟初始化Bean
- 无法通过依赖查找
代码演示: com.forjson.spring.dependency.source.ResolvableDependencySourceDemo
@Autowired
private String value;
@PostConstruct
public void init() {
System.out.println(value);
}
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
//1.注册当前类为 配置类(Configuration Class)
applicationContext.register(ResolvableDependencySourceDemo.class);
/**
* A 解决方案: 添加BeanFactoryPostProcessor
* 原因:AbstractApplicationContext#refresh() 应用上下文启动时,会先执行BeanFactoryPostProcessor,再执行init()方法
* 故,在init调用之前,执行我们需要做的操作即可。
*/
applicationContext.addBeanFactoryPostProcessor(beanFactory -> {
beanFactory.registerResolvableDependency(String.class, "Hello,World!");
});
//2. 启动应用上下文
applicationContext.refresh();
/**
* Question:
* 下面两行代码会抛异常:org.springframework.beans.factory.NoSuchBeanDefinitionException
* 原因是因为Spring生命周期初始化执行完成,才会执行该代码。
* 在@PostConstruct 执行初始化方法时,需要获取到该注入类型,但此时该类型还没有注入,所以会抛异常.
* 解决方案:在init之前,将该String类型,注册.见A代码处
*/
// ConfigurableListableBeanFactory beanFactory = applicationContext.getBeanFactory();
// beanFactory.registerResolvableDependency(String.class, "Hello,World!");
//3.关闭应用上下文
applicationContext.close();
}
七、外部化配置作为依赖来源
-
要素
- 类型:非常规Spring 对象依赖来源
-
限制
- 无生命周期管理
- 无法实现延迟初始化Bean
- 无法通过依赖查找
参考代码: ExternalConfigurationDependencySourceDemo
八、面试题精选
-
注入和查找的依赖来源是否相同?
- 否。依赖查找的来源仅限于BeanDefinition以及单例对象,而依赖注入的来源还包括Resolvable Dependency以及@Value所标注的外部化配置
-
单例对象能在IoC容器启动后注册吗?
- 可以的。单例对象的注册与BeanDefinition注册不同,BeanDefinition会被ConfigurableListableBeanFactory#freezeConfiguration()方法影响,从而冻结注册,单例对象则没有这个限制。
ConfigurableListableBeanFactory#freezeConfiguration() 方法会影响DefaultListableBeanFactory#getBeanDefinitionNames
-
Spring依赖注入来源有哪些?
- Spring BeanDefinition
- 单例对象
- Resolvable Dependency
- @Value