Spring IOC原理补充说明原理补充说明(循环依赖、循环依赖、Bean作用域等作用域等)
主要介绍了Spring IOC原理补充说明(循环依赖、Bean作用域等),具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
前言前言
通过之前的几篇文章将Spring基于XML配置的IOC原理分析完成,但其中还有一些比较重要的细节没有分析总结,比如循环依赖的解决、作用域的实现原理、BeanPostProcessor的执行时机以及
SpringBoot零配置实现原理(@ComponentScan、@Import、@ImportSource、@Bean注解的使用和解析)等等。下面就先来看看循环依赖是怎么解决的,在此之前一定要熟悉整个Bean的实例化过
程,本篇只会贴出关键性代码。
正文正文
循环依赖循环依赖
首先来看几个问题:
什么是循环依赖?什么是循环依赖?
在熟悉了Bean实例化原理后,你会怎么解决循环依赖的问题?
Spring怎么解决循环依赖?有哪些循环依赖可以被解决?哪些又不能?
什么是循环依赖?什么是循环依赖?
这个概念很容易理解,简单说就是两个类相互依赖,类似线程死锁的问题,也就是当创建A对象时需要注入B的依赖对象,但B同时也依赖A,那到底该先创建A还是先创建B呢?
Spring是如何解决循环依赖的?是如何解决循环依赖的?
探究Spring的解决方法之前,我们首先得搞清楚Spring Bean有几种依赖注入的方式:
通过构造函数通过构造函数
通过属性通过属性
通过方法(不一定是setter方法,只要在方法上加上了@Autowired,都会进行依赖注入)
其次,Spring作用域有singleton、prototype、request、session等等,但在非单例模式下发生循环依赖是会直接抛出异常的,下面这个代码不知道你还有没有印象,在AbstractBeanFactory.doGetBean中
有这个判断:
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
为什么这么设计呢?反过来想,如果不这么设计,你怎么知道循环依赖到底是依赖的哪个对象呢?搞清楚了这个再来看哪些依赖注入的方式发生循环依赖是可以解决,而那些又不能。结论是构造函数方
式没办法解决循环依赖,其它两种都可以。
我们先来看看为什么通过属性注入和方法注入可以解决。回忆一下Bean的实例化过程:
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
throws BeanCreationException {
// Instantiate the bean.
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
//创建实例
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
final Object bean = instanceWrapper.getWrappedInstance();
Class<?> beanType = instanceWrapper.getWrappedClass();
if (beanType != NullBean.class) {
mbd.resolvedTargetType = beanType;
}
// Allow post-processors to modify the merged bean definition.
synchronized (mbd.postProcessingLock) {
if (!mbd.postProcessed) {
try {
// Bean实例化完成后收集类中的注解(@PostConstruct,@PreDestroy,@Resource, @Autowired,@Value)
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Post-processing of merged bean definition failed", ex);
}
mbd.postProcessed = true;
}
}
// Eagerly cache singletons to be able to resolve circular references
// even when triggered by lifecycle interfaces like BeanFactoryAware.
// 单例bean提前暴露
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
if (logger.isTraceEnabled()) {
logger.trace("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
//这里着重理解,对理解循环依赖帮助非常大,重要程度 5 添加三级缓存
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
// Initialize the bean instance.
Object exposedObject = bean;
try {
//ioc di,依赖注入的核心方法,该方法必须看
populateBean(beanName, mbd, instanceWrapper);
//bean 实例化+ioc依赖注入完以后的调用,非常重要
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
catch (Throwable ex) {
if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
throw (BeanCreationException) ex;
}
else {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
}
}
if (earlySingletonExposure) {
Object earlySingletonReference = getSingleton(beanName, false);
if (earlySingletonReference != null) {
if (exposedObject == bean) {
exposedObject = earlySingletonReference;
}
else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
String[] dependentBeans = getDependentBeans(beanName);
Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);