Browse Source

AbstractBeanFactory removes alreadyCreated entry after bean creation failure

Issue: SPR-10896
pull/354/head
Juergen Hoeller 11 years ago committed by unknown
parent
commit
e213561dac
  1. 132
      spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanFactory.java

132
spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanFactory.java

@ -278,79 +278,85 @@ 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.
String[] dependsOn = mbd.getDependsOn(); // Guarantee initialization of beans that the current bean depends on.
if (dependsOn != null) { String[] dependsOn = mbd.getDependsOn();
for (String dependsOnBean : dependsOn) { if (dependsOn != null) {
getBean(dependsOnBean); for (String dependsOnBean : dependsOn) {
registerDependentBean(dependsOnBean, beanName); getBean(dependsOnBean);
} 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()) {
// 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 { // Create bean instance.
String scopeName = mbd.getScope(); if (mbd.isSingleton()) {
final Scope scope = this.scopes.get(scopeName); sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
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;
}
} }
// Check if required type matches the type of the actual bean instance. // Check if required type matches the type of the actual bean instance.
@ -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.

Loading…
Cancel
Save