Spring IOC 依赖注入,循环依赖
1.、主要内容
2、注入流程
public void refresh() throws BeansException, IllegalStateException {
// 加锁防止在启动过程中出现其他线程抢占资源的情况
synchronized (this.startupShutdownMonitor) {
// 准备工作,记录启动时间
prepareRefresh();
// 加载配置信息到BeanFactory中,这一步仅仅将信息加载完成,并没有完成初始化
/**
* ClassPathXMLApplicationContext包含着BeanFactory所提供的一切特征,在这一步骤中将会复用
* BeanFactory中的配置文件读取解析及其他功能,这一步之后,ClassPathXmlApplicationContext
* 实际上就已经包含了BeanFactory所提供的功能,也就是可以进行Bean的提取等基础操作了。
*/
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
//对beanFactory进行各种功能填充
prepareBeanFactory(beanFactory);
try {
//子类覆盖方法做额外处理
postProcessBeanFactory(beanFactory);
//激活各种beanFactory处理器
invokeBeanFactoryPostProcessors(beanFactory);
//注册拦截Bean创建的Bean处理器,这里只是注册,真正的调用实在getBean时候
registerBeanPostProcessors(beanFactory);
//为上下文初始化Message源,即不同语言的消息体,国际化处理
initMessageSource();
//初始化应用消息广播器,并放入“applicationEventMulticaster”bean中
initApplicationEventMulticaster();
//留给子类来初始化其它的Bean
onRefresh();
//在所有注册的bean中查找Listener bean,注册到消息广播器中
registerListeners();
//初始化剩下的单实例(非惰性的)(bean加载)
finishBeanFactoryInitialization(beanFactory);
//完成刷新过程,通知生命周期处理器lifecycleProcessor刷新过程,同时发出ContextRefreshEvent通知别人
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// Destroy already created singletons to avoid dangling resources.
destroyBeans();
// Reset 'active' flag.
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
}
}
3、循环依赖问题
循环依赖:一个或多个对象实例之间存在直接或间接的依赖关系,这种依赖关系构成了构成一个环形调用。
第一种情况:自己依赖自己的直接依赖
第二种情况:两个对象之间的直接依赖
第三种情况:多个对象之间的间接依赖
3.1 循环依赖的N种场景
spring中出现循环依赖主要有以下场景:
3.2 spring解决循环依赖的方法
spring内部有三级缓存:
- singletonObjects 一级缓存,用于保存实例化、注入、初始化完成的bean实例
- earlySingletonObjects 二级缓存,用于保存实例化完成的bean实例
- singletonFactories 三级缓存,用于保存bean创建工厂,以便于后面扩展有机会创建代理对象
spring是如何解决循环依赖的:
三层缓存只能解决单例模式下的setter注入
- 多例setter注入,不会被提前初始化bean,只有当引用的时候才会创建
- 构筑器注入,类初始化的时就进行了构造器的创建,该步骤无法分离,所以无法使用三级缓存
- DependsOn循环依赖,比如我们需要在实例化Bean A之前,先实例化Bean B,这个时候就可以使用
@DependsOn
注解。优先级问题,导致死锁
注:springboot中的实例默认是单例的,如@Controller、@Service、@Component、@Repository和@Bean