Article directory
- Pre
- org.springframework.beans.factory.BeanFactoryAware
- Extension point description
- Aware interface
- Execution timing and order of Spring’s built-in Aware interface
- Source code analysis (direct call)
- Source code analysis (BeanPostProcessor call execution sequence)
- Extension point example
Pre
Spring Boot – List of extension interfaces
org.springframework.beans.factory.BeanFactoryAware
package org.springframework.beans.factory; import org.springframework.beans.BeansException; /** * Interface to be implemented by beans that wish to be aware of their * owning {@link BeanFactory}. * * <p>For example, beans can look up collaborating beans via the factory * (Dependency Lookup). Note that most beans will choose to receive references * to collaborating beans via corresponding bean properties or constructor * arguments (Dependency Injection). * * <p>For a list of all bean lifecycle methods, see the * {@link BeanFactory BeanFactory javadocs}. * * @author Rod Johnson * @author Chris Beams * @since 11.03.2003 * @see BeanNameAware * @see BeanClassLoaderAware * @see InitializingBean * @see org.springframework.context.ApplicationContextAware */ public interface BeanFactoryAware extends Aware { /** * Callback that supplies the owning factory to a bean instance. * <p>Invoked after the population of normal bean properties * but before an initialization callback such as * {@link InitializingBean#afterPropertiesSet()} or a custom init-method. * @param beanFactory owning BeanFactory (never {@code null}). * The bean can immediately call methods on the factory. * @throws BeansException in case of initialization errors * @see BeanInitializationException */ void setBeanFactory(BeanFactory beanFactory) throws BeansException; }
Extension point description
The extension point method is setBeanFactory
, and you can get the BeanFactory
attribute.
Usage scenario: You can get BeanFactory
after the bean is instantiated but before it is initialized. At this time, each bean can be specially customized. Or you can get BeanFactory
for caching and use it later.
Aware interface
-
Built-in Aware interface for Spring core and context
ApplicationEventPublisherAware
MessageSourceAware
ResourceLoaderAware
BeanFactoryAware
EnvironmentAware
EmbeddedValueResolverAware
ImportAware
LoadTimeWeaverAware
BeanClassLoaderAware
BeanNameAware
ApplicationContextAware -
Spring web’s built-in Aware interface
ServletContextAware
ServletConfigAware -
Spring’s other built-in Aware interfaces
SchedulerContextAware (spring scheduling)
NotificationPublisherAware (spring jmx export)
BootstrapContextAware (spring jca)
Execution timing and sequence of Spring’s built-in Aware interface
The execution time of the Aware interface must be when the Spring Bean is created.
There are mainly two modes for the implementation of the Aware interface:
- When initializing the Bean (
initializeBean
), directly call the method -> setXXXX BeanPostProcessor -> Object postProcessBeforeInitialization(Object bean, String beanName)
processor.postProcessBeforeInitialization(result, beanName);
Enter
Spring’s built-in core Aware BeanPostProcessor is ApplicationContextAwareProcessor
org.springframework.context.support.ApplicationContextAwareProcessor#postProcessBeforeInitialization
Let’s continue to look at invokeAwareInterfaces(bean);
It can be seen that ApplicationContextAwareProcessor is associated with most of Spring’s built-in Aware interfaces, and their execution order is as follows:
EnvironmentAware -> EmbeddedValueResolverAware -> ResourceLoaderAware -> ApplicationEventPublisherAware -> MessageSourceAware -> ApplicationStartupAware -> ApplicationContextAware
Conclusion: The timing of direct method calls is earlier than the timing of calls through BeanPostProcessor#postProcessBeforeInitialization
Since the calling of the Aware interface is directly affected by BeanPostProcessor
, the execution sequence of BeanPostProcessor
is also the calling sequence of the Aware interface.
Then why did you jump directly to ApplicationContextAwareProcessor
?
Let’s take a look at the setting execution timing of ApplicationContextAwareProcessor.
AbstractApplicationContext#refresh
method
public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { // Prepare this context for refreshing. prepareRefresh(); // Tell the subclass to refresh the internal bean factory. ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // Prepare the bean factory for use in this context. prepareBeanFactory(beanFactory); //....omit the rest of the code }
Continue to see prepareBeanFactory
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) { //....omit the rest of the code // Configure the bean factory with context callbacks. beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this)); //....omit the rest of the code }
You can see beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this)
Here you can see that ApplicationContextAwareProcessor
is directly added to the BeanFactory
first.
Source code analysis (direct call)
org.springframework.context.support.PostProcessorRegistrationDelegate#registerBeanPostProcessors() BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class); org.springframework.beans.factory.support.AbstractBeanFactory#getBean org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBean org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean
In the doCreateBean
method
Focus on
// Initialize the bean instance. Object exposedObject = bean; try { populateBean(beanName, mbd, instanceWrapper); exposedObject = initializeBean(beanName, exposedObject, mbd); }
Enter org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#initializeBean
if (System.getSecurityManager() != null) { AccessController.doPrivileged((PrivilegedAction<Object>) () -> { invokeAwareMethods(beanName, bean); return null; }, getAccessControlContext()); } else { invokeAwareMethods(beanName, bean); }
look
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#invokeAwareMethods private void invokeAwareMethods(String beanName, Object bean) { if (bean instanceof Aware) { if (bean instanceof BeanNameAware) { ((BeanNameAware) bean).setBeanName(beanName); } if (bean instanceof BeanClassLoaderAware) { ClassLoader bcl = getBeanClassLoader(); if (bcl != null) { ((BeanClassLoaderAware) bean).setBeanClassLoader(bcl); } } if (bean instanceof BeanFactoryAware) { ((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this); } } }
See it?
if (bean instanceof BeanFactoryAware) { ((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this); }
From the above code snippets, it can be concluded that the execution order of the Aware interface is
BeanNameAware -> BeanClassLoaderAware -> BeanFactoryAware
The call chain is as follows
org.springframework.context.support.PostProcessorRegistrationDelegate#registerBeanPostProcessors() BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class); org.springframework.beans.factory.support.AbstractBeanFactory#getBean org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBean org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#initializeBean org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#invokeAwareMethods
Source code analysis (BeanPostProcessor call execution sequence)
In fact, it is already in the first screenshot above, let’s take a look at it again
org.springframework.context.support.PostProcessorRegistrationDelegate#registerBeanPostProcessors() BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class); org.springframework.beans.factory.support.AbstractBeanFactory#getBean org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBean org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#initializeBean
Continue to see initializeBean
//....omitted Object wrappedBean = bean; if (mbd == null || !mbd.isSynthetic()) { wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName); } //....omitted @Override public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName) throws BeansException { Object result = existingBean; for (BeanPostProcessor processor : getBeanPostProcessors()) { Object current = processor.postProcessBeforeInitialization(result, beanName); if (current == null) { return result; } result = current; } return result; } public List<BeanPostProcessor> getBeanPostProcessors() { return this.beanPostProcessors; } private final List<BeanPostProcessor> beanPostProcessors = new CopyOnWriteArrayList<>();
It can be seen that beanPostProcessors
is an ordered list associated with the BeanFactory
. The data source of this list is the ConfigurableBeanFactory#addBeanPostProcessor(BeanPostProcessor beanPostProcessor)
method.
Return to AbstractApplicationContext#refresh()
registerBeanPostProcessors(beanFactory);//Inject BeanPost into BeanFactory
The final executor of registering BeanPostProcessor
is PostProcessorRegistrationDelegate.registerBeanPostProcessors
The ordering rules are as follows (for the BeanPostProcessor BeanDefinition
belonging to the BeanFactory
):
String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);
- Implemented the PriorityOrdered interface with the highest priority, and then sorted by order Small -> Large
- The second is to implement the Ordered interface, and then sort by order small -> large
- Others are based on the BeanDefinition Spring registration order.
Of course, you can also configure the BeanFactory through BeanFactoryPostProcessor
, for example ConfigurationClassPostProcessor
@Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) { int factoryId = System.identityHashCode(beanFactory); if (this.factoriesPostProcessed.contains(factoryId)) { throw new IllegalStateException( "postProcessBeanFactory already called on this post-processor against " + beanFactory); } this.factoriesPostProcessed.add(factoryId); if (!this.registriesPostProcessed.contains(factoryId)) { // BeanDefinitionRegistryPostProcessor hook apparently not supported... // Simply call processConfigurationClasses lazily at this point then. processConfigBeanDefinitions((BeanDefinitionRegistry) beanFactory); } enhanceConfigurationClasses(beanFactory); //Register to add ImportAware interface processor beanFactory.addBeanPostProcessor(new ImportAwareBeanPostProcessor(beanFactory)); } private static class ImportAwareBeanPostProcessor extends InstantiationAwareBeanPostProcessorAdapter { .... @Override public Object postProcessBeforeInitialization(Object bean, String beanName) { if (bean instanceof ImportAware) { ImportRegistry ir = this.beanFactory.getBean(IMPORT_REGISTRY_BEAN_NAME, ImportRegistry.class); AnnotationMetadata importingClass = ir.getImportingClassFor(ClassUtils.getUserClass(bean).getName()); if (importingClass != null) { //ImportAware#setImportMetadata call ((ImportAware) bean).setImportMetadata(importingClass); } } return bean; } }
It can be seen from the above that the execution order of ImportAware
is executed after the Aware interfaces associated with ApplicationContextAwareProcessor
.
In fact, there is also a LoadTimeWeaverAwareProcessor
AbstractApplicationContext#prepareBeanFactory // Detect a LoadTimeWeaver and prepare for weaving, if found. if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {//Conditional injection, the bean or bean definition must exist beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory)); // Set a temporary ClassLoader for type matching. beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader())); }
The current Aware interface execution sequence is as follows:
BeanNameAware -> BeanClassLoaderAware -> BeanFactoryAware -> EnvironmentAware -> EmbeddedValueResolverAware -> ResourceLoaderAware -> ApplicationEventPublisherAware -> MessageSourceAware -> ApplicationContextAware -> ImportAware -> LoadTimeWeaverAware
Extension point example
package com.artisan.bootspringextend.testextends; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactoryAware; import org.springframework.context.annotation.Configuration; /** * @author little craftsman * @version 1.0 * @description: TODO * @date 2022/12/4 9:53 * @mark: show me the code, change the world */ @Slf4j @Configuration public class ExtendBeanFactoryAware implements BeanFactoryAware { @Override public void setBeanFactory(BeanFactory beanFactory) throws BeansException { log.info("----->ExtendBeanFactoryAware {}" , beanFactory.getBean(ExtendBeanFactoryAware.class).getClass().getSimpleName()); } }
Let’s look at the second, more complete extension
package com.artisan.bootspringextend.testextends; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanClassLoaderAware; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactoryAware; import org.springframework.beans.factory.BeanNameAware; import org.springframework.context.*; import org.springframework.context.annotation.ImportAware; import org.springframework.context.weaving.LoadTimeWeaverAware; import org.springframework.core.env.Environment; import org.springframework.core.io.ResourceLoader; import org.springframework.core.metrics.ApplicationStartup; import org.springframework.core.type.AnnotationMetadata; import org.springframework.instrument.classloading.LoadTimeWeaver; import org.springframework.stereotype.Component; import org.springframework.util.StringValueResolver; /** * @author little craftsman * @version 1.0 * @description: TODO * @date 2022/12/4 11:02 * @mark: show me the code, change the world */ @Slf4j @Component public class ExtendInvokeAware implements BeanNameAware, BeanClassLoaderAware, BeanFactoryAware, EnvironmentAware, EmbeddedValueResolverAware, ResourceLoaderAware, ApplicationEventPublisherAware, MessageSourceAware,ApplicationStartupAware, ApplicationContextAware, ImportAware, LoadTimeWeaverAware { @Override public void setBeanClassLoader(ClassLoader classLoader) { log.info(" ------> BeanClassLoaderAware::setBeanClassLoader invoked"); } @Override public void setBeanFactory(BeanFactory beanFactory) throws BeansException { log.info(" ------> BeanFactoryAware::setBeanFactory invoked"); } @Override public void setBeanName(String s) { log.info(" ------> BeanNameAware::setBeanName invoked"); } @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { log.info(" ------> ApplicationContextAware::setApplicationContext invoked"); } @Override public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) { log.info(" ------> ApplicationEventPublisherAware::setApplicationEventPublisher invoked"); } @Override public void setEmbeddedValueResolver(StringValueResolver resolver) { log.info(" ------> EmbeddedValueResolverAware::setEmbeddedValueResolver invoked"); } @Override public void setEnvironment(Environment environment) { log.info(" ------> EnvironmentAware::setEnvironment invoked"); } @Override public void setMessageSource(MessageSource messageSource) { log.info(" ------> MessageSourceAware::setMessageSource invoked"); } @Override public void setResourceLoader(ResourceLoader resourceLoader) { log.info(" ------> ResourceLoaderAware::setResourceLoader invoked"); } @Override public void setApplicationStartup(ApplicationStartup applicationStartup) { log.info(" ------> ApplicationStartup::setApplicationStartup invoked"); } @Override public void setImportMetadata(AnnotationMetadata importMetadata) { log.info(" ------> ImportAware::setImportMetadata invoked"); } @Override public void setLoadTimeWeaver(LoadTimeWeaver loadTimeWeaver) { log.info(" ------> LoadTimeWeaverAware::setLoadTimeWeaver invoked"); } }
Output results
. ____ _ __ _ _ /\ / ___'_ __ _ _(_)_ __ __ _
( ( )___ | ‘_ | ‘| | ’ / ` |
/ )| |)| | | | | || (| | ) ) ) )
‘ || .__|| ||| |, | / / //
=========||==============|/=// em>/_/
::Spring Boot:: (v2.4.2)
2022-12-04 19:14:25.103 INFO 12832 --- [main] .b.t.ExtendApplicationContextInitializer : ExtendApplicationContextInitializer # initialize Called 2022-12-04 19:14:25.110 INFO 12832 --- [main] c.a.b.BootSpringExtendApplication : Starting BootSpringExtendApplication using Java 1.8.0_261 on LAPTOP-JF3RBRRJ with PID 12832 (D:IdeaProjectsoot2oot-spring-extend argetclasses started by artisan in D: IdeaProjectsoot2) 2022-12-04 19:14:25.111 INFO 12832 --- [main] c.a.b.BootSpringExtendApplication: No active profile set, falling back to default profiles: default 2022-12-04 19:14:25.444 INFO 12832 --- [main] c.a.b.testextends.ExtendInvokeAware: ------> BeanNameAware::setBeanName invoked 2022-12-04 19:14:25.444 INFO 12832 --- [main] c.a.b.testextends.ExtendInvokeAware: ------> BeanClassLoaderAware::setBeanClassLoader invoked 2022-12-04 19:14:25.444 INFO 12832 --- [main] c.a.b.testextends.ExtendInvokeAware: ------> BeanFactoryAware::setBeanFactory invoked 2022-12-04 19:14:25.444 INFO 12832 --- [main] c.a.b.testextends.ExtendInvokeAware: ------> EnvironmentAware::setEnvironment invoked 2022-12-04 19:14:25.444 INFO 12832 --- [main] c.a.b.testextends.ExtendInvokeAware: ------> EmbeddedValueResolverAware::setEmbeddedValueResolver invoked 2022-12-04 19:14:25.444 INFO 12832 --- [main] c.a.b.testextends.ExtendInvokeAware: ------> ResourceLoaderAware::setResourceLoader invoked 2022-12-04 19:14:25.444 INFO 12832 --- [main] c.a.b.testextends.ExtendInvokeAware: ------> ApplicationEventPublisherAware::setApplicationEventPublisher invoked 2022-12-04 19:14:25.444 INFO 12832 --- [main] c.a.b.testextends.ExtendInvokeAware: ------> MessageSourceAware::setMessageSource invoked 2022-12-04 19:14:25.444 INFO 12832 --- [main] c.a.b.testextends.ExtendInvokeAware: ------> ApplicationStartup::setApplicationStartup invoked 2022-12-04 19:14:25.444 INFO 12832 --- [main] c.a.b.testextends.ExtendInvokeAware: ------> ApplicationContextAware::setApplicationContext invoked 2022-12-04 19:14:25.529 INFO 12832 --- [main] c.a.b.BootSpringExtendApplication : Started BootSpringExtendApplication in 0.747 seconds (JVM running for 1.792) Process finished with exit code 0