spring循环依赖的解决方案
Spring IOC循环依赖解决方案分析
这里Spring主要用了三层缓存来完成对循环依赖的实现。
下面的属性来源于DefaultSingletonBeanRegistry类
/** Cache of singleton objects: bean name --> bean instance */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(64);
/** Cache of singleton factories: bean name --> ObjectFactory */
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<String, ObjectFactory<?>>(16);
/** Cache of early singleton objects: bean name --> bean instance */
private final Map<String, Object> earlySingletonObjects = new HashMap<String, Object>(16);
当获取一个实例对象的时候,会调用此方法
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return (singletonObject != NULL_OBJECT ? singletonObject : null);
}
先从singletonObjects 找,如果找不到会从earlySingletonObjects中查询,再找不到去singletonFactories 中去查询,如果找到的话会放在earlySingletonObjects中,那么问题来了,singletonFactories的对象是什么时候放进去的。
研究Spring构造类实例的时候,通过AbstractAutowireCapableBeanFactory的doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args)方法中调用addSingletonFactory方法将A类曝光到singletonFactories中。
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);
}
}
}
Spring注入一个类的大体步骤分为两部分,一是先完成对类的构造工作,二是会对类的属性进行设置和填充
那么关于的单例的类实例之间的互相引用的问题就清晰了
假设A对象有个属性B 则在A初始化的时候,构造完成之后就放在了singletonFactories中,当发现去set属性的时候发现B没有初始化,于是接着初始化B,设置属性的时候在缓存中都可以拿到各自对象的引用,所以不会有循环依赖的报错
网友评论