Skip to content

Commit 6905dff

Browse files
committed
Introduce spring.locking.strict=true flag for 6.1.x style bean creation locking
Closes gh-34303
1 parent 20736bd commit 6905dff

File tree

3 files changed

+56
-1
lines changed

3 files changed

+56
-1
lines changed

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

+14-1
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@
7676
import org.springframework.core.OrderComparator;
7777
import org.springframework.core.Ordered;
7878
import org.springframework.core.ResolvableType;
79+
import org.springframework.core.SpringProperties;
7980
import org.springframework.core.annotation.MergedAnnotation;
8081
import org.springframework.core.annotation.MergedAnnotations;
8182
import org.springframework.core.annotation.MergedAnnotations.SearchStrategy;
@@ -128,6 +129,17 @@
128129
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
129130
implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {
130131

132+
/**
133+
* System property that instructs Spring to enforce string locking during bean creation,
134+
* rather than the mix of strict and lenient locking that 6.2 applies by default. Setting
135+
* this flag to "true" restores 6.1.x style locking in the entire pre-instantiation phase.
136+
* @since 6.2.6
137+
* @see #preInstantiateSingletons()
138+
*/
139+
public static final String STRICT_LOCKING_PROPERTY_NAME = "spring.locking.strict";
140+
141+
private static final boolean lenientLockingAllowed = !SpringProperties.getFlag(STRICT_LOCKING_PROPERTY_NAME);
142+
131143
@Nullable
132144
private static Class<?> jakartaInjectProviderClass;
133145

@@ -1031,7 +1043,8 @@ protected void checkMergedBeanDefinition(RootBeanDefinition mbd, String beanName
10311043
@Override
10321044
@Nullable
10331045
protected Boolean isCurrentThreadAllowedToHoldSingletonLock() {
1034-
return (this.preInstantiationPhase ? this.preInstantiationThread.get() != PreInstantiation.BACKGROUND : null);
1046+
return (lenientLockingAllowed && this.preInstantiationPhase ?
1047+
this.preInstantiationThread.get() != PreInstantiation.BACKGROUND : null);
10351048
}
10361049

10371050
@Override

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

+41
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,15 @@
2020
import org.junit.jupiter.api.Timeout;
2121

2222
import org.springframework.beans.factory.ObjectProvider;
23+
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
24+
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
2325
import org.springframework.beans.testfixture.beans.TestBean;
2426
import org.springframework.context.ConfigurableApplicationContext;
27+
import org.springframework.core.SpringProperties;
2528
import org.springframework.core.testfixture.EnabledForTestGroups;
2629
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
2730

31+
import static org.assertj.core.api.Assertions.assertThat;
2832
import static org.springframework.context.annotation.Bean.Bootstrap.BACKGROUND;
2933
import static org.springframework.core.testfixture.TestGroup.LONG_RUNNING;
3034

@@ -56,6 +60,21 @@ void bootstrapWithUnmanagedThreads() {
5660
ctx.close();
5761
}
5862

63+
@Test
64+
@Timeout(5)
65+
@EnabledForTestGroups(LONG_RUNNING)
66+
void bootstrapWithStrictLockingThread() {
67+
SpringProperties.setFlag(DefaultListableBeanFactory.STRICT_LOCKING_PROPERTY_NAME);
68+
try {
69+
ConfigurableApplicationContext ctx = new AnnotationConfigApplicationContext(StrictLockingBeanConfig.class);
70+
assertThat(ctx.getBean("testBean2", TestBean.class).getSpouse()).isSameAs(ctx.getBean("testBean1"));
71+
ctx.close();
72+
}
73+
finally {
74+
SpringProperties.setProperty(DefaultListableBeanFactory.STRICT_LOCKING_PROPERTY_NAME, null);
75+
}
76+
}
77+
5978
@Test
6079
@Timeout(5)
6180
@EnabledForTestGroups(LONG_RUNNING)
@@ -148,6 +167,28 @@ public TestBean testBean4() {
148167
}
149168

150169

170+
@Configuration(proxyBeanMethods = false)
171+
static class StrictLockingBeanConfig {
172+
173+
@Bean
174+
public TestBean testBean1(ObjectProvider<TestBean> testBean2) {
175+
new Thread(testBean2::getObject).start();
176+
try {
177+
Thread.sleep(1000);
178+
}
179+
catch (InterruptedException ex) {
180+
throw new RuntimeException(ex);
181+
}
182+
return new TestBean();
183+
}
184+
185+
@Bean
186+
public TestBean testBean2(ConfigurableListableBeanFactory beanFactory) {
187+
return new TestBean((TestBean) beanFactory.getSingleton("testBean1"));
188+
}
189+
}
190+
191+
151192
@Configuration(proxyBeanMethods = false)
152193
static class CircularReferenceBeanConfig {
153194

Diff for: spring-core/src/main/java/org/springframework/core/SpringProperties.java

+1
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
* @author Juergen Hoeller
4040
* @since 3.2.7
4141
* @see org.springframework.beans.StandardBeanInfoFactory#IGNORE_BEANINFO_PROPERTY_NAME
42+
* @see org.springframework.beans.factory.support.DefaultListableBeanFactory#STRICT_LOCKING_PROPERTY_NAME
4243
* @see org.springframework.core.env.AbstractEnvironment#IGNORE_GETENV_PROPERTY_NAME
4344
* @see org.springframework.expression.spel.SpelParserConfiguration#SPRING_EXPRESSION_COMPILER_MODE_PROPERTY_NAME
4445
* @see org.springframework.jdbc.core.StatementCreatorUtils#IGNORE_GETPARAMETERTYPE_PROPERTY_NAME

0 commit comments

Comments
 (0)