What is ApplicationContext?
It internally creates a BeanFactory, configures it for us and does additional things which are very in an application’s lifecycle. In this article, I will go through some of these additional pieces.
In the below diagram all the boxes in blue are the additional stuff that ApplicationContext takes care of and the grey boxes are what BeanFactory handles.
ApplicationContextAwareProcessor and Environment beans
- ApplicationContext automatically adds a BeanPostProcessor to the container called ApplicationContextAwareProcessor. Beans which implement ApplicationContextAware are scanned and
setApplicationContext()
is invoked to set the context. - ApplicationContext automatically registers the environment beans for us. Below is a context file doesn’t contain any environment specific beans but we still can access those beans.
springDemoContext.xml
<beans> <bean id="testBean" class="springdemo.TestBean"/> <bean id="beanPostProcessor" class="springdemo.TestBeanProcessor"/> <bean id="beanFactoryPostProcessor" class="springdemo.TestBeanFactoryProcessor"/> </beans>
Test case
@Test public void testAppContext() throws Exception { ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("springDemoContext.xml"); assertTrue(ctx.containsBean("environment")); assertTrue(ctx.containsBean("systemProperties")); assertTrue(ctx.containsBean("systemEnvironment")); }
MessageSource
ApplicationEventMulticaster
Instantiates non-lazy Singleton
The default behavior for ApplicationContext implementations is to eagerly pre-instantiate all singleton beans at startup whereas in case of BeanFactory it will instantiate only when you call getBean(). Any issues with bean configuration, we will come to know as soon as the context is created instead of coming to know at runtime.
Lifecycle Flow
Just to summarize with an example, I have here a TestBean that implements all the important interfaces and then I create an ApplicationContext. In each callback method I have a system output to trace the lifecycle flow from creation to closure of the context. If you want to see the bean’s lifecycle diagram click here.
- BeanNameAware
- BeanClassLoaderAware
- ApplicationContextAware
- BeanFactoryAware
- Lifecycle
- ApplicationListener
- DisposableBean
- InitializingBean
TestBean
package springdemo; import org.springframework.beans.BeansException; import org.springframework.beans.factory.*; import org.springframework.context.*; public class TestBean implements BeanNameAware, BeanClassLoaderAware, ApplicationContextAware, BeanFactoryAware, Lifecycle, ApplicationListener, DisposableBean, InitializingBean { String name; public BeanFactory getBeanFactory() { return beanFactory; } ApplicationContext context; ClassLoader beanClassLoader; String beanName; BeanFactory beanFactory; public void setName(String name) { this.name = name; } public String getName() { return name; } @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { System.out.println("Configure bean: set ApplicationContextn"); context = applicationContext; } @Override public void setBeanClassLoader(ClassLoader classLoader) { System.out.println("Configure bean: set Bean's classLoadern"); beanClassLoader = classLoader; } @Override public void setBeanName(String name) { System.out.println("Configure bean: set Bean namen"); beanName = name; } public ApplicationContext getContext() { return context; } public ClassLoader getBeanClassLoader() { return beanClassLoader; } public String getBeanName() { return beanName; } @Override public void setBeanFactory(BeanFactory factory) throws BeansException { System.out.println("Configure bean: set Bean factoryn"); beanFactory = factory; } @Override public void start() { System.out.println("start " + getBeanName() + "n"); } @Override public void stop() { System.out.println("stop " + getBeanName() + "n"); } @Override public boolean isRunning() { return true; } @Override public void onApplicationEvent(ApplicationEvent event) { System.out.println("bean " + beanName + " receives " + event.getClass() + "n"); } @Override public void destroy() throws Exception { System.out.println("bean " + beanName + " destroyedn"); } @Override public void afterPropertiesSet() throws Exception { System.out.println("bean " + beanName + " afterPropertiesSet is calledn"); } }
Test case below creates an application context and checks whether the default beans are loaded.
@Test public void testAppContext() throws Exception { ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("/springdemo/springDemoContext.xml"); assertTrue(ctx.containsBean("environment")); assertTrue(ctx.containsBean("systemProperties")); assertTrue(ctx.containsBean("systemEnvironment")); assertTrue(ctx.containsBean("messageSource")); assertTrue(ctx.containsBean("applicationEventMulticaster")); assertTrue(ctx.containsBean("lifecycleProcessor")); }
Output
bean factory post processor Configure bean: set Bean name Configure bean: set Bean's classLoader Configure bean: set Bean factory Configure bean: set ApplicationContext bean testBean post processor before init bean testBean afterPropertiesSet is called bean testBean post processor after init bean testBean receives class org.springframework.context.event.ContextRefreshedEvent bean testBean receives class org.springframework.context.event.ContextClosedEvent stop testBean bean testBean destroyed