引言
假如有class A;class B。其中A依赖B,B依赖A。那么在创建对象时就会有循环依赖的问题,Spring是如何解决这个问题的呢?如果这个依赖是在构造器中,spring还可以解决循环依赖的问题吗?
@Component
public class A {
@Autowired
private B b;
}
@Component
public class B {
@Autowired
private A a;
}
一、单例field属性的循环依赖
这一节比较长,但很重要。
首先,我们需要单步调试代码,帮助我们更方便的了解spring的方法调用关系。这一步可参考下述代码:
public class TestMain {
public static void main(String[] args) {
AnnotationConfigApplicationContext aac = new AnnotationConfigApplicationContext(TestMain.class);
aac.getBean("a");
}
}
我们通过单步调试,可以跟踪到获取bean的核心方法:org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton(java.lang.String, boolean)
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// 1 singletonObjects,存储成熟的完整bean对象
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
// 2 earlySingletonObjects 存储早期对象,早期对象初始化不完全
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
// 3 singletonFactories 存储bean工厂,解决有后置处理器的bean,找到其最终对象的factory
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);
}
上述代码中有三个缓存map,分别存储不同时期的对象。
- singletonObjects存储完整的bean,bean完全创建完成,将其放入singletonObjects。获取bean也先由这里获取。
- earlySingletonObjects存储早期对象,该早期对象中存在不可用的属性值。
- singletonFactories存储bean工厂对象,是经过AOP增强的最终工厂对象。
上述代码中,我们看到有三级缓存,这是解决循环依赖的关键。简单看下getSingleton做了以下几件事:查询一级缓存singletonObjects,然后查询二级缓存earlySingletonObjects,最后查询三级缓存singletonFactory,同时将bean放到二级缓存,并由三级缓存清除。
但是这里对一个全新的bean,返回还是null,而且各级缓存中的对象是什么时候放进去的呢?我们先来看下:org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean
protected <T> T doGetBean(
final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)
throws BeansException {
......
Object sharedInstance = getSingleton(beanName);
......
// Create bean instance.
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
@Override
public Object getObject() throws BeansException {
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);
}
......
上述分析的getSingleton是第5行,这里我们先关注第9行的getSingleton方法。单例模式下,通过getSingleton(为和第5行的getSingleton区分,我们称这个为第二个getSingleton)获取bean,实现如下:
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
synchronized (this.singletonObjects) {
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
......
beforeSingletonCreation(beanName);
......
try {
singletonObject = singletonFactory.getObject();
newSingleton = true;
}
......
if (newSingleton) {
addSingleton(beanName, singletonObject);
}
}
}
......
}
上面有singletonFactory.getObject(),该方法的实现是在入参中定义的,即createBean(beanName, mbd, args)(后面详细分析)。此外还有一个addSingleton的方法,实现如下:
protected void addSingleton(String beanName, Object singletonObject) {
synchronized (this.singletonObjects) {
this.singletonObjects.put(beanName, (singletonObject != null ? singletonObject : NULL_OBJECT));
this.singletonFactories.remove(beanName);
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
}
}
到这里,我们可以看到,一个全新的对象,是通过createBean创建完成,然后放到singletonObjects的。
接下来我们分析:org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args)
throws BeanCreationException {
......
if (instanceWrapper == null) {
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null);
......
// 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) {
......
addSingletonFactory(beanName, new ObjectFactory<Object>() {
@Override
public Object getObject() throws BeansException {
return getEarlyBeanReference(beanName, mbd, bean);
}
});
}
// Initialize the bean instance.
Object exposedObject = bean;
try {
populateBean(beanName, mbd, instanceWrapper);
if (exposedObject != null) {
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
}
......
return exposedObject;
}
在创建bean的时候,先调用createBeanInstance生成一个BeanWrapper。他的最终调用只是newInstance了一个对象,没有对对象进行初始化,这就为后续的aop增强,以及循环对象的注入提供了条件。
public static <T> T instantiateClass(Constructor<T> ctor, Object... args) throws BeanInstantiationException {
try {
ReflectionUtils.makeAccessible(ctor);
return ctor.newInstance(args);
}
......
}
继续回到doCreateBean方法,如下所示:
if (earlySingletonExposure) {
......
addSingletonFactory(beanName, new ObjectFactory<Object>() {
@Override
public Object getObject() throws BeansException {
return getEarlyBeanReference(beanName, mbd, bean);
}
});
}
当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);
}
}
}
这里我们可以看到,singletonFactory被放到了singletonFactories,singletonFactory是new的那个ObjectFactory。这里ObjectFactory为什么要这么定义,还有为什么需要使用singletonFactories?二级缓存不能解决循环依赖问题?这就需要关注getEarlyBeanReference。
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
Object exposedObject = bean;
if (bean != null && !mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
if (exposedObject == null) {
return null;
}
}
}
}
return exposedObject;
}
getEarlyBeanReference是由三级缓存singletonFactory中获取对象的实现方法,它调用的是org.springframework.beans.factory.config.SmartInstantiationAwareBeanPostProcessor#getEarlyBeanReference方法。实现如下:
public Object getEarlyBeanReference(Object bean, String beanName) throws BeansException {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (!this.earlyProxyReferences.contains(cacheKey)) {
this.earlyProxyReferences.add(cacheKey);
}
return wrapIfNecessary(bean, beanName, cacheKey);
}
继续看下wrapIfNecessary,org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#wrapIfNecessary:
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
......
// Create proxy if we have advice.
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
if (specificInterceptors != DO_NOT_PROXY) {
this.advisedBeans.put(cacheKey, Boolean.TRUE);
Object proxy = createProxy(
bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
上面通过createProxy方法,创建了带有aop增强设置的方法。到此,第三级缓存singletonFactory的作用我们就清楚了,主要是解决aop增强的实现。到这里我们可以得知new的ObjectFactory,最终帮助我们拿到了aop增强后的对象。
接下来需要注意的方法是populateBean:org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#populateBean:
protected void populateBean(String beanName, RootBeanDefinition mbd, BeanWrapper bw) {
PropertyValues pvs = mbd.getPropertyValues();
......
if (hasInstAwareBpps || needsDepCheck) {
PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
if (hasInstAwareBpps) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
if (pvs == null) {
return;
}
}
}
}
if (needsDepCheck) {
checkDependencies(beanName, mbd, filteredPds, pvs);
}
}
applyPropertyValues(beanName, mbd, bw, pvs);
}
populateBean用于填充对象的属性。这里会填充对象依赖的其他对象信息。上述代码的postProcessPropertyValues方法,最终会调用到:
org.springframework.beans.factory.support.DefaultListableBeanFactory#findAutowireCandidates。
protected Map<String, Object> findAutowireCandidates(
String beanName, Class<?> requiredType, DependencyDescriptor descriptor) {
......
for (String candidateName : candidateNames) {
if (!isSelfReference(beanName, candidateName) && isAutowireCandidate(candidateName, descriptor)) {
result.put(candidateName, getBean(candidateName));
}
}
......
}
上面的candidateName表示依赖的对象名称(B),这里可以看到,对于依赖的对象,又会重新调用getBean获取bean对象。具体调用,可以参考下面的调用堆栈图:
我们清楚了三级缓存的作用,下面我们结合上述分析,看看三级缓存是如何解决循环依赖问题的。
假设A依赖B,B依赖A。获取A时,A和B在三级缓存都不存在,因此第一个getSingleton返回null。之后会调doGetBean创建A,创建A时,先调createBeanInstance得到一个newInstance的没有实例化的对象。然后把对象A的工厂类放到singletonFactories,这里需要提的是,若A有做AOP增强,那么放到singletonFactories的就是AOP增强后工厂类。
接下来会在创建A中执行populateBean方法,进一步会调getBean,获取B,这将重复上述过程。
在获取B时,创建B的方法也会走到populateBean,这时,B又会获取A的对象。这时第二次获取A对象的getBean方法,会在执行第一个getSingleton时,检查到第三级缓存singletonFactories中有A的工厂方法,于是将对象A放到早期对象缓存earlySingletonObjects中。这轮查询,有得到一个早期的对象A,B将使用这个早期的对象A,完成对象B的创建。
B对象创建完成,A对象还在earlySingletonObjects中,在getSingleton中最后的addSingleton方法,会将对象A由二级缓存放到一级缓存singletonObjects中,这时获取到完整的对象A。
二、构造器中的循环依赖
接下来我们再看看,spring能否处理构造器中包含循环依赖的问题。
@Component
public class A {
private B cb;
@Autowired
A(B b){
this.cb = b;
}
}
@Component
public class B {
private A ca;
@Autowired
B(A a){
this.ca = a;
}
}
同样,我们还是假设A的构造器中依赖B,B的构造器中依赖A。我们回顾上述第二个getSingleton中的beforeSingletonCreation方法:
protected void beforeSingletonCreation(String beanName) {
if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
}
这里,singletonsCurrentlyInCreation保存的是当前正在创建,但是还没有创建完毕的类,根据上述对循环依赖的分析,当第二次创建A时,singletonsCurrentlyInCreation中已经包含A。这里,我们看下singletonsCurrentlyInCreation的定义:
private final Set<String> singletonsCurrentlyInCreation =
Collections.newSetFromMap(new ConcurrentHashMap<>(16));
这里,使用的是ConcurrentHashMap来保存,add方法实现为:
public boolean add(E e) { return m.put(e, Boolean.TRUE) == null; }
也就是说,当map中已经包含A时,ConcurrentHashMap的put方法会返回旧值(非null),这里的add方法会返回false。通过调试,发现inCreationCheckExclusions也是空,因此,这时会抛BeanCurrentlyInCreationException异常,导致创建A失败。因此,spring无法直接解决构造器中包含循环依赖的对象。
到这里,我们会问到,spring为什么要这么设计呢?其实原因很简单,spring的早期对象A没有被初始化,当newInstatnce一个对象B时,会执行B的构造方法,如果B的构造方法中对早期对象A进行操作,可能会抛异常。
那么。Spring无法解决这个问题吗?不是的,在构造函数的循环依赖参数前使用@Lazy注解,即可在构造器中使用循环依赖。
@Component
public class B {
private A ca;
@Autowired
B(@Lazy A a){
this.ca = a;
}
}
三、总结
1.spring通过使用三级缓存来解决循环依赖的问题,之所以使用三级缓存而不是二级缓存,是因为还需要处理aop增强的类。
2.spring无法直接解决构造器循环依赖,但可以使用@Lazy注解实现构造器的循环依赖