Avoid lenient locking for additional external bootstrap threads
Includes spring.locking.strict revision to differentiate between true, false, not set. Includes checkFlag accessor on SpringProperties, also used in StatementCreatorUtils. Closes gh-34729 See gh-34303
This commit is contained in:
@@ -16,6 +16,9 @@
|
||||
|
||||
package org.springframework.context.annotation;
|
||||
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.Timeout;
|
||||
|
||||
@@ -67,7 +70,7 @@ class BackgroundBootstrapTests {
|
||||
@Test
|
||||
@Timeout(10)
|
||||
@EnabledForTestGroups(LONG_RUNNING)
|
||||
void bootstrapWithStrictLockingThread() {
|
||||
void bootstrapWithStrictLockingFlag() {
|
||||
SpringProperties.setFlag(DefaultListableBeanFactory.STRICT_LOCKING_PROPERTY_NAME);
|
||||
try {
|
||||
ConfigurableApplicationContext ctx = new AnnotationConfigApplicationContext(StrictLockingBeanConfig.class);
|
||||
@@ -79,6 +82,42 @@ class BackgroundBootstrapTests {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@Timeout(10)
|
||||
@EnabledForTestGroups(LONG_RUNNING)
|
||||
void bootstrapWithStrictLockingInferred() throws InterruptedException {
|
||||
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
|
||||
ctx.register(InferredLockingBeanConfig.class);
|
||||
ExecutorService threadPool = Executors.newFixedThreadPool(2);
|
||||
threadPool.submit(() -> ctx.refresh());
|
||||
Thread.sleep(500);
|
||||
threadPool.submit(() -> ctx.getBean("testBean2"));
|
||||
Thread.sleep(1000);
|
||||
assertThat(ctx.getBean("testBean2", TestBean.class).getSpouse()).isSameAs(ctx.getBean("testBean1"));
|
||||
ctx.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
@Timeout(10)
|
||||
@EnabledForTestGroups(LONG_RUNNING)
|
||||
void bootstrapWithStrictLockingTurnedOff() throws InterruptedException {
|
||||
SpringProperties.setFlag(DefaultListableBeanFactory.STRICT_LOCKING_PROPERTY_NAME, false);
|
||||
try {
|
||||
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
|
||||
ctx.register(InferredLockingBeanConfig.class);
|
||||
ExecutorService threadPool = Executors.newFixedThreadPool(2);
|
||||
threadPool.submit(() -> ctx.refresh());
|
||||
Thread.sleep(500);
|
||||
threadPool.submit(() -> ctx.getBean("testBean2"));
|
||||
Thread.sleep(1000);
|
||||
assertThat(ctx.getBean("testBean2", TestBean.class).getSpouse()).isNull();
|
||||
ctx.close();
|
||||
}
|
||||
finally {
|
||||
SpringProperties.setProperty(DefaultListableBeanFactory.STRICT_LOCKING_PROPERTY_NAME, null);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@Timeout(10)
|
||||
@EnabledForTestGroups(LONG_RUNNING)
|
||||
@@ -128,6 +167,24 @@ class BackgroundBootstrapTests {
|
||||
ctx.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
@Timeout(10)
|
||||
@EnabledForTestGroups(LONG_RUNNING)
|
||||
void bootstrapWithCustomExecutorAndStrictLocking() {
|
||||
SpringProperties.setFlag(DefaultListableBeanFactory.STRICT_LOCKING_PROPERTY_NAME);
|
||||
try {
|
||||
ConfigurableApplicationContext ctx = new AnnotationConfigApplicationContext(CustomExecutorBeanConfig.class);
|
||||
ctx.getBean("testBean1", TestBean.class);
|
||||
ctx.getBean("testBean2", TestBean.class);
|
||||
ctx.getBean("testBean3", TestBean.class);
|
||||
ctx.getBean("testBean4", TestBean.class);
|
||||
ctx.close();
|
||||
}
|
||||
finally {
|
||||
SpringProperties.setProperty(DefaultListableBeanFactory.STRICT_LOCKING_PROPERTY_NAME, null);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
static class UnmanagedThreadBeanConfig {
|
||||
@@ -220,6 +277,27 @@ class BackgroundBootstrapTests {
|
||||
}
|
||||
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
static class InferredLockingBeanConfig {
|
||||
|
||||
@Bean
|
||||
public TestBean testBean1() {
|
||||
try {
|
||||
Thread.sleep(1000);
|
||||
}
|
||||
catch (InterruptedException ex) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
return new TestBean("testBean1");
|
||||
}
|
||||
|
||||
@Bean
|
||||
public TestBean testBean2(ConfigurableListableBeanFactory beanFactory) {
|
||||
return new TestBean((TestBean) beanFactory.getSingleton("testBean1"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
static class CircularReferenceAgainstMainThreadBeanConfig {
|
||||
|
||||
@@ -377,13 +455,13 @@ class BackgroundBootstrapTests {
|
||||
|
||||
@Bean(bootstrap = BACKGROUND) @DependsOn("testBean3")
|
||||
public TestBean testBean1(TestBean testBean3) throws InterruptedException {
|
||||
Thread.sleep(3000);
|
||||
Thread.sleep(6000);
|
||||
return new TestBean();
|
||||
}
|
||||
|
||||
@Bean(bootstrap = BACKGROUND) @Lazy
|
||||
public TestBean testBean2() throws InterruptedException {
|
||||
Thread.sleep(3000);
|
||||
Thread.sleep(6000);
|
||||
return new TestBean();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user