问题描述:
比如两个Bean InstacneA 和InstacneB 里面存在属性相互引用 创建Bean的时候 会相互依赖。
1.构造器注入 直接失败
2.protolType为多例的时候 也失败
3.单例 且是setter注入能成功创建
透过表面现象 看本质问题
Spring容器如何解决的呢?
源码走起~
思路 容器启动的时候便是 refresh()方法中 最后实例Bean的时候 会调用到
org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean
@SuppressWarnings("unchecked")
protected T doGetBean(
final String name, final Class requiredType, final Object[] args, boolean typeCheckOnly)
throws BeansException {
//解析bean 别名 alias
final String beanName = transformedBeanName(name);
Object bean;
// Eagerly check singleton cache for manually registered singletons.
//尝试从 单例子缓存池子内 去取 第一次创建的时候没有实例
Object sharedInstance = getSingleton(beanName);
if (sharedInstance !=null && args ==null) {
if (logger.isDebugEnabled()) {
if (isSingletonCurrentlyInCreation(beanName)) {
logger.debug("Returning eagerly cached instance of singleton bean '" + beanName +
"' that is not fully initialized yet - a consequence of a circular reference");
}
else {
logger.debug("Returning cached instance of singleton bean '" + beanName +"'");
}
}
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
else {
//拿不到当前单例 就往下走
// Fail if we're already creating this bean instance:
// We're assumably within a circular reference.
//多例的则抛出异常
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
// Check if bean definition exists in this factory.
BeanFactory parentBeanFactory = getParentBeanFactory();
if (parentBeanFactory !=null && !containsBeanDefinition(beanName)) {
// Not found -> check parent.
String nameToLookup = originalBeanName(name);
if (args !=null) {
// Delegation to parent with explicit args.
return (T) parentBeanFactory.getBean(nameToLookup, args);
}
else {
// No args -> delegate to standard getBean method.
return parentBeanFactory.getBean(nameToLookup, requiredType);
}
}
if (!typeCheckOnly) {
markBeanAsCreated(beanName);
}
try {
// 合并父类的属性到当前实例
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
//检查当前bean 是不是抽象类 如果是抽象的则会抛出异常 所以抽象的类不会实例化
checkMergedBeanDefinition(mbd, beanName, args);
// Guarantee initialization of beans that the current bean depends on.
// @DependsOn 判断实例先后顺序 加载顺序 依赖检查
String[] dependsOn = mbd.getDependsOn();
if (dependsOn !=null) {
for (String dep : dependsOn) {
if (isDependent(beanName, dep)) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Circular depends-on relationship between '" + beanName +"' and '" + dep +"'");
}
registerDependentBean(dep, beanName);
try {
getBean(dep);
}
catch (NoSuchBeanDefinitionException ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"'" + beanName +"' depends on missing bean '" + dep +"'", ex);
}
}
}
//创建Bean的过程开始
// Create bean instance.
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, new ObjectFactory() {
@Override
public ObjectgetObject()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);
}
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);
}
else {
String scopeName = mbd.getScope();
final Scope scope =this.scopes.get(scopeName);
if (scope ==null) {
throw new IllegalStateException("No Scope registered for scope name '" + scopeName +"'");
}
try {
Object scopedInstance = scope.get(beanName, new ObjectFactory() {
@Override
public ObjectgetObject()throws BeansException {
beforePrototypeCreation(beanName);
try {
return createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
}
});
bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
}
catch (IllegalStateException ex) {
throw new BeanCreationException(beanName,
"Scope '" + scopeName +"' is not active for the current thread; consider " +
"defining a scoped proxy for this bean if you intend to refer to it from a singleton",
ex);
}
}
}
catch (BeansException ex) {
cleanupAfterBeanCreationFailure(beanName);
throw ex;
}
}
// Check if required type matches the type of the actual bean instance.
if (requiredType !=null && bean !=null && !requiredType.isInstance(bean)) {
try {
return getTypeConverter().convertIfNecessary(bean, requiredType);
}
catch (TypeMismatchException ex) {
if (logger.isDebugEnabled()) {
logger.debug("Failed to convert bean '" + name +"' to required type '" +
ClassUtils.getQualifiedName(requiredType) +"'", ex);
}
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
}
return (T) bean;
}
--------------------------获取单例bean
/**
* Return the (raw) singleton object registered under the given name.
*
Checks already instantiated singletons and also allows for an early
* reference to a currently created singleton (resolving a circular reference).
* @param beanName the name of the bean to look for
* @param allowEarlyReference whether early references should be created or not
* @return the registered singleton object, or {@code null} if none found
*/
protected ObjectgetSingleton(String beanName, boolean allowEarlyReference) {
Object singletonObject =this.singletonObjects.get(beanName);
// 是不是在创建这个bean
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);
}
//属性未被赋值的时候 早期对象A被创建
populateBean方法 发布bean的过程中去进行属性赋值
对早期对象A的属性赋值 也就是intanceB属性赋值
发现属性b 需要创建
-------创建B
再次 调用同样对流程 创建B的早期对象(无属性) 发现依赖A实例
---->这个时候再去创建A(去早期对象缓存中拿 拿到了A的早期对象 )
B中的 A就被赋值了
放入到一级缓存
移除二级 三级中 缓存中的B 实例
这个时候B就被创建好了
然后再给A赋值
为什么构造器注入会抛出异常呢?
暴露的是一个早期对象 调用构造器 A的时候 就会去直接创建B-》....
因为你没有创建完 便没办法暴露....
但是这个是 缓存没有A 那么
这个时候便 无法解决