循环依赖就是class A依赖class B,同时class B依赖class A,更多的class互相依赖类似。
显然scope为prototype的bean是无法解决的,每次都要new新的bean,还要互相依赖,就像死锁一样。
只提供一个属性注入的构造器同样无法解决循环依赖,原因同prototype,注意这里指A只有一个构造方法,构造方法参数为B,这样是无法实例化的。如果A还提供了空的构造方法,那是可以完成实例化的。
so,spring只解决singleton bean的循环依赖,那是怎么解决的呢?显然问题出在实例化的时候,如果先实例化,然后再进行属性注入是可以的。
比如,可以先实例化A和B,然后在A中需要B时,通过getBean的方式获取B,同理在B中使用getBean获取A。spring也是如此,提前曝光bean,然后装配。
@Service
public class ServiceA {
@Autowired
private ServiceB serviceB;
@Service
public class ServiceB {
@Autowired
private ServiceA serviceA;
@Configuration
@ComponentScan(value = "com.star.xxx")
public class BeanTestConfig {
}
public class BeanTest {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(BeanTestConfig.class);
context.getBean("serviceA",ServiceA.class);
}
}
在spring中bean创建都是从doGetBean()开始的,可以在getBean()方法处断点进入,然后会看到Object sharedInstance = getSingleton(beanName);具体代码如下:
@Nullable
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;
}
三个map集合如下,用来缓存bean实例或ObjectFactory:
/** 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实例:
// Create bean instance.
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, () -> {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
// Explicitly remove instance from singleton cache: It might have been put there
// eagerly by the creation process, to allow for circular reference resolution.
// Also remove any beans that received a temporary reference to the bean.
destroySingleton(beanName);
throw ex;
}
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
中间实例化bean暂时省略,然后向缓存singletonFactories中添加ObjectFactory:
// 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));
}
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);
}
}
}
实例完成后,开始init操作,组装bean:
// Initialize the bean instance.
Object exposedObject = bean;
try {
populateBean(beanName, mbd, instanceWrapper);
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
然后调用各种beanPostProcessor,这里使用的是@Autowired注解,对应的AutowiredAnnotationBeanPostProcessor,获取B实例,同样从doGetBean()开始。
不同的是初始化B时,singletonFactories中已经有了A的ObjectFactory,ObjectFactory类似FactoryBean包装了一下目标实例。
接着调用ObjectFactory的getObject方法返回目标实例,放入earlySingletonObjects中,同时移除ObjectFactory用完即除,然后B就成功初始化了,B就放到了缓存singletonObjects。
有了B此时A也可以成功初始化了,A也放到singletonObjects中,缓存earlySingletonObjects中的A也可以删除了。毕竟最终是要放到singletonObjects中的,其他两个map缓存只是为了临时缓存用来解决循环依赖的问题,这也是为什么map的初始化容量差别所在。
以上就是spring解决循环依赖的基本流程了,其实spring的创建bean的流程也是这么走下来的。
觉得有用,点个关注。如有纰漏,欢迎批评指正。