Notify lenientCreationFinished condition after locked creation as well
Closes gh-34522
This commit is contained in:
parent
108caea385
commit
d2733cea36
|
@ -253,7 +253,6 @@ public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements
|
||||||
Boolean lockFlag = isCurrentThreadAllowedToHoldSingletonLock();
|
Boolean lockFlag = isCurrentThreadAllowedToHoldSingletonLock();
|
||||||
boolean acquireLock = !Boolean.FALSE.equals(lockFlag);
|
boolean acquireLock = !Boolean.FALSE.equals(lockFlag);
|
||||||
boolean locked = (acquireLock && this.singletonLock.tryLock());
|
boolean locked = (acquireLock && this.singletonLock.tryLock());
|
||||||
boolean lenient = false;
|
|
||||||
try {
|
try {
|
||||||
Object singletonObject = this.singletonObjects.get(beanName);
|
Object singletonObject = this.singletonObjects.get(beanName);
|
||||||
if (singletonObject == null) {
|
if (singletonObject == null) {
|
||||||
|
@ -268,7 +267,6 @@ public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements
|
||||||
Thread.currentThread().getName() + "\" while other thread holds " +
|
Thread.currentThread().getName() + "\" while other thread holds " +
|
||||||
"singleton lock for other beans " + this.singletonsCurrentlyInCreation);
|
"singleton lock for other beans " + this.singletonsCurrentlyInCreation);
|
||||||
}
|
}
|
||||||
lenient = true;
|
|
||||||
this.lenientCreationLock.lock();
|
this.lenientCreationLock.lock();
|
||||||
try {
|
try {
|
||||||
this.singletonsInLenientCreation.add(beanName);
|
this.singletonsInLenientCreation.add(beanName);
|
||||||
|
@ -329,7 +327,7 @@ public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements
|
||||||
// Try late locking for waiting on specific bean to be finished.
|
// Try late locking for waiting on specific bean to be finished.
|
||||||
this.singletonLock.lock();
|
this.singletonLock.lock();
|
||||||
locked = true;
|
locked = true;
|
||||||
// Singleton object should have appeared in the meantime.
|
// Lock-created singleton object should have appeared in the meantime.
|
||||||
singletonObject = this.singletonObjects.get(beanName);
|
singletonObject = this.singletonObjects.get(beanName);
|
||||||
if (singletonObject != null) {
|
if (singletonObject != null) {
|
||||||
return singletonObject;
|
return singletonObject;
|
||||||
|
@ -343,8 +341,12 @@ public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements
|
||||||
this.suppressedExceptions = new LinkedHashSet<>();
|
this.suppressedExceptions = new LinkedHashSet<>();
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
singletonObject = singletonFactory.getObject();
|
// Leniently created singleton object could have appeared in the meantime.
|
||||||
newSingleton = true;
|
singletonObject = this.singletonObjects.get(beanName);
|
||||||
|
if (singletonObject == null) {
|
||||||
|
singletonObject = singletonFactory.getObject();
|
||||||
|
newSingleton = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (IllegalStateException ex) {
|
catch (IllegalStateException ex) {
|
||||||
// Has the singleton object implicitly appeared in the meantime ->
|
// Has the singleton object implicitly appeared in the meantime ->
|
||||||
|
@ -388,15 +390,13 @@ public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements
|
||||||
if (locked) {
|
if (locked) {
|
||||||
this.singletonLock.unlock();
|
this.singletonLock.unlock();
|
||||||
}
|
}
|
||||||
if (lenient) {
|
this.lenientCreationLock.lock();
|
||||||
this.lenientCreationLock.lock();
|
try {
|
||||||
try {
|
this.singletonsInLenientCreation.remove(beanName);
|
||||||
this.singletonsInLenientCreation.remove(beanName);
|
this.lenientCreationFinished.signalAll();
|
||||||
this.lenientCreationFinished.signalAll();
|
}
|
||||||
}
|
finally {
|
||||||
finally {
|
this.lenientCreationLock.unlock();
|
||||||
this.lenientCreationLock.unlock();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,6 +56,16 @@ class BackgroundBootstrapTests {
|
||||||
ctx.close();
|
ctx.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Timeout(5)
|
||||||
|
@EnabledForTestGroups(LONG_RUNNING)
|
||||||
|
void bootstrapWithCircularReference() {
|
||||||
|
ConfigurableApplicationContext ctx = new AnnotationConfigApplicationContext(CircularReferenceBeanConfig.class);
|
||||||
|
ctx.getBean("testBean1", TestBean.class);
|
||||||
|
ctx.getBean("testBean2", TestBean.class);
|
||||||
|
ctx.close();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Timeout(5)
|
@Timeout(5)
|
||||||
@EnabledForTestGroups(LONG_RUNNING)
|
@EnabledForTestGroups(LONG_RUNNING)
|
||||||
|
@ -138,6 +148,34 @@ class BackgroundBootstrapTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Configuration(proxyBeanMethods = false)
|
||||||
|
static class CircularReferenceBeanConfig {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public TestBean testBean1(ObjectProvider<TestBean> testBean2) {
|
||||||
|
new Thread(testBean2::getObject).start();
|
||||||
|
try {
|
||||||
|
Thread.sleep(1000);
|
||||||
|
}
|
||||||
|
catch (InterruptedException ex) {
|
||||||
|
throw new RuntimeException(ex);
|
||||||
|
}
|
||||||
|
return new TestBean();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public TestBean testBean2(TestBean testBean1) {
|
||||||
|
try {
|
||||||
|
Thread.sleep(2000);
|
||||||
|
}
|
||||||
|
catch (InterruptedException ex) {
|
||||||
|
throw new RuntimeException(ex);
|
||||||
|
}
|
||||||
|
return new TestBean();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Configuration(proxyBeanMethods = false)
|
@Configuration(proxyBeanMethods = false)
|
||||||
static class CustomExecutorBeanConfig {
|
static class CustomExecutorBeanConfig {
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue