Skip to content

Commit 1187bc2

Browse files
committed
Merge branch '6.2.x'
# Conflicts: # spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractAutowireCapableBeanFactory.java
2 parents 01fea5e + fa168ca commit 1187bc2

File tree

4 files changed

+53
-18
lines changed

4 files changed

+53
-18
lines changed

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

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -990,9 +990,17 @@ protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd,
990990
* that we couldn't obtain a shortcut FactoryBean instance
991991
*/
992992
private @Nullable FactoryBean<?> getSingletonFactoryBeanForTypeCheck(String beanName, RootBeanDefinition mbd) {
993-
boolean locked = this.singletonLock.tryLock();
994-
if (!locked) {
995-
return null;
993+
Boolean lockFlag = isCurrentThreadAllowedToHoldSingletonLock();
994+
if (lockFlag == null) {
995+
this.singletonLock.lock();
996+
}
997+
else {
998+
boolean locked = (lockFlag && this.singletonLock.tryLock());
999+
if (!locked) {
1000+
// Avoid shortcut FactoryBean instance but allow for subsequent type-based resolution.
1001+
resolveBeanClass(mbd, beanName);
1002+
return null;
1003+
}
9961004
}
9971005

9981006
try {

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

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -269,13 +269,15 @@ public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
269269
// Fallback as of 6.2: process given singleton bean outside of singleton lock.
270270
// Thread-safe exposure is still guaranteed, there is just a risk of collisions
271271
// when triggering creation of other beans as dependencies of the current bean.
272-
if (logger.isInfoEnabled()) {
273-
logger.info("Obtaining singleton bean '" + beanName + "' in thread \"" +
274-
Thread.currentThread().getName() + "\" while other thread holds " +
275-
"singleton lock for other beans " + this.singletonsCurrentlyInCreation);
276-
}
277272
this.lenientCreationLock.lock();
278273
try {
274+
if (logger.isInfoEnabled()) {
275+
Set<String> lockedBeans = new HashSet<>(this.singletonsCurrentlyInCreation);
276+
lockedBeans.removeAll(this.singletonsInLenientCreation);
277+
logger.info("Obtaining singleton bean '" + beanName + "' in thread \"" +
278+
currentThread.getName() + "\" while other thread holds singleton " +
279+
"lock for other beans " + lockedBeans);
280+
}
279281
this.singletonsInLenientCreation.add(beanName);
280282
}
281283
finally {

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

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2024 the original author or authors.
2+
* Copyright 2002-2025 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -117,7 +117,15 @@ ResolvableType getFactoryBeanGeneric(@Nullable ResolvableType type) {
117117
*/
118118
protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
119119
if (factory.isSingleton() && containsSingleton(beanName)) {
120-
this.singletonLock.lock();
120+
Boolean lockFlag = isCurrentThreadAllowedToHoldSingletonLock();
121+
boolean locked;
122+
if (lockFlag == null) {
123+
this.singletonLock.lock();
124+
locked = true;
125+
}
126+
else {
127+
locked = (lockFlag && this.singletonLock.tryLock());
128+
}
121129
try {
122130
Object object = this.factoryBeanObjectCache.get(beanName);
123131
if (object == null) {
@@ -130,11 +138,13 @@ protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanNam
130138
}
131139
else {
132140
if (shouldPostProcess) {
133-
if (isSingletonCurrentlyInCreation(beanName)) {
134-
// Temporarily return non-post-processed object, not storing it yet
135-
return object;
141+
if (locked) {
142+
if (isSingletonCurrentlyInCreation(beanName)) {
143+
// Temporarily return non-post-processed object, not storing it yet
144+
return object;
145+
}
146+
beforeSingletonCreation(beanName);
136147
}
137-
beforeSingletonCreation(beanName);
138148
try {
139149
object = postProcessObjectFromFactoryBean(object, beanName);
140150
}
@@ -143,7 +153,9 @@ protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanNam
143153
"Post-processing of FactoryBean's singleton object failed", ex);
144154
}
145155
finally {
146-
afterSingletonCreation(beanName);
156+
if (locked) {
157+
afterSingletonCreation(beanName);
158+
}
147159
}
148160
}
149161
if (containsSingleton(beanName)) {
@@ -154,7 +166,9 @@ protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanNam
154166
return object;
155167
}
156168
finally {
157-
this.singletonLock.unlock();
169+
if (locked) {
170+
this.singletonLock.unlock();
171+
}
158172
}
159173
}
160174
else {

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

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424

2525
import org.springframework.beans.factory.BeanCreationException;
2626
import org.springframework.beans.factory.BeanCurrentlyInCreationException;
27+
import org.springframework.beans.factory.FactoryBean;
2728
import org.springframework.beans.factory.ObjectProvider;
2829
import org.springframework.beans.factory.UnsatisfiedDependencyException;
2930
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
@@ -243,14 +244,24 @@ public TestBean testBean3(TestBean testBean4) {
243244
}
244245

245246
@Bean
246-
public TestBean testBean4() {
247+
public FactoryBean<TestBean> testBean4() {
247248
try {
248249
Thread.sleep(2000);
249250
}
250251
catch (InterruptedException ex) {
251252
Thread.currentThread().interrupt();
252253
}
253-
return new TestBean();
254+
TestBean testBean = new TestBean();
255+
return new FactoryBean<>() {
256+
@Override
257+
public TestBean getObject() {
258+
return testBean;
259+
}
260+
@Override
261+
public Class<?> getObjectType() {
262+
return testBean.getClass();
263+
}
264+
};
254265
}
255266
}
256267

0 commit comments

Comments
 (0)