欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 文旅 > 艺术 > Bean创建过程中调的方法

Bean创建过程中调的方法

2026/5/4 16:50:30 来源:https://blog.csdn.net/jupiter_888/article/details/144670958  浏览:    关键词:Bean创建过程中调的方法

在AbstractBeanFactory中
getSingleton方法中,
调beforeSingletonCreation方法,
将beanName添加到defaultSingletonBeanRegistry的成员变量singletonCurrentlyInCreation集合中。
然后调singletonFactory.getObject方法,调到匿名beanFactory实例,

AbstractBeanFactory
getBean
doGetBean
{匿名beanFactory实例:
lambda.doGetBean {
AbstractAutowireCapableBeanFactory.createBean
}
}

创建过程:【

AbstractAutowireCapableBeanFactory.doCreateBean

// Eagerly cache singletons to be able to resolve circular references// even when triggered by lifecycle interfaces like BeanFactoryAware.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");}// 加入三级缓存,没有循环依赖也会执行这一步addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));}// Initialize the bean instance.Object exposedObject = bean;try {populateBean(beanName, mbd, instanceWrapper);exposedObject = initializeBean(beanName, exposedObject, mbd);}
 createBeanInstanceinstantiateBeanSimpleInstantiationStrategy.instantiateBeanUtils.instantiateClass

DefaultSingletonBeanRegistry.addSingleton方法
将已创建的Bean加入到容器。

三级缓存中的创建的Bean的移动

/** Cache of singleton objects: bean name to bean instance. */private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);/** Cache of singleton factories: bean name to ObjectFactory. */private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);/** Cache of early singleton objects: bean name to bean instance. */private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);

在不存在循环依赖的时候, Bean创建过程的最后一步从singletonFactories中移除,添加到singletonObjects

	/*** Add the given singleton object to the singleton cache of this factory.* <p>To be called for eager registration of singletons.* @param beanName the name of the bean* @param singletonObject the singleton object*/protected void addSingleton(String beanName, Object singletonObject) {synchronized (this.singletonObjects) {this.singletonObjects.put(beanName, singletonObject);this.singletonFactories.remove(beanName);this.earlySingletonObjects.remove(beanName);this.registeredSingletons.add(beanName);}}

存在循环依赖的时候,先放在三级缓存singletonFactories,
当被其他Bean调用的之后从singletonFactories移除,增加到二级缓存earlySingletonObjects,
最后从earlySingletonObjects移除,增加到三级缓存singletonObjects。

解决循环依赖的过程,主要用到了singletonFactories,不要earlySingletonObjects行不行呢?

在Spring解决循环依赖的过程中,singletonFactoriesearlySingletonObjects都起着重要作用,通常不能完全不用earlySingletonObjects,以下是具体分析:

singletonFactories的作用

  • 存储对象工厂singletonFactories是一个ObjectFactory类型的三级缓存,用于存储创建单例Bean的工厂对象。当一个Bean正在创建过程中,还未完全初始化完成时,会将其对应的对象工厂放入该缓存中。
  • 生成早期引用:通过调用对象工厂的getObject方法,可以获取到Bean的早期引用。这个早期引用可以在其他Bean依赖该Bean时进行注入,从而解决循环依赖问题。

earlySingletonObjects的作用

  • 存储早期Bean实例earlySingletonObjects也是一个用于解决循环依赖的缓存,它存储的是已经创建但还未完全初始化的Bean实例的早期引用。当从singletonFactories中获取到对象工厂并调用getObject方法生成早期引用后,会将这个早期引用放入earlySingletonObjects缓存中。
  • 避免重复创建:在后续的依赖注入过程中,如果再次需要获取该Bean的早期引用,会直接从earlySingletonObjects缓存中获取,而不需要再次调用对象工厂的getObject方法,提高了性能并避免了可能的重复创建问题。

不能完全不用earlySingletonObjects的原因

  • 性能优化:如果没有earlySingletonObjects缓存,每次获取Bean的早期引用都需要从singletonFactories中获取对象工厂并调用getObject方法,这会带来一定的性能开销。尤其是在存在复杂的循环依赖关系时,频繁的工厂调用会降低系统的运行效率。
  • 保证一致性:在多线程环境下,earlySingletonObjects可以保证在同一时间内,对于同一个正在创建的Bean,所有线程获取到的早期引用是一致的。如果没有这个缓存,可能会导致不同线程获取到不同的早期引用,从而引发数据不一致等问题。

虽然singletonFactories在解决循环依赖中是关键,但earlySingletonObjects也不可或缺,它们共同协作来高效、正确地处理循环依赖问题。

构造方法相互依赖是三级缓存机制都解决不了的循环依赖

class BeanA {private BeanB b;public BeanA(BeanB b) {this.b = b;}
}class BeanB {private BeanA a;public BeanB(BeanA a) {this.a = a;}
}

你所写的这种直接在构造函数中相互依赖注入的方式在Spring中是不行的,会导致循环依赖问题无法正常解决,原因如下:

Spring解决循环依赖的机制限制

  • Spring在处理循环依赖时,主要依靠三级缓存机制。当创建一个Bean时,会先将其早期引用放入缓存中,以便在其他Bean依赖它时可以获取到这个早期引用进行注入。但这种机制在构造函数相互依赖的情况下存在问题,因为在构造函数执行时,Bean还未完全创建完成,此时如果直接将未完成创建的Bean作为参数传递给另一个Bean的构造函数,就会导致依赖注入失败。

解决方案

使用@Lazy注解

可以在其中一个Bean的依赖注入处使用@Lazy注解,延迟该Bean的初始化,直到真正需要使用时才进行创建。例如:

import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;@Component
public class BeanA {private final BeanB b;public BeanA(@Lazy BeanB b) {this.b = b;}
}@Component
public class BeanB {private final BeanA a;public BeanB(BeanA a) {this.a = a;}
}

在上述代码中,BeanA的构造函数中注入BeanB时使用了@Lazy注解,这样BeanBBeanA构造函数被调用时不会立即创建,而是在第一次使用BeanB时才进行创建,从而避免了构造函数循环依赖的问题。

使用属性注入或方法注入

将依赖注入方式从构造函数注入改为属性注入或方法注入,这样可以让Spring在处理循环依赖时有更多的灵活性。例如:

import org.springframework.stereotype.Component;@Component
public class BeanA {private BeanB b;public void setB(BeanB b) {this.b = b;}
}@Component
public class BeanB {private BeanA a;public void setA(BeanA a) {this.a = a;}
}

然后在配置类中通过@Bean注解的方法来进行依赖注入的配置:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class AppConfig {@Beanpublic BeanA beanA() {return new BeanA();}@Beanpublic BeanB beanB() {return new BeanB();}@Beanpublic void configure(BeanA a, BeanB b) {a.setB(b);b.setA(a);}
}

在上述代码中,BeanABeanB使用了属性注入的方式,通过AppConfig配置类中的configure方法来手动完成依赖注入,避免了在构造函数中直接相互依赖的问题。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词