Add BeanFactoryInitializer callback before preInstantiateSingletons
Closes gh-32836
This commit is contained in:
		
							parent
							
								
									f10caf6aa6
								
							
						
					
					
						commit
						28eb9aebcf
					
				|  | @ -0,0 +1,41 @@ | ||||||
|  | /* | ||||||
|  |  * Copyright 2002-2024 the original author or authors. | ||||||
|  |  * | ||||||
|  |  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
|  |  * you may not use this file except in compliance with the License. | ||||||
|  |  * You may obtain a copy of the License at | ||||||
|  |  * | ||||||
|  |  *      https://www.apache.org/licenses/LICENSE-2.0 | ||||||
|  |  * | ||||||
|  |  * Unless required by applicable law or agreed to in writing, software | ||||||
|  |  * distributed under the License is distributed on an "AS IS" BASIS, | ||||||
|  |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||
|  |  * See the License for the specific language governing permissions and | ||||||
|  |  * limitations under the License. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | package org.springframework.beans.factory; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Callback interface for initializing a Spring {@link ListableBeanFactory} | ||||||
|  |  * prior to entering the singleton pre-instantiation phase. Can be used to | ||||||
|  |  * trigger early initialization of specific beans before regular singletons. | ||||||
|  |  * | ||||||
|  |  * <p>Can be programmatically applied to a {@code ListableBeanFactory} instance. | ||||||
|  |  * In an {@code ApplicationContext}, beans of type {@code BeanFactoryInitializer} | ||||||
|  |  * will be autodetected and automatically applied to the underlying bean factory. | ||||||
|  |  * | ||||||
|  |  * @author Juergen Hoeller | ||||||
|  |  * @since 6.2 | ||||||
|  |  * @param <F> the bean factory type | ||||||
|  |  * @see org.springframework.beans.factory.config.ConfigurableListableBeanFactory#preInstantiateSingletons() | ||||||
|  |  */ | ||||||
|  | public interface BeanFactoryInitializer<F extends ListableBeanFactory> { | ||||||
|  | 
 | ||||||
|  | 	/** | ||||||
|  | 	 * Initialize the given bean factory. | ||||||
|  | 	 * @param beanFactory the bean factory to bootstrap | ||||||
|  | 	 */ | ||||||
|  | 	void initialize(F beanFactory); | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | @ -1,5 +1,5 @@ | ||||||
| /* | /* | ||||||
|  * Copyright 2002-2020 the original author or authors. |  * Copyright 2002-2024 the original author or authors. | ||||||
|  * |  * | ||||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); |  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
|  * you may not use this file except in compliance with the License. |  * you may not use this file except in compliance with the License. | ||||||
|  | @ -44,7 +44,7 @@ public interface ApplicationContextInitializer<C extends ConfigurableApplication | ||||||
| 
 | 
 | ||||||
| 	/** | 	/** | ||||||
| 	 * Initialize the given application context. | 	 * Initialize the given application context. | ||||||
| 	 * @param applicationContext the application to configure | 	 * @param applicationContext the application context to bootstrap | ||||||
| 	 */ | 	 */ | ||||||
| 	void initialize(C applicationContext); | 	void initialize(C applicationContext); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -37,6 +37,7 @@ import org.apache.commons.logging.LogFactory; | ||||||
| import org.springframework.beans.BeansException; | import org.springframework.beans.BeansException; | ||||||
| import org.springframework.beans.CachedIntrospectionResults; | import org.springframework.beans.CachedIntrospectionResults; | ||||||
| import org.springframework.beans.factory.BeanFactory; | import org.springframework.beans.factory.BeanFactory; | ||||||
|  | import org.springframework.beans.factory.BeanFactoryInitializer; | ||||||
| import org.springframework.beans.factory.NoSuchBeanDefinitionException; | import org.springframework.beans.factory.NoSuchBeanDefinitionException; | ||||||
| import org.springframework.beans.factory.ObjectProvider; | import org.springframework.beans.factory.ObjectProvider; | ||||||
| import org.springframework.beans.factory.config.AutowireCapableBeanFactory; | import org.springframework.beans.factory.config.AutowireCapableBeanFactory; | ||||||
|  | @ -932,6 +933,7 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader | ||||||
| 	 * Finish the initialization of this context's bean factory, | 	 * Finish the initialization of this context's bean factory, | ||||||
| 	 * initializing all remaining singleton beans. | 	 * initializing all remaining singleton beans. | ||||||
| 	 */ | 	 */ | ||||||
|  | 	@SuppressWarnings("unchecked") | ||||||
| 	protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) { | 	protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) { | ||||||
| 		// 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) && | ||||||
|  | @ -954,6 +956,12 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader | ||||||
| 			beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal)); | 			beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal)); | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
|  | 		// Call BeanFactoryInitializer beans early to allow for initializing specific other beans early. | ||||||
|  | 		String[] initializerNames = beanFactory.getBeanNamesForType(BeanFactoryInitializer.class, false, false); | ||||||
|  | 		for (String initializerName : initializerNames) { | ||||||
|  | 			beanFactory.getBean(initializerName, BeanFactoryInitializer.class).initialize(beanFactory); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
| 		// Initialize LoadTimeWeaverAware beans early to allow for registering their transformers early. | 		// Initialize LoadTimeWeaverAware beans early to allow for registering their transformers early. | ||||||
| 		String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false); | 		String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false); | ||||||
| 		for (String weaverAwareName : weaverAwareNames) { | 		for (String weaverAwareName : weaverAwareNames) { | ||||||
|  |  | ||||||
|  | @ -19,55 +19,30 @@ package org.springframework.test.context.support; | ||||||
| import org.apache.commons.logging.Log; | import org.apache.commons.logging.Log; | ||||||
| import org.apache.commons.logging.LogFactory; | import org.apache.commons.logging.LogFactory; | ||||||
| 
 | 
 | ||||||
| import org.springframework.beans.factory.BeanFactory; | import org.springframework.beans.factory.BeanFactoryInitializer; | ||||||
| import org.springframework.beans.factory.BeanFactoryAware; |  | ||||||
| import org.springframework.beans.factory.InitializingBean; |  | ||||||
| import org.springframework.beans.factory.ListableBeanFactory; | import org.springframework.beans.factory.ListableBeanFactory; | ||||||
| import org.springframework.context.weaving.LoadTimeWeaverAware; |  | ||||||
| import org.springframework.instrument.classloading.LoadTimeWeaver; |  | ||||||
| import org.springframework.lang.Nullable; |  | ||||||
| import org.springframework.test.context.DynamicPropertySource; | import org.springframework.test.context.DynamicPropertySource; | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * Internal component which eagerly initializes beans created by {@code @Bean} |  * Internal component which eagerly initializes beans created by {@code @Bean} | ||||||
|  * factory methods annotated with {@link DynamicPropertySource @DynamicPropertySource}. |  * factory methods annotated with {@link DynamicPropertySource @DynamicPropertySource}. | ||||||
|  * |  * | ||||||
|  * <p>This class implements {@link LoadTimeWeaverAware} since doing so is |  | ||||||
|  * currently the only way to have a component eagerly initialized before the |  | ||||||
|  * {@code ConfigurableListableBeanFactory.preInstantiateSingletons()} phase. |  | ||||||
|  * |  | ||||||
|  * @author Sam Brannen |  * @author Sam Brannen | ||||||
|  * @since 6.2 |  * @since 6.2 | ||||||
|  */ |  */ | ||||||
| class DynamicPropertySourceBeanInitializer implements BeanFactoryAware, InitializingBean, LoadTimeWeaverAware { | class DynamicPropertySourceBeanInitializer implements BeanFactoryInitializer<ListableBeanFactory> { | ||||||
| 
 | 
 | ||||||
| 	private static final Log logger = LogFactory.getLog(DynamicPropertySourceBeanInitializer.class); | 	private static final Log logger = LogFactory.getLog(DynamicPropertySourceBeanInitializer.class); | ||||||
| 
 | 
 | ||||||
| 	@Nullable |  | ||||||
| 	private BeanFactory beanFactory; |  | ||||||
| 
 |  | ||||||
| 
 | 
 | ||||||
| 	@Override | 	@Override | ||||||
| 	public void setBeanFactory(BeanFactory beanFactory) { | 	public void initialize(ListableBeanFactory beanFactory) { | ||||||
| 		this.beanFactory = beanFactory; | 		for (String name : beanFactory.getBeanNamesForAnnotation(DynamicPropertySource.class)) { | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	@Override |  | ||||||
| 	public void afterPropertiesSet() { |  | ||||||
| 		if (!(this.beanFactory instanceof ListableBeanFactory lbf)) { |  | ||||||
| 			throw new IllegalStateException("BeanFactory must be set and must be a ListableBeanFactory"); |  | ||||||
| 		} |  | ||||||
| 		for (String name : lbf.getBeanNamesForAnnotation(DynamicPropertySource.class)) { |  | ||||||
| 			if (logger.isDebugEnabled()) { | 			if (logger.isDebugEnabled()) { | ||||||
| 				logger.debug("Eagerly initializing @DynamicPropertySource bean '%s'".formatted(name)); | 				logger.debug("Eagerly initializing @DynamicPropertySource bean '%s'".formatted(name)); | ||||||
| 			} | 			} | ||||||
| 			this.beanFactory.getBean(name); | 			beanFactory.getBean(name); | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	@Override |  | ||||||
| 	public void setLoadTimeWeaver(LoadTimeWeaver loadTimeWeaver) { |  | ||||||
| 		// no-op |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| } | } | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue