diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java index abe39708346..0a2556ddbe9 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java @@ -1164,12 +1164,19 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto if (mbd.isBackgroundInit()) { Executor executor = getBootstrapExecutor(); if (executor != null) { + // Force initialization of depends-on beans in mainline thread. String[] dependsOn = mbd.getDependsOn(); if (dependsOn != null) { for (String dep : dependsOn) { getBean(dep); } } + // Force initialization of factory reference in mainline thread. + String factoryBeanName = mbd.getFactoryBeanName(); + if (factoryBeanName != null) { + getBean(factoryBeanName); + } + // Instantiate current bean in background thread. CompletableFuture future = CompletableFuture.runAsync( () -> instantiateSingletonInBackgroundThread(beanName), executor); addSingletonFactory(beanName, () -> { diff --git a/spring-context/src/test/java/org/springframework/context/annotation/BackgroundBootstrapTests.java b/spring-context/src/test/java/org/springframework/context/annotation/BackgroundBootstrapTests.java index 91a9e726fd7..85ff05b6f43 100644 --- a/spring-context/src/test/java/org/springframework/context/annotation/BackgroundBootstrapTests.java +++ b/spring-context/src/test/java/org/springframework/context/annotation/BackgroundBootstrapTests.java @@ -197,6 +197,16 @@ class BackgroundBootstrapTests { } } + @Test + @Timeout(10) + @EnabledForTestGroups(LONG_RUNNING) + void bootstrapWithCustomExecutorAndLazyConfig() { + ConfigurableApplicationContext ctx = new AnnotationConfigApplicationContext(CustomExecutorLazyBeanConfig.class); + assertThat(ctx.getBeanFactory().containsSingleton("testBean1")).isTrue(); + assertThat(ctx.getBeanFactory().containsSingleton("testBean2")).isTrue(); + ctx.close(); + } + @Configuration(proxyBeanMethods = false) static class UnmanagedThreadBeanConfig { @@ -542,4 +552,36 @@ class BackgroundBootstrapTests { } } + + @Configuration(proxyBeanMethods = false) + static class CustomExecutorLazyBeanConfig { + + @Bean + public ThreadPoolTaskExecutor bootstrapExecutor() { + ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); + executor.setThreadNamePrefix("Custom-"); + executor.setCorePoolSize(2); + executor.initialize(); + return executor; + } + + @Configuration(proxyBeanMethods = false) + @Lazy + static class LazyBeanConfig { + + @Bean(bootstrap = BACKGROUND) + public TestBean testBean1() throws InterruptedException { + Thread.sleep(6000); + return new TestBean(); + } + + @Bean(bootstrap = BACKGROUND) + @Lazy + public TestBean testBean2() throws InterruptedException { + Thread.sleep(6000); + return new TestBean(); + } + } + } + }