Skip to content

Commit 533ecf0

Browse files
committed
Merge branch '6.2.x'
2 parents 99d5e90 + d2733ce commit 533ecf0

File tree

2 files changed

+52
-14
lines changed

2 files changed

+52
-14
lines changed

Diff for: spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultSingletonBeanRegistry.java

+14-14
Original file line numberDiff line numberDiff line change
@@ -251,7 +251,6 @@ public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
251251
Boolean lockFlag = isCurrentThreadAllowedToHoldSingletonLock();
252252
boolean acquireLock = !Boolean.FALSE.equals(lockFlag);
253253
boolean locked = (acquireLock && this.singletonLock.tryLock());
254-
boolean lenient = false;
255254
try {
256255
Object singletonObject = this.singletonObjects.get(beanName);
257256
if (singletonObject == null) {
@@ -266,7 +265,6 @@ public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
266265
Thread.currentThread().getName() + "\" while other thread holds " +
267266
"singleton lock for other beans " + this.singletonsCurrentlyInCreation);
268267
}
269-
lenient = true;
270268
this.lenientCreationLock.lock();
271269
try {
272270
this.singletonsInLenientCreation.add(beanName);
@@ -327,7 +325,7 @@ public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
327325
// Try late locking for waiting on specific bean to be finished.
328326
this.singletonLock.lock();
329327
locked = true;
330-
// Singleton object should have appeared in the meantime.
328+
// Lock-created singleton object should have appeared in the meantime.
331329
singletonObject = this.singletonObjects.get(beanName);
332330
if (singletonObject != null) {
333331
return singletonObject;
@@ -341,8 +339,12 @@ public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
341339
this.suppressedExceptions = new LinkedHashSet<>();
342340
}
343341
try {
344-
singletonObject = singletonFactory.getObject();
345-
newSingleton = true;
342+
// Leniently created singleton object could have appeared in the meantime.
343+
singletonObject = this.singletonObjects.get(beanName);
344+
if (singletonObject == null) {
345+
singletonObject = singletonFactory.getObject();
346+
newSingleton = true;
347+
}
346348
}
347349
catch (IllegalStateException ex) {
348350
// Has the singleton object implicitly appeared in the meantime ->
@@ -386,15 +388,13 @@ public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
386388
if (locked) {
387389
this.singletonLock.unlock();
388390
}
389-
if (lenient) {
390-
this.lenientCreationLock.lock();
391-
try {
392-
this.singletonsInLenientCreation.remove(beanName);
393-
this.lenientCreationFinished.signalAll();
394-
}
395-
finally {
396-
this.lenientCreationLock.unlock();
397-
}
391+
this.lenientCreationLock.lock();
392+
try {
393+
this.singletonsInLenientCreation.remove(beanName);
394+
this.lenientCreationFinished.signalAll();
395+
}
396+
finally {
397+
this.lenientCreationLock.unlock();
398398
}
399399
}
400400
}

Diff for: spring-context/src/test/java/org/springframework/context/annotation/BackgroundBootstrapTests.java

+38
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,16 @@ void bootstrapWithUnmanagedThreads() {
5656
ctx.close();
5757
}
5858

59+
@Test
60+
@Timeout(5)
61+
@EnabledForTestGroups(LONG_RUNNING)
62+
void bootstrapWithCircularReference() {
63+
ConfigurableApplicationContext ctx = new AnnotationConfigApplicationContext(CircularReferenceBeanConfig.class);
64+
ctx.getBean("testBean1", TestBean.class);
65+
ctx.getBean("testBean2", TestBean.class);
66+
ctx.close();
67+
}
68+
5969
@Test
6070
@Timeout(5)
6171
@EnabledForTestGroups(LONG_RUNNING)
@@ -138,6 +148,34 @@ public TestBean testBean4() {
138148
}
139149

140150

151+
@Configuration(proxyBeanMethods = false)
152+
static class CircularReferenceBeanConfig {
153+
154+
@Bean
155+
public TestBean testBean1(ObjectProvider<TestBean> testBean2) {
156+
new Thread(testBean2::getObject).start();
157+
try {
158+
Thread.sleep(1000);
159+
}
160+
catch (InterruptedException ex) {
161+
throw new RuntimeException(ex);
162+
}
163+
return new TestBean();
164+
}
165+
166+
@Bean
167+
public TestBean testBean2(TestBean testBean1) {
168+
try {
169+
Thread.sleep(2000);
170+
}
171+
catch (InterruptedException ex) {
172+
throw new RuntimeException(ex);
173+
}
174+
return new TestBean();
175+
}
176+
}
177+
178+
141179
@Configuration(proxyBeanMethods = false)
142180
static class CustomExecutorBeanConfig {
143181

0 commit comments

Comments
 (0)