一、回顾下 bean的创建过程
二、构造器注入的循环依赖
1、先创建两个循环依赖的类
public class ServiceA{
private ServiceB b;
// 构造方法
public ServiceA(ServiceB b){
this.b = b;
}
}
public class ServiceB{
private ServiceA a;
// 构造方法
public ServiceB(ServiceA a){
this.a = a;
}
}
2、然后 main 函数中调用,发现该依赖无法解决
new ServiceA(new ServiceB(new ServiceA(.......)))
三、Set 方式注入
设置两个循环依赖的类
public class ServiceBB{
private ServiceAA aa;
// set方法
public void setServiceAA(ServiceAA serviceAA){
this.aa = serviceAA;
}
}
public class ServiceAA{
private ServiceBB bb;
// set方法
public void setServiceBB(ServiceBB servicebb){
this.bb = servicebb;
}
}
然后main函数调用,set可以解决循环调用,因为new的时候是调用一个空的无参构造方法,此时并没有依赖。
原因是 spring 内部用到了 三级缓存 解决这个问题。
public class test{
public static void main(String[] args){
ServiceAA a = new ServiceAA();
ServiceBB b = new ServiceBB();
b.setServiceAA(a);
a.setServiceBB(b);
}
}
四、三级缓存
1、简单介绍
在实例化的过程中,将处于半成品的对象全部都放到缓存中,方便后续来进行调用,只要有了当前对象的引用地址,那么后续来进行赋值也可以。 半成品对象放到了map缓存结构中,成品对象要不要也放到某一个map中,能否把成品和半成品对象放到一起?如果放到一起,就会导致获取对象的时候获取到半成品对象,值为空。 为了将成品和半成品对象完全的区分开,那么可以创建两个缓存对象,即两个map,当然还有第三个map,这就是三级缓存。 一级:成品对象 二级:半成品对象 三级:?为什么需要这个三级缓存
2、三级缓存代码位置
public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {
/** Cache of singleton objects: bean name to bean instance. */
// 一级
// 单例池:存放了已经经历了完整生命周期的bean对象,即已经初始化好的bean,也就是所谓的单例池
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
/** Cache of singleton factories: bean name to ObjectFactory. */
// 三级 存放可以生成Bean的工厂,存放FactoryBean。假如A类实现了FactoryBean,那么依赖注入的时候不是A类,而是A类产生的Bean
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
/** Cache of early singleton objects: bean name to bean instance. */
// 二级
// 存放早期暴露出来的bean对象,Bean的生命周期未结束(属性还没有填充完整),即存放的是实例化一半的bean
private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16);
DefaultListableBeanFactory#preInstantiateSingletons —》 getbean—>doGetBean—>如下代码
Object singletonObject = this.singletonObjects.get(beanName);
// 如果一级缓存为空,则执行如下代码
if (singletonObject == null) {
继续走下去,从传进的 singletonFactory 中获取 getObject
我们看看传进来的 singletonFactory 是什么,如下,是个 Lambda表达式,进入 createBean
—》doCreateBean
然后看到这个方法里面调用了 addSingletonFactory 方法。
addSingletonFactory 方法如下
/**
* Add the given singleton factory for building the specified singleton
* if necessary.
* <p>To be called for eager registration of singletons, e.g. to be able to
* resolve circular references.
* @param beanName the name of the bean
* @param singletonFactory the factory for the singleton object
*/
protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(singletonFactory, "Singleton factory must not be null");
// 使用 singletonOjects 加锁,保证线程安全
synchronized (this.singletonObjects) {
//如果一级单例对象的高速缓存map【bean名称->bean实例】没有beanName的对象
if (!this.singletonObjects.containsKey(beanName)) {
// 将 beanname,singletonFactory 放到单例工厂的缓存(三级)【bean名称 - ObjectFactory】
this.singletonFactories.put(beanName, singletonFactory);
// 将二级单例对象的高速缓存【bean名称->bean实例】释放beanName的相关缓存
this.earlySingletonObjects.remove(beanName);
// 将 beanName 添加到已注册的单例集合中
this.registeredSingletons.add(beanName);
}
}
}
(populateBean)接着进行bean属性的填充,或者可能依赖于其他bean 的属性的,则会递归初始化依赖的bean
populateBean—》applyPropertyValues—》 valueResolver.resolveValueIfNecessary—》resolveReference—》 this.beanFactory.getBean —》doGetBean —》Object sharedInstance = getSingleton(beanName);
�注意:这次的 getSingleton,和上面的 getSingleton不一样,这个的没有 lambda方法,
@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// Quick check for existing instance without full singleton lock
Object singletonObject = this.singletonObjects.get(beanName);
// 正在创建中
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
// 从二级缓存里面取
singletonObject = this.earlySingletonObjects.get(beanName);
// 二级缓存中没有,并且允许创建二级缓存
if (singletonObject == null && allowEarlyReference) {
// 锁定全局变量进行处理
synchronized (this.singletonObjects) {
// Consistent creation of early reference within full singleton lock
singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null) {
// 当某些方法需要提前初始化的时候则会调用 addSingletonFactory方法将对应的ObjectFactory初始化策略存储在singletonfactories里面
// 三级缓存中取
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
// 如果存在单例工厂,则通过工厂创建一个单例对象
singletonObject = singletonFactory.getObject();
// 记录在缓存中,二级缓存和三级缓存的对象不能同时存在
this.earlySingletonObjects.put(beanName, singletonObject);
// 移除三级缓存
this.singletonFactories.remove(beanName);
}
}
}
}
}
}
return singletonObject;
}
�。。。。。。。有空自己debug吧
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);
}
}
五、疑问
1、三级缓存汇总分别保存的是什么对象
1、成品对象 2、半成品对象 3、lambda表达式
2、如果只使用1级缓存行不行?
不行,因为成品和半成品对象会放到一起,在进行对象获取的时候有可能会获取到半成品对象,这样的对象是没办法使用的。
3、如果只有二级缓存,将三级缓存去掉 行不行?
getSingleton、doCreateBean 中用到了二级缓存 只有二级缓存的时候,也可以解决循环依赖问题。
但是AOP就不能用了。会报错 this mean that said other beans do not use the final version of the bean ,没有使用最终版本的bean对象
4、三级缓存存在到底是干什么用的?
如果一个对象需要被代理,生成代理对象,那么这个对象需要预先生产非代理对象吗? 需要
三级缓存到底干了什么? lamdba.getEarlyBeanReference(),只要搞清楚这个方法的具体执行逻辑即可。 当前方法中,有可能会用代理对象替换非代理对象,如果没有三级缓存的话,那么就可能无法得到代理对象,即在整个容器中,包含了同名对象的代理对象和非代理对象,这是不行的。 容器中,对象都是单例的,意味着根据名称只能取到一个对象的值,如果没有三级缓存,那这个代理对象就有可能存放在二级缓存中,那就可能冲突了。所以在三级缓存中完成了代理对象替换非代理对象的工作,确定返回的是唯一对象。 所以三级缓存是为了解决在 aop 代理过程中产生的循环依赖问题,如果没有 aop的话,二级缓存足以。
上图中最后返回的代理对象,会被放到三级缓存中去。