In spring, if a bean implements ApplicationContextAware
, then it is able to access the applicationContext
. Therefore it is able to get other beans.
When spring instantiates beans, it looks for a couple of interfaces like ApplicationContextAware
and InitializingBean
. If they are found, the methods are invoked. E.g. (very simplified)
Class<?> beanClass = beanDefinition.getClass();
Object bean = beanClass.newInstance();
if (bean instanceof ApplicationContextAware) {
((ApplicationContextAware) bean).setApplicationContext(ctx);
}
Note that in newer version it may be better to use annotations, rather than implementing spring-specific interfaces. Now you can simply use:
@Inject // or @Autowired
private ApplicationContext ctx;
Spring source code to explain how ApplicationContextAware work
when you use ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
In AbstractApplicationContext
class,the refresh()
method have the following code:
// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);
enter this method,beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
will add ApplicationContextAwareProcessor to AbstractrBeanFactory.
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
// Tell the internal bean factory to use the context's class loader etc.
beanFactory.setBeanClassLoader(getClassLoader());
beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));
// Configure the bean factory with context callbacks.
beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
...........
When spring initialize bean in AbstractAutowireCapableBeanFactory
,
in method initializeBean
,call applyBeanPostProcessorsBeforeInitialization
to implement the bean post process. the process include inject the applicationContext.
@Override
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
result = beanProcessor.postProcessBeforeInitialization(result, beanName);
if (result == null) {
return result;
}
}
return result;
}
when BeanPostProcessor implement Objectto execute the postProcessBeforeInitialization method,for example ApplicationContextAwareProcessor
that added before.
private void invokeAwareInterfaces(Object bean) {
if (bean instanceof Aware) {
if (bean instanceof EnvironmentAware) {
((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());
}
if (bean instanceof EmbeddedValueResolverAware) {
((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(
new EmbeddedValueResolver(this.applicationContext.getBeanFactory()));
}
if (bean instanceof ResourceLoaderAware) {
((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);
}
if (bean instanceof ApplicationEventPublisherAware) {
((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);
}
if (bean instanceof MessageSourceAware) {
((MessageSourceAware) bean).setMessageSource(this.applicationContext);
}
if (bean instanceof ApplicationContextAware) {
((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
}
}
}
ApplicationContextAware Interface ,the current application context, through which you can invoke the spring container services. We can get current applicationContext instance injected by below method in the class
public void setApplicationContext(ApplicationContext context) throws BeansException.
Interface to be implemented by any object that wishes to be notified of the ApplicationContext that it runs in.
above is excerpted from the Spring doc website https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/context/ApplicationContextAware.html.
So, it seemed to be invoked when Spring container has started, if you want to do something at that time.
It just has one method to set the context, so you will get the context and do something to sth now already in context I think.