Skip to content

Commit 2dd550d

Browse files
committed
Force initialization of configuration class in mainline thread
Closes gh-36844 (cherry picked from commit af2b961)
1 parent 9ca396e commit 2dd550d

2 files changed

Lines changed: 49 additions & 0 deletions

File tree

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1164,12 +1164,19 @@ private CompletableFuture<?> preInstantiateSingleton(String beanName, RootBeanDe
11641164
if (mbd.isBackgroundInit()) {
11651165
Executor executor = getBootstrapExecutor();
11661166
if (executor != null) {
1167+
// Force initialization of depends-on beans in mainline thread.
11671168
String[] dependsOn = mbd.getDependsOn();
11681169
if (dependsOn != null) {
11691170
for (String dep : dependsOn) {
11701171
getBean(dep);
11711172
}
11721173
}
1174+
// Force initialization of factory reference in mainline thread.
1175+
String factoryBeanName = mbd.getFactoryBeanName();
1176+
if (factoryBeanName != null) {
1177+
getBean(factoryBeanName);
1178+
}
1179+
// Instantiate current bean in background thread.
11731180
CompletableFuture<?> future = CompletableFuture.runAsync(
11741181
() -> instantiateSingletonInBackgroundThread(beanName), executor);
11751182
addSingletonFactory(beanName, () -> {

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

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,16 @@ void bootstrapWithCustomExecutorAndStrictLocking() {
197197
}
198198
}
199199

200+
@Test
201+
@Timeout(10)
202+
@EnabledForTestGroups(LONG_RUNNING)
203+
void bootstrapWithCustomExecutorAndLazyConfig() {
204+
ConfigurableApplicationContext ctx = new AnnotationConfigApplicationContext(CustomExecutorLazyBeanConfig.class);
205+
assertThat(ctx.getBeanFactory().containsSingleton("testBean1")).isTrue();
206+
assertThat(ctx.getBeanFactory().containsSingleton("testBean2")).isTrue();
207+
ctx.close();
208+
}
209+
200210

201211
@Configuration(proxyBeanMethods = false)
202212
static class UnmanagedThreadBeanConfig {
@@ -542,4 +552,36 @@ public TestBean testBean4(@Lazy TestBean testBean1, @Lazy TestBean testBean2, @L
542552
}
543553
}
544554

555+
556+
@Configuration(proxyBeanMethods = false)
557+
static class CustomExecutorLazyBeanConfig {
558+
559+
@Bean
560+
public ThreadPoolTaskExecutor bootstrapExecutor() {
561+
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
562+
executor.setThreadNamePrefix("Custom-");
563+
executor.setCorePoolSize(2);
564+
executor.initialize();
565+
return executor;
566+
}
567+
568+
@Configuration(proxyBeanMethods = false)
569+
@Lazy
570+
static class LazyBeanConfig {
571+
572+
@Bean(bootstrap = BACKGROUND)
573+
public TestBean testBean1() throws InterruptedException {
574+
Thread.sleep(6000);
575+
return new TestBean();
576+
}
577+
578+
@Bean(bootstrap = BACKGROUND)
579+
@Lazy
580+
public TestBean testBean2() throws InterruptedException {
581+
Thread.sleep(6000);
582+
return new TestBean();
583+
}
584+
}
585+
}
586+
545587
}

0 commit comments

Comments
 (0)