您的位置:首页 > 编程语言 > Java开发

Spring的三层缓存,解决循环依赖问题

2019-03-20 17:52 1176 查看

Spring中的BEAN可以通过Setter或者构造器的方式注入属性,那么如果有两个相互引用的类

class A{

B b;

...get

...set

},

class B{

A a;

...get

...set

},

基于Spring的单例模式的话,这两个单例对象需要相互引用,那么这个时候Spring又如何适应这种循环依赖呢,平常的直接存BeanFactory中读取出Bean的方法当然不能使用了,那么平时有做算法题习惯的人,就知道我们需要先使用Map进行暂时存储。而Spring也使用类似的方法。

 

接下来要上Spring源码了

 

[code]   //DefaultSingletonBeanRegistry中

@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
Object singletonObject = this.singletonObjects.get(beanName);
//判断当前Bean是否存在且是正在创建的单例Bean,使用三级缓存
if (singletonObject == null && this.isSingletonCurrentlyInCreation(beanName)) {
Map var4 = this.singletonObjects;
synchronized(this.singletonObjects) {
singletonObject = this.earlySingletonObjects.get(beanName);
//二级缓存
if (singletonObject == null && allowEarlyReference) {
ObjectFactory<?> singletonFactory = (ObjectFactory)this.singletonFactories.get(beanName);
//三级缓存
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}

return singletonObject;
}

1.singletonObjects

2.earlySingletonObjects

3.singletonFactory

 

 

简单来说,使用三级缓存判断是否存在当前Bean,如果存在,则逐层返回,

那么就有两个问题,三级缓存是什么时候设置的,这三种缓存又有什么区别?

 

接下来看看createBean的方法

[code]	protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
throws BeanCreationException {
// 先从factoryBeanInstanceCache缓存中尝试获取
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
//如果缓存中不存在,则根据bean对应的策略创建新的实例,如:工厂方法、构造器自动注入、简单初始化
if (instanceWrapper == null) {
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
final Object bean = instanceWrapper.getWrappedInstance();
Class<?> beanType = instanceWrapper.getWrappedClass();
if (beanType != NullBean.class) {
mbd.resolvedTargetType = beanType;
}

// 应用MergedBeanDefinitionPostProcessor 后处理器,合并bean的定义信息
// Autowire等注解信息就是在这一步完成预解析,并且将注解需要的信息放入缓存
synchronized (mbd.postProcessingLock) {
if (!mbd.postProcessed) {
try {
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
}
//catch..
mbd.postProcessed = true;
}
}

// 是否需要提前曝光=单例&允许循环依赖&bean正在创建中
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
//为了避免循环依赖,在bean初始化完成前,就将创建bean实例的ObjectFactory放入工厂缓存(singletonFactories)
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}

// 对bean属性进行填充,注入bean中的属性,会递归初始化依赖的bean
Object exposedObject = bean;
try {
populateBean(beanName, mbd, instanceWrapper);
//调用初始化方法,比如init-method、注入Aware对象、应用后处理器
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
//catch

if (earlySingletonExposure) {
//从提前曝光的bean缓存中查询bean,目的是验证是否有循环依赖存在
//如果存在循环依赖,也就是说该bean已经被其他bean递归加载过,放入了提早曝光的bean缓存中
Object earlySingletonReference = getSingleton(beanName, false);
//只有检测到循环依赖的情况下,earlySingletonReference才不会为null
if (earlySingletonReference != null) {
//如果exposedObject没有在 initializeBean 初始化方法中改变,也就是没有被增强
if (exposedObject == bean) {
exposedObject = earlySingletonReference;
}
else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
//检测依赖
String[] dependentBeans = getDependentBeans(beanName);
Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
for (String dependentBean : dependentBeans) {
if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
actualDependentBeans.add(dependentBean);
}
}
//因为bean创建后,其依赖的bean一定也是已经创建的
//如果actualDependentBeans不为空,则表示依赖的bean并没有被创建完,即存在循环依赖
if (!actualDependentBeans.isEmpty()) {
throw new BeanCurrentlyInCreationException("...");
}
}
}
}

// 根据scope注册bean
try {
registerDisposableBeanIfNecessary(beanName, bean, mbd);
}
//catch。。。
return exposedObject;
//引用https://blog.csdn.net/finalcola/article/details/81449140

 

 

第三层缓存-》保存工厂方法

第二层缓存-》保存未完全装载的方法

第一层-》完全体

 

那么工厂方法又是什么时候创建的呢?

[code]public abstract class AbstractBeanFactory implements ConfigurableBeanFactory{
/**
* 充当了Bean实例的缓存,实现方式和单例注册表相同
*/
private final Map singletonCache=new HashMap();
public Object getBean(String name)throws BeansException{
return getBean(name,null,null);
}
...
public Object getBean(String name,Class requiredType,Object[] args)throws BeansException{
//对传入的Bean name稍做处理,防止传入的Bean name名有非法字符(或则做转码)
String beanName=transformedBeanName(name);
Object bean=null;
//手工检测单例注册表
Object sharedInstance=null;
//使用了代码锁定同步块,原理和同步方法相似,但是这种写法效率更高
synchronized(this.singletonCache){
sharedInstance=this.singletonCache.get(beanName);
}
if(sharedInstance!=null){
...
//返回合适的缓存Bean实例
bean=getObjectForSharedInstance(name,sharedInstance);
}else{
...
//取得Bean的定义
RootBeanDefinition mergedBeanDefinition=getMergedBeanDefinition(beanName,false);
...
//根据Bean定义判断,此判断依据通常来自于组件配置文件的单例属性开关
//<bean id="date" class="java.util.Date" scope="singleton"/>
//如果是单例,做如下处理
if(mergedBeanDefinition.isSingleton()){
synchronized(this.singletonCache){
//再次检测单例注册表
sharedInstance=this.singletonCache.get(beanName);
if(sharedInstance==null){
...
try {
//真正创建Bean实例
sharedInstance=createBean(beanName,mergedBeanDefinition,args);
//向单例注册表注册Bean实例
addSingleton(beanName,sharedInstance);
}catch (Exception ex) {
...
}finally{
...
}
}
}
bean=getObjectForSharedInstance(name,sharedInstance);
}
//如果是非单例,即prototpye,每次都要新创建一个Bean实例
//<bean id="date" class="java.util.Date" scope="prototype"/>
else{
bean=createBean(beanName,mergedBeanDefinition,args);
}
}
...
return bean;
}
}

 

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: