开心消消乐官方网站开发公司,软件开发工程师的发展前景,营销型网站建设的选择方式,wordpress 短信 插件Spring如何解决循环引用的问题
关于循环引用#xff0c;首先说一个结论#xff1a;
Spring能够解决的情况为#xff1a;两个对象都是单实例、且通过set方法进行注入。
两个对象都是单实例#xff0c;通过构造方法进行注入#xff0c;Spring不能进行循环引用问题#x…Spring如何解决循环引用的问题
关于循环引用首先说一个结论
Spring能够解决的情况为两个对象都是单实例、且通过set方法进行注入。
两个对象都是单实例通过构造方法进行注入Spring不能进行循环引用问题
两个对象都是多实例的情况下不管是set注入还是构造注入都不能解决Spring循环引用问题。
循环引用问题介绍
循环引用问题即
有AB两个类A类中有B类型的成员变量b、B类中有A类型的成员变量a。创建a的过程需要b创建b的过程又需要a 循环引用问题分析
请看如下流程
调用getBean(“a”)来获取a对象;先调用getSingleton(“a”)来尝试获取a但是获取不到需要调用doCreateBean()来创建aa的b属性是null需要填充b属性调用getBean(“b”)来获取b对象先调用getSingleton(“b”)来尝试获取b但是获取不到需要调用doCreateBean()来创建bb的a属性是null需要填充a属性又需要要调用getBean(“a”)来获取a。
这时getBean(“a”)可以获取到吗?如果能获取到是在哪里获取的如果获取不到又会有什么问题呢
我们首先看下getSingleton()源码 addSingleton方法如下图 如此可以看到在进行实例化、属性填充、初始化都完成后才会放到singletonObjects中。
那getSingleton()方法就获取不到a只能再去创建a对象了吗当然不是如果再去创建aa就不是单例的呢。
所以这就需要**没有创建完全的a也要存储起来。**但是并没有存储到singletonObjects中因为singletonObjects是存储例化、属性填充、初始化都完成后的对象。
Spring又为我们定义了两个存储的位置earlySingletonObjects、singletonFactories。
那什么时候将未创建完全的对象存储起来呢
这我们应该在实例化对象完成后填充属性前的代码查找。可以看到如下代码 addSingletonFactory(beanName, () - getEarlyBeanReference(beanName, mbd, bean));addSingletonFactory方法源码如下
protected void addSingletonFactory(String beanName, ObjectFactory ? singletonFactory) {Assert.notNull(singletonFactory, Singleton factory must not be null);synchronized(this.singletonObjects) {if(!this.singletonObjects.containsKey(beanName)) {this.singletonFactories.put(beanName, singletonFactory);this.earlySingletonObjects.remove(beanName);this.registeredSingletons.add(beanName);}}
}实例化后会把创建非完全体对象的工厂放到singletonFactories里这个工厂就是lambda表达式() - getEarlyBeanReference(beanName, mbd, bean)调用的getEarlyBeanReference(beanName, mbd, bean)方法。 addSingletonFactory还会把earlySingletonObjects、registeredSingletons中的对象删除。
singletonFactories 存储不完全体的bean的id作为key一个工厂作为value 工厂方法是lambda表达式()-getEarlyBeanReference(beanName, mbd, bean) 此方法内部使用了BeanPostProcessor。
singletonFactories为什么不存储未完全体的a而存储一个工厂方法呢
这意味着他会处理一些复杂功能。 上述介绍的循环引用的问题是最简单的情况。还有一些复杂情况。
如果A需要做AOP需要为A做代理呢或者B也要做代理呢 代理是在初始化阶段使用BeanPostProcessor的postProcessAfterInitialization()方法来做的。 singletonFactories存工厂的原因
为b填充属性a时需要获取到不完全体的a为b赋值 并且如果A需要做代理 而代理是在BeanPostProcessor中的postProcessAfterInitialization()方法做的 所以singletonFactories存储的是一个工厂里面的方法是用BeanPostProcessor中的 这样就无需在a初始化的过程中创建代理了可以把a的代理提前创建出来。
那在A创建过程中是否还要创建代理呢————不会。
在上面提前创建a的代理完成后会将代理对象放到代理缓存中在a初始化创建代理时直接从代理缓存中拿就可以了。
站在b的角度讲现在b的属性填充完成了后面就是初始化了在初始化过程中就可以走正常的代理过程了。
a在填充属性时就可以填充b的代理了就可以走初始化了初始化过程中的代理从代理缓存获取就可以了。
为b填充a代理对象分析
doGetBean()中的getSingleton方法 在为b填充a的代理时singletonFactory.getObject()就会回调存储起来的那个lambda表达式()-getEarlyBeanReference(beanName, mbd, bean)。 会把a的代理获取出来
然后把a的代理放到earlySingletonObjects中
把存储的a工厂的lambda表达式从singletonFactories中移除。
b初始化完成后b就是完全体了调用addSingleton方法就会把b存储到singletonObjects中了。
等a再初始化完成就是完全体了。
这样就解决了循环引用问题。