AbstractBeanFactory removes alreadyCreated entry after bean creation failure

Issue: SPR-10896
This commit is contained in:
Juergen Hoeller
2013-09-14 06:55:19 +02:00
committed by unknown
parent 0ee910c61a
commit e213561dac

View File

@@ -278,78 +278,84 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
markBeanAsCreated(beanName); markBeanAsCreated(beanName);
} }
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName); try {
checkMergedBeanDefinition(mbd, beanName, args); final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
checkMergedBeanDefinition(mbd, beanName, args);
// Guarantee initialization of beans that the current bean depends on. // Guarantee initialization of beans that the current bean depends on.
String[] dependsOn = mbd.getDependsOn(); String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) { if (dependsOn != null) {
for (String dependsOnBean : dependsOn) { for (String dependsOnBean : dependsOn) {
getBean(dependsOnBean); getBean(dependsOnBean);
registerDependentBean(dependsOnBean, beanName); registerDependentBean(dependsOnBean, 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);
}
else if (mbd.isPrototype()) { // Create bean instance.
// It's a prototype -> create a new instance. if (mbd.isSingleton()) {
Object prototypeInstance = null; sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
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 '" + scopeName + "'");
}
try {
Object scopedInstance = scope.get(beanName, new ObjectFactory<Object>() {
@Override @Override
public Object getObject() throws BeansException { public Object getObject() throws BeansException {
beforePrototypeCreation(beanName);
try { try {
return createBean(beanName, mbd, args); return createBean(beanName, mbd, args);
} }
finally { catch (BeansException ex) {
afterPrototypeCreation(beanName); // 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(scopedInstance, name, beanName, mbd); bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
} }
catch (IllegalStateException ex) {
throw new BeanCreationException(beanName, else if (mbd.isPrototype()) {
"Scope '" + scopeName + "' is not active for the current thread; " + // It's a prototype -> create a new instance.
"consider defining a scoped proxy for this bean if you intend to refer to it from a singleton", Object prototypeInstance = null;
ex); 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 '" + scopeName + "'");
}
try {
Object scopedInstance = scope.get(beanName, new ObjectFactory<Object>() {
@Override
public Object getObject() 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;
} }
} }
@@ -1430,6 +1436,14 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
this.alreadyCreated.add(beanName); this.alreadyCreated.add(beanName);
} }
/**
* Perform appropriate cleanup of cached metadata after bean creation failed.
* @param beanName the name of the bean
*/
protected void cleanupAfterBeanCreationFailure(String beanName) {
this.alreadyCreated.remove(beanName);
}
/** /**
* Determine whether the specified bean is eligible for having * Determine whether the specified bean is eligible for having
* its bean definition metadata cached. * its bean definition metadata cached.