Mark bootstrap thread for entire finishBeanFactoryInitialization phase
Backport Bot / build (push) Has been cancelled
Details
Build and Deploy Snapshot / Build and Deploy Snapshot (push) Has been cancelled
Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:17], map[id:ubuntu-latest name:Linux]) (push) Has been cancelled
Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:21], map[id:ubuntu-latest name:Linux]) (push) Has been cancelled
Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:25], map[id:ubuntu-latest name:Linux]) (push) Has been cancelled
Details
Deploy Docs / Dispatch docs deployment (push) Has been cancelled
Details
Build and Deploy Snapshot / Verify (push) Has been cancelled
Details
Backport Bot / build (push) Has been cancelled
Details
Build and Deploy Snapshot / Build and Deploy Snapshot (push) Has been cancelled
Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:17], map[id:ubuntu-latest name:Linux]) (push) Has been cancelled
Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:21], map[id:ubuntu-latest name:Linux]) (push) Has been cancelled
Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:25], map[id:ubuntu-latest name:Linux]) (push) Has been cancelled
Details
Deploy Docs / Dispatch docs deployment (push) Has been cancelled
Details
Build and Deploy Snapshot / Verify (push) Has been cancelled
Details
Closes gh-35398
This commit is contained in:
parent
ecd3dd8883
commit
80e7ee321e
|
@ -152,6 +152,18 @@ public interface ConfigurableListableBeanFactory
|
||||||
*/
|
*/
|
||||||
boolean isConfigurationFrozen();
|
boolean isConfigurationFrozen();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mark current thread as main bootstrap thread for singleton instantiation,
|
||||||
|
* with lenient bootstrap locking applying for background threads.
|
||||||
|
* <p>Any such marker is to be removed at the end of the managed bootstrap in
|
||||||
|
* {@link #preInstantiateSingletons()}.
|
||||||
|
* @since 6.2.12
|
||||||
|
* @see #setBootstrapExecutor
|
||||||
|
* @see #preInstantiateSingletons()
|
||||||
|
*/
|
||||||
|
default void prepareSingletonBootstrap() {
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ensure that all non-lazy-init singletons are instantiated, also considering
|
* Ensure that all non-lazy-init singletons are instantiated, also considering
|
||||||
* {@link org.springframework.beans.factory.FactoryBean FactoryBeans}.
|
* {@link org.springframework.beans.factory.FactoryBean FactoryBeans}.
|
||||||
|
@ -159,6 +171,7 @@ public interface ConfigurableListableBeanFactory
|
||||||
* @throws BeansException if one of the singleton beans could not be created.
|
* @throws BeansException if one of the singleton beans could not be created.
|
||||||
* Note: This may have left the factory with some beans already initialized!
|
* Note: This may have left the factory with some beans already initialized!
|
||||||
* Call {@link #destroySingletons()} for full cleanup in this case.
|
* Call {@link #destroySingletons()} for full cleanup in this case.
|
||||||
|
* @see #prepareSingletonBootstrap()
|
||||||
* @see #destroySingletons()
|
* @see #destroySingletons()
|
||||||
*/
|
*/
|
||||||
void preInstantiateSingletons() throws BeansException;
|
void preInstantiateSingletons() throws BeansException;
|
||||||
|
|
|
@ -1102,6 +1102,11 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void prepareSingletonBootstrap() {
|
||||||
|
this.mainThreadPrefix = getThreadNamePrefix();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void preInstantiateSingletons() throws BeansException {
|
public void preInstantiateSingletons() throws BeansException {
|
||||||
if (logger.isTraceEnabled()) {
|
if (logger.isTraceEnabled()) {
|
||||||
|
@ -1114,7 +1119,9 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
||||||
|
|
||||||
// Trigger initialization of all non-lazy singleton beans...
|
// Trigger initialization of all non-lazy singleton beans...
|
||||||
this.preInstantiationThread.set(PreInstantiation.MAIN);
|
this.preInstantiationThread.set(PreInstantiation.MAIN);
|
||||||
this.mainThreadPrefix = getThreadNamePrefix();
|
if (this.mainThreadPrefix == null) {
|
||||||
|
this.mainThreadPrefix = getThreadNamePrefix();
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
List<CompletableFuture<?>> futures = new ArrayList<>();
|
List<CompletableFuture<?>> futures = new ArrayList<>();
|
||||||
for (String beanName : beanNames) {
|
for (String beanName : beanNames) {
|
||||||
|
|
|
@ -936,6 +936,9 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
|
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
|
||||||
|
// Mark current thread for singleton instantiation with applied bootstrap locking.
|
||||||
|
beanFactory.prepareSingletonBootstrap();
|
||||||
|
|
||||||
// Initialize bootstrap executor for this context.
|
// Initialize bootstrap executor for this context.
|
||||||
if (beanFactory.containsBean(BOOTSTRAP_EXECUTOR_BEAN_NAME) &&
|
if (beanFactory.containsBean(BOOTSTRAP_EXECUTOR_BEAN_NAME) &&
|
||||||
beanFactory.isTypeMatch(BOOTSTRAP_EXECUTOR_BEAN_NAME, Executor.class)) {
|
beanFactory.isTypeMatch(BOOTSTRAP_EXECUTOR_BEAN_NAME, Executor.class)) {
|
||||||
|
|
|
@ -31,6 +31,7 @@ import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||||
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
||||||
import org.springframework.beans.testfixture.beans.TestBean;
|
import org.springframework.beans.testfixture.beans.TestBean;
|
||||||
import org.springframework.context.ConfigurableApplicationContext;
|
import org.springframework.context.ConfigurableApplicationContext;
|
||||||
|
import org.springframework.context.weaving.LoadTimeWeaverAware;
|
||||||
import org.springframework.core.SpringProperties;
|
import org.springframework.core.SpringProperties;
|
||||||
import org.springframework.core.testfixture.EnabledForTestGroups;
|
import org.springframework.core.testfixture.EnabledForTestGroups;
|
||||||
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
|
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
|
||||||
|
@ -68,6 +69,16 @@ class BackgroundBootstrapTests {
|
||||||
ctx.close();
|
ctx.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Timeout(10)
|
||||||
|
@EnabledForTestGroups(LONG_RUNNING)
|
||||||
|
void bootstrapWithLoadTimeWeaverAware() {
|
||||||
|
ConfigurableApplicationContext ctx = new AnnotationConfigApplicationContext(LoadTimeWeaverAwareBeanConfig.class);
|
||||||
|
ctx.getBean("testBean1", TestBean.class);
|
||||||
|
ctx.getBean("testBean2", TestBean.class);
|
||||||
|
ctx.close();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Timeout(10)
|
@Timeout(10)
|
||||||
@EnabledForTestGroups(LONG_RUNNING)
|
@EnabledForTestGroups(LONG_RUNNING)
|
||||||
|
@ -266,6 +277,50 @@ class BackgroundBootstrapTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Configuration(proxyBeanMethods = false)
|
||||||
|
static class LoadTimeWeaverAwareBeanConfig {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
LoadTimeWeaverAware loadTimeWeaverAware(ObjectProvider<TestBean> testBean1) {
|
||||||
|
Thread thread = new Thread(testBean1::getObject);
|
||||||
|
thread.start();
|
||||||
|
try {
|
||||||
|
thread.join();
|
||||||
|
}
|
||||||
|
catch (InterruptedException ex) {
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
|
}
|
||||||
|
return (loadTimeWeaver -> {});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public TestBean testBean1(TestBean testBean2) {
|
||||||
|
return new TestBean(testBean2);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean @Lazy
|
||||||
|
public FactoryBean<TestBean> testBean2() {
|
||||||
|
try {
|
||||||
|
Thread.sleep(2000);
|
||||||
|
}
|
||||||
|
catch (InterruptedException ex) {
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
|
}
|
||||||
|
TestBean testBean = new TestBean();
|
||||||
|
return new FactoryBean<>() {
|
||||||
|
@Override
|
||||||
|
public TestBean getObject() {
|
||||||
|
return testBean;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public Class<?> getObjectType() {
|
||||||
|
return testBean.getClass();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Configuration(proxyBeanMethods = false)
|
@Configuration(proxyBeanMethods = false)
|
||||||
static class StrictLockingBeanConfig {
|
static class StrictLockingBeanConfig {
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue