Spring IOC(8)SingletonBeanRegist
在Spring(7)里面介绍了DefaultListableBeanFactory,稍微提到了除BeanFactory之外的另外两个顶层接口BeanDefinitionRegistry和SingletonBeanRegistry。
BeanDefinitionRegistry提供了BeanDefinition的管理功能,如下图所示:
SingletonBeanRegistry提供了SingletonBean的管理功能,如下图所示:
SingletonBeanRegistry与BeanDefinitionRegistry不同的是,SingletonBeanRegistry有一个默认的实现DefaultSingletonBeanRegistry。
DefaultSingletonBeanRegistry
DefaultSingletonBeanRegistry是SingletonBeanRegistry的默认实现,所以它提供了singletonObjects来作为singleton bean的缓存,但是为了解决bean循环引用的问题,所以引入了三层缓存,即二级缓存earlySingletonObjects和三级缓存singletonFactories。
//单例bean的一级缓存
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
//单例bean的三级缓存
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
//单例bean的二级缓存
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
//set类型,已注册的单例bean集合
private final Set<String> registeredSingletons = new LinkedHashSet<>(256);
//跟bean循环引用有关系,表示正在创建的单例bean集合
private final Set<String> singletonsCurrentlyInCreation =
Collections.newSetFromMap(new ConcurrentHashMap<>(16));
//需要排除的正在创建bean的检查
private final Set<String> inCreationCheckExclusions =
Collections.newSetFromMap(new ConcurrentHashMap<>(16));
private Set<Exception> suppressedExceptions;
//表示现在是不是destroy singleton
private boolean singletonsCurrentlyInDestruction = false;
//disposable bean的缓存
private final Map<String, Object> disposableBeans = new LinkedHashMap<>();
//
private final Map<String, Set<String>> containedBeanMap = new ConcurrentHashMap<>(16);
//dependent bean的集合
private final Map<String, Set<String>> dependentBeanMap = new ConcurrentHashMap<>(64);
private final Map<String, Set<String>> dependenciesForBeanMap = new ConcurrentHashMap<>(64);
那么这上面的singleton的缓存是怎么解决bean的循环依赖的呢?
我们先记录下跟这三个缓存相关的方法:
//将singleton bean实例放入singletonObject一级缓存中
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);
}
}
//将singleton bean放入三级缓存中
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);
}
}
}
//如果一级缓存singletonObjects存在bean,则返回。
//如果singletonObjects没有该bean,且这个bean正在创建,
// 就检查二级缓存earlySingletonObjects是否存在该bean实例。
//如果不存在就继续检查三级缓存singletonFactory,三级缓存肯定有,
// 因为这个bean正在创建中,那么就将三级缓存的值放入到二级缓存。
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;
}
这三级缓存是怎么协同工作的?(XML版本)
Spring解决循环依赖问题是通过结合bean实例化和bean属性填装分离,singletonObjects、earlySingletonObjects 、singletonFactories 三级缓存机制和引用提前暴露机制实现的。
<bean id="teacher" class="com.gary.spring.Teacher" >
<property name="student" ref="student"/>
</bean>
<bean id="student" class="com.gary.spring.Student" >
<property name="teacher" ref="teacher"/>
</bean>
Student student = (Student) beanFactory.getBean("student");
System.out.println(student.getTeacher());
定义了两个bean,Teacher里面持有Student的成员变量,同时Student里面持有Teacher的引用。
当开始调用getBean("student")的时候开始创建Student的实例。
1.1)--> getBean(beanName)
开始获取Student的bean。
1.2)--> doGetBean(beanName, null, null, false)
- 先调用getSingleton(beanName),来检查三级缓存中是否存在Student bean,如果存在就直接返回了。第一次调用肯定返回null。
- 再调用getSingleton(beanName, ObjectFactory<?> singletonFactory)
这里面会将当前bean放入singletonsCurrentlyInCreation缓存 - 调用createBean()创建bean
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
// Eagerly check singleton cache for manually registered singletons.
//检查三级循环
Object sharedInstance = getSingleton(beanName);
。。。省略代码
// Create bean instance.
if (mbd.isSingleton()) {
//getSingleton(beanName, ObjectFactory<?> singletonFactory)
sharedInstance = getSingleton(beanName, () -> {
try {
//调用createBean创建bean
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);
}
else if (mbd.isPrototype()) {
// It's a prototype -> create a new instance.
Object prototypeInstance = null;
try {
beforePrototypeCreation(beanName);
prototypeInstance = createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
。。。省略代码
return (T) bean;
}
1.3)--> doCreateBean(beanName, RootBeanDefinition, args)
这里会首先通过createBeanInstance()创建Student bean对应的实例,并且通过addSingletonFactory(beanName, bean)把创建的但是还未初始化的bean放入三级缓存。
getEarlyBeanReference与AOP创建proxy有关系,所以有可能放入三级缓存的是proxy代理对象。
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
throws BeanCreationException {
//创建bean的实例,封装成beanWrapper
if (instanceWrapper == null) {
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
//获取beanWrapper里面bean实例
final Object bean = instanceWrapper.getWrappedInstance();
// 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");
}
//将bean先放入三级缓存SingletonFactorys
//getEarlyBeanReference与AOP创建有关系
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
// Initialize the bean instance.
Object exposedObject = bean;
try {
//开始装载bean的相关属性值
populateBean(beanName, mbd, instanceWrapper);
//初始化bean
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
catch (Throwable ex) {
if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
throw (BeanCreationException) ex;
}
else {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
}
}
if (earlySingletonExposure) {
//如果是过早暴露singleton bean,就再检查earlySingletonObjects二级缓存
Object earlySingletonReference = getSingleton(beanName, false);
if (earlySingletonReference != null) {
if (exposedObject == bean) {
exposedObject = earlySingletonReference;
}
// allowRawInjectionDespiteWrapping 标注是否允许此Bean的原始类型被注入到其它Bean里面,即使自己最终会被包装(代理),AOP相关
// 默认是false表示不允许,如果改为true表示允许
else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
String[] dependentBeans = getDependentBeans(beanName);
Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
for (String dependentBean : dependentBeans) {
if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
actualDependentBeans.add(dependentBean);
}
}
if (!actualDependentBeans.isEmpty()) {
throw new BeanCurrentlyInCreationException(beanName,
"Bean with name '" + beanName + "' has been injected into other beans [" +
StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
"] in its raw version as part of a circular reference, but has eventually been " +
"wrapped. This means that said other beans do not use the final version of the " +
"bean. This is often the result of over-eager type matching - consider using " +
"'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");
}
}
}
}
// Register bean as disposable.
try {
registerDisposableBeanIfNecessary(beanName, bean, mbd);
}
catch (BeanDefinitionValidationException ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
}
return exposedObject;
}
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
Object exposedObject = bean;
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
}
}
}
return exposedObject;
}
public Object getEarlyBeanReference(Object bean, String beanName) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (!this.earlyProxyReferences.contains(cacheKey)) {
this.earlyProxyReferences.add(cacheKey);
}
//如有需要,则生成proxy
return wrapIfNecessary(bean, beanName, cacheKey);
}
1.4)--> populateBean(beanName, mbd, instanceWrapper)
这个方法会populateBean的属性,然后通过applyPropertyValues()来设置property对应的属性值,
protected void applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs) {
。。。省略部分代码
List<PropertyValue> deepCopy = new ArrayList<>(original.size());
boolean resolveNecessary = false;
//主要这里开始循环遍历PropertyValueList,original = mpvs.getPropertyValueList();
for (PropertyValue pv : original) {
if (pv.isConverted()) {
deepCopy.add(pv);
}
else {
String propertyName = pv.getName();
Object originalValue = pv.getValue();
//这里需要通过valueResolver来判断并获取属性的Value
Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue);
Object convertedValue = resolvedValue;
boolean convertible = bw.isWritableProperty(propertyName) &&
!PropertyAccessorUtils.isNestedOrIndexedProperty(propertyName);
if (convertible) {
convertedValue = convertForProperty(resolvedValue, propertyName, bw, converter);
}
// Possibly store converted value in merged bean definition,
// in order to avoid re-conversion for every created bean instance.
if (resolvedValue == originalValue) {
if (convertible) {
pv.setConvertedValue(convertedValue);
}
deepCopy.add(pv);
}
else if (convertible && originalValue instanceof TypedStringValue &&
!((TypedStringValue) originalValue).isDynamic() &&
!(convertedValue instanceof Collection || ObjectUtils.isArray(convertedValue))) {
pv.setConvertedValue(convertedValue);
deepCopy.add(pv);
}
else {
resolveNecessary = true;
deepCopy.add(new PropertyValue(pv, convertedValue));
}
}
}
if (mpvs != null && !resolveNecessary) {
mpvs.setConverted();
}
// Set our (possibly massaged) deep copy.
try {
bw.setPropertyValues(new MutablePropertyValues(deepCopy));
}
catch (BeansException ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Error setting property values", ex);
}
}
//valueResolver根据Value的类型来获得对应的值
public Object resolveValueIfNecessary(Object argName, @Nullable Object value) {
// We must check each value to see whether it requires a runtime reference
// to another bean to be resolved.
if (value instanceof RuntimeBeanReference) {
RuntimeBeanReference ref = (RuntimeBeanReference) value;
//如果是bean的相互引用就会走这里,通过resolveReference来获得相应的值
return resolveReference(argName, ref);
}
else if (value instanceof RuntimeBeanNameReference) {
String refName = ((RuntimeBeanNameReference) value).getBeanName();
refName = String.valueOf(doEvaluate(refName));
if (!this.beanFactory.containsBean(refName)) {
throw new BeanDefinitionStoreException(
"Invalid bean name '" + refName + "' in bean reference for " + argName);
}
return refName;
}
else if (value instanceof BeanDefinitionHolder) {
// Resolve BeanDefinitionHolder: contains BeanDefinition with name and aliases.
BeanDefinitionHolder bdHolder = (BeanDefinitionHolder) value;
return resolveInnerBean(argName, bdHolder.getBeanName(), bdHolder.getBeanDefinition());
}
else if (value instanceof BeanDefinition) {
// Resolve plain BeanDefinition, without contained name: use dummy name.
BeanDefinition bd = (BeanDefinition) value;
String innerBeanName = "(inner bean)" + BeanFactoryUtils.GENERATED_BEAN_NAME_SEPARATOR +
ObjectUtils.getIdentityHexString(bd);
return resolveInnerBean(argName, innerBeanName, bd);
}
。。。省略代码
}
//resolveReference会通过this.beanFactory.getBean(refName);来获得Value的值
private Object resolveReference(Object argName, RuntimeBeanReference ref) {
try {
Object bean;
String refName = ref.getBeanName();
refName = String.valueOf(doEvaluate(refName));
if (ref.isToParent()) {
if (this.beanFactory.getParentBeanFactory() == null) {
throw new BeanCreationException(
this.beanDefinition.getResourceDescription(), this.beanName,
"Can't resolve reference to bean '" + refName +
"' in parent factory: no parent factory available");
}
bean = this.beanFactory.getParentBeanFactory().getBean(refName);
}
else {
//*****这里是重点
bean = this.beanFactory.getBean(refName);
this.beanFactory.registerDependentBean(refName, this.beanName);
}
if (bean instanceof NullBean) {
bean = null;
}
return bean;
}
catch (BeansException ex) {
throw new BeanCreationException(
this.beanDefinition.getResourceDescription(), this.beanName,
"Cannot resolve reference to bean '" + ref.getBeanName() + "' while setting " + argName, ex);
}
}
看到上面的代码,在创建完Student的实例之后,开始populate Student的属性值,那么在设置Teacher的值的时候,就通过getBean(Teacher)去创建Teacher的单例bean。
那么这里开始创建Teacher相关的步骤,且与上面步骤完全一致,不同的是populateBean之后的动作。
2.1)--> getBean(beanName)
开始获取Teacher的bean。
2.2)--> doGetBean(beanName, null, null, false)
2.3)--> doCreateBean(beanName, RootBeanDefinition, args)
createBeanInstance()创建Teacher的实例,并且通过addSingletonFactory(beanName, bean)把创建的但是还未初始化的bean放入三级缓存。
2.4)--> populateBean(beanName, mbd, instanceWrapper)
创建Teacher实例之后,开始populate Teacher的相关属性,这时候开始getBean(Student),获取尝试获取Student。
获取尝试获取Student,涉及到三级缓存
3.1)--> getBean(beanName)
又开始尝试获取Student的bean。
3.2)-->doGetBean(beanName, null, null, false)
这里会通过getSingleton(beanName)来检查三级缓存,这个时候三级缓存中应该是由两个bean分别是Student和Teacher,那么很好,将Student的bean从三级缓存中删除并添加到二级缓存,并且直接返回。
回到2步骤继续创建Teacher
2.4)--> 又回到2.4步骤,Teacher的populateBean就能拿到Student的实例了。
2.3)--> 完成initializeBean(beanName, exposedObject, mbd)
调用初始化方法,初始化Teacher。
2.3)--> getSingleton(beanName, false)
检查earlySingletonObjects二级缓存,这里注意earlySingletonReference,思考为什么需要三级缓存而不是二级缓存?
2.2)-->getSingleton(beanName, ObjectFactory<?> singletonFactory)
方法返回,将Teacher从singletonsCurrentlyInCreation,且将Teacher从二级和三级缓存中移除,加入一级缓存singletonObjects。
回到1步骤继续创建Student
1.4)这时候回到Student Bean的1.4步骤,将Teacher值设置完成。
1.3)--> initializeBean(beanName, exposedObject, mbd)
调用初始化方法,初始化Student。
1.3)--> getSingleton(beanName, false)
检查earlySingletonObjects二级缓存
1.2)-->getSingleton(beanName, ObjectFactory<?> singletonFactory)
方法返回,将Student从singletonsCurrentlyInCreation,且将Student从二级和三级缓存中移除,加入一级缓存singletonObjects。
总结:
1)注意此文讨论的bean为单例情况(且是set注入,而不是构造器注入),prototype的bean循环依赖都会抛出异常,如果是单例与prototype混合的情况,如果是先创建单例则能成功,反之则会抛出异常。
2)Spring解决循环依赖问题是通过结合bean实例化和bean属性填装分离,singletonObjects、earlySingletonObjects 、singletonFactories 三级缓存机制和引用提前暴露机制实现的。
3)上面提到的,如果是正常的bean循环引用,那么二级缓存其实也是能实现的。但是为什么要设计三级缓存呢?
使用三级而非二级缓存并非出于IOC的考虑,而是出于AOP的考虑,即若使用二级缓存,在AOP情形下,注入到其他bean的,不是最终的代理对象,而是原始对象。
相关代码就在1.3)--> doCreateBean后面earlySingletonReference。