How does Spring initialize under the hood ? — Part 3

Minh-Luan H. Phan
4 min readJul 24, 2019

--

If you have not read Part 1, Part 2, please take a look at it before read this article. Because they are related to some events which are the solid based for the process in Part 3. In this part, i will discuss about ContextLoaderListener .

I appreciate every comments which build this topic up. It would be my honor when this topic brings to you some valuable knowledges. And if you observe something interesting about Spring, just inbox or comment below, people are getting smarter by learning, sharing and communicating. It is always the best to learn from each other.

To keep every thing as simple as possible and also keep you out of distraction, i have removed some lines of codes as well as methods. However, it will not affect to our simple demo.

My Contact

Warm up

AbstractAnnotationConfigWebApplicationContext

Swing back to part 1. We have familiared to class AbstractAnnotationConfigWebApplicationContext . Having a look at its parents is very important. The red one is representated for interface and the black is class (or abstract class)

AnnotationConfigWebApplicationContext

AbstractContextLoaderInitializer

In registerContextLoaderListener(ServletContext) , a ContextLoaderListener is instantiated with an argument that is WebApplicationContext (actually, it is AbstractAnnotationConfigWebApplicationContext), this is the reason why i have mentioned its hierarchy above.

Main Discussion

ContextLoaderListener

  • contextInitialized(ServletContextEvent): ContextLoaderListener implement ServletContextListener which take the responsibility for receiving notification when ServletContext initialize or destroy. When ServletContext will be initialized when first request from client comes to our application (first request happened immediately after the process in Part 1). You can see from the snippet above, initWebApplicationContext(ServletContext) will be invoked
  • initWebApplicationContext(ServletContext): this method is to cast our application context from AnnotationConfigWebApplicationContext to ConfigurableWebApplicationContextbecause this interface has some setters such as ServletContext, ServletConfig, nameSpace, themeSource. If you want to config something, these setters must be call before refresh() (this method is our main disscussion today) get call. Then, configureAndRefreshWebApplicationContext() will be called.
  • configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext, ServletContext): in this method, ServletContext and ID of this application context will be set before reresh(), all the property source (.properties files) will be load eagerly to ensure servlet property sources are in place for use in any post-processing or initialization that occurs below prior refresh(). When everything has been done, it's gonna refresh(). We will dive into this method below.

AbstractApplicationContext.refresh()

refresh()

There are 3 phases in this method: pre-initialize (line 14–23), initialize (line 26–44) and post-initialize (line 47–51)

  • prepareReresh(): this method is to set startup date, initialize file .properties (again) and validate it.
  • obtainFreshBeanFactory(): this method is to create BeanFactory (to manage Beans) and load Beans (AnnotatedClass) was registered in getRootConfigClasses() (check Part 1 to know about this method).
obtainFreshBeanFactory()
  • prepareBeanFactory(ConfigurableListableBeanFactory): this method is to add BeanPostProcessor, register Singleton Bean and configure ClassLoader.
prepareBeanFactory(ConfigurableListableBeanFactory)
  • postProcessBeanFactory(ConfigurableListableBeanFactory): this method is to register web-specific scopes: request, session, global session, application, to register web-specific environment bean such as “servletContext”, “servletConfig”, “contextParameters” (take from servletContext.getInitParameter(String), servletConfig.getInitParameter(String)), “contextAttributes” (take from servletContext.getAttribute(String))
postProcessBeanFactory(ConfigurableListableBeanFactory)
  • invokeBeanFactoryPostProcessor(ConfigurableListableBeanFactory): to invoke BeanFactoryPostProcessor (if any). Normally, List<BeanFactoryPostProcessor> will empty, however, developer can use addBeanFactoryPostProcessor(BeanFactoryPostProcessor) to add. BeanFactoryPostProcessor provide a facility which allow modifying the BeanFactory after its standard initialization. At this time, all bean definitions will have loaded (you can find it in beanFactory.beanDefinitionNames), but no bean have been instantiate yet.
  • registerBeanPostProcessors(ConfigurableListableBeanFactory): like BeanFactoryPostProcessor , interface BeanPostProcessor facilitates for modifying Bean before it initializes or after it destroys. There are many ways to gain access to lifecycle of a bean such as using @PostConstruct, @PreDestroy or just init(), destroy() to be more consistent.

There are 5 BeanPostProcessors (by default) that are registered in this methods:
- AutowiredAnnotationBeanPostProcessor: for detecting @Autowire field and also provide “context:annotation-config” and “context:component-scan”
- RequiredAnnotationBeanPostProcessor:
for using @Required annotation which is decorated on setter method.
- CommonAnnotationBeanPostProcessor: supports common Java annotations out of the box, it also support @PostConstruct and @PreDestroy to gain access to bean lifecycle.

- PersistenceAnnotationBeanPostProcessor: that processes PersistenceUnitand PersistenceContext annotations, for injection of the corresponding JPA resources EntityManagerFactory and EntityManager
- InfrastructureAdvisorAutoProxyCreator: for Aspect Oriented Programming

registerBeanPostProcessors(ConfigurableListableBeanFactory)
  • initMessageSource(): MessageSource is a strategy interface for resolving message such as translating from a specifice language to a specific language. There are 2 classes implement interface MessageSource.
initMessageSource()
  • initApplicationEventMulticaster(): interface to be implemented by objects that can manage a number of ApplicationListener object and published event to them.
initApplicationEventMulticaster()
  • registerListeners(): add bean that implement ApplicationListener
registerListeners()
  • finishBeanFactoryInitialization(ConfigurableListableBeanFactory):instantiate all Singleton bean in your WebApplicationContext.
finishBeanFactoryInitialization(ConfigurableListableBeanFactory)
  • finishRefresh(): clear resource cache, apply a lifecycle processor into this context. Publish event ContextRefreshEvent. This is an event that will be invoked when application context get init or refreshed.Actually, it just set timestamp and a source object (AnnotationConfigWebApplicationContext)

LiveBeanView: just a feature which support developer to view beans in IDE, it’s not affect to WebApplicationContext.

finishRefresh()
  • resetCommonCaches(): to clear all cache
resetCommonCaches()

Sum Up

There is pseudocode about what was happened throught out this demo. Just for keeping you on track.

--

--

Minh-Luan H. Phan
Minh-Luan H. Phan

Written by Minh-Luan H. Phan

Do the difficult things while they are easy and do the great things while they are small. A journey of a thousand miles must begin with a single step — Lao Tzu

No responses yet