Skip to content

Commit 28eb9ae

Browse files
committed
Add BeanFactoryInitializer callback before preInstantiateSingletons
Closes gh-32836
1 parent f10caf6 commit 28eb9ae

File tree

4 files changed

+56
-32
lines changed

4 files changed

+56
-32
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/*
2+
* Copyright 2002-2024 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.beans.factory;
18+
19+
/**
20+
* Callback interface for initializing a Spring {@link ListableBeanFactory}
21+
* prior to entering the singleton pre-instantiation phase. Can be used to
22+
* trigger early initialization of specific beans before regular singletons.
23+
*
24+
* <p>Can be programmatically applied to a {@code ListableBeanFactory} instance.
25+
* In an {@code ApplicationContext}, beans of type {@code BeanFactoryInitializer}
26+
* will be autodetected and automatically applied to the underlying bean factory.
27+
*
28+
* @author Juergen Hoeller
29+
* @since 6.2
30+
* @param <F> the bean factory type
31+
* @see org.springframework.beans.factory.config.ConfigurableListableBeanFactory#preInstantiateSingletons()
32+
*/
33+
public interface BeanFactoryInitializer<F extends ListableBeanFactory> {
34+
35+
/**
36+
* Initialize the given bean factory.
37+
* @param beanFactory the bean factory to bootstrap
38+
*/
39+
void initialize(F beanFactory);
40+
41+
}

spring-context/src/main/java/org/springframework/context/ApplicationContextInitializer.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2020 the original author or authors.
2+
* Copyright 2002-2024 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -44,7 +44,7 @@ public interface ApplicationContextInitializer<C extends ConfigurableApplication
4444

4545
/**
4646
* Initialize the given application context.
47-
* @param applicationContext the application to configure
47+
* @param applicationContext the application context to bootstrap
4848
*/
4949
void initialize(C applicationContext);
5050

spring-context/src/main/java/org/springframework/context/support/AbstractApplicationContext.java

+8
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
import org.springframework.beans.BeansException;
3838
import org.springframework.beans.CachedIntrospectionResults;
3939
import org.springframework.beans.factory.BeanFactory;
40+
import org.springframework.beans.factory.BeanFactoryInitializer;
4041
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
4142
import org.springframework.beans.factory.ObjectProvider;
4243
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
@@ -932,6 +933,7 @@ protected void registerListeners() {
932933
* Finish the initialization of this context's bean factory,
933934
* initializing all remaining singleton beans.
934935
*/
936+
@SuppressWarnings("unchecked")
935937
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
936938
// Initialize bootstrap executor for this context.
937939
if (beanFactory.containsBean(BOOTSTRAP_EXECUTOR_BEAN_NAME) &&
@@ -954,6 +956,12 @@ protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory b
954956
beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal));
955957
}
956958

959+
// Call BeanFactoryInitializer beans early to allow for initializing specific other beans early.
960+
String[] initializerNames = beanFactory.getBeanNamesForType(BeanFactoryInitializer.class, false, false);
961+
for (String initializerName : initializerNames) {
962+
beanFactory.getBean(initializerName, BeanFactoryInitializer.class).initialize(beanFactory);
963+
}
964+
957965
// Initialize LoadTimeWeaverAware beans early to allow for registering their transformers early.
958966
String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
959967
for (String weaverAwareName : weaverAwareNames) {

spring-test/src/main/java/org/springframework/test/context/support/DynamicPropertySourceBeanInitializer.java

+5-30
Original file line numberDiff line numberDiff line change
@@ -19,55 +19,30 @@
1919
import org.apache.commons.logging.Log;
2020
import org.apache.commons.logging.LogFactory;
2121

22-
import org.springframework.beans.factory.BeanFactory;
23-
import org.springframework.beans.factory.BeanFactoryAware;
24-
import org.springframework.beans.factory.InitializingBean;
22+
import org.springframework.beans.factory.BeanFactoryInitializer;
2523
import org.springframework.beans.factory.ListableBeanFactory;
26-
import org.springframework.context.weaving.LoadTimeWeaverAware;
27-
import org.springframework.instrument.classloading.LoadTimeWeaver;
28-
import org.springframework.lang.Nullable;
2924
import org.springframework.test.context.DynamicPropertySource;
3025

3126
/**
3227
* Internal component which eagerly initializes beans created by {@code @Bean}
3328
* factory methods annotated with {@link DynamicPropertySource @DynamicPropertySource}.
3429
*
35-
* <p>This class implements {@link LoadTimeWeaverAware} since doing so is
36-
* currently the only way to have a component eagerly initialized before the
37-
* {@code ConfigurableListableBeanFactory.preInstantiateSingletons()} phase.
38-
*
3930
* @author Sam Brannen
4031
* @since 6.2
4132
*/
42-
class DynamicPropertySourceBeanInitializer implements BeanFactoryAware, InitializingBean, LoadTimeWeaverAware {
33+
class DynamicPropertySourceBeanInitializer implements BeanFactoryInitializer<ListableBeanFactory> {
4334

4435
private static final Log logger = LogFactory.getLog(DynamicPropertySourceBeanInitializer.class);
4536

46-
@Nullable
47-
private BeanFactory beanFactory;
48-
49-
50-
@Override
51-
public void setBeanFactory(BeanFactory beanFactory) {
52-
this.beanFactory = beanFactory;
53-
}
5437

5538
@Override
56-
public void afterPropertiesSet() {
57-
if (!(this.beanFactory instanceof ListableBeanFactory lbf)) {
58-
throw new IllegalStateException("BeanFactory must be set and must be a ListableBeanFactory");
59-
}
60-
for (String name : lbf.getBeanNamesForAnnotation(DynamicPropertySource.class)) {
39+
public void initialize(ListableBeanFactory beanFactory) {
40+
for (String name : beanFactory.getBeanNamesForAnnotation(DynamicPropertySource.class)) {
6141
if (logger.isDebugEnabled()) {
6242
logger.debug("Eagerly initializing @DynamicPropertySource bean '%s'".formatted(name));
6343
}
64-
this.beanFactory.getBean(name);
44+
beanFactory.getBean(name);
6545
}
6646
}
6747

68-
@Override
69-
public void setLoadTimeWeaver(LoadTimeWeaver loadTimeWeaver) {
70-
// no-op
71-
}
72-
7348
}

0 commit comments

Comments
 (0)