How does Spring initialize under the hood ? — Part 1

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

--

Who will take responsibility to create Spring Container ?. To answer this question, we will dive deeply into to the most ancient package: java.util, to reveal the Secret of Spring Framework.

To simplify and keep you on track with what i did, i have removed some unused method as well as some lines of code, of course, it will not affect to our demo. So, if you want to know a full version of these class. Just open your IDE and explore it by yourself. Believe me, it is absolutely amazing to know how they structure a project by using interface and abstract class.

I appreciate every comments which build this topic up. It would be my honor when this topic brings to you some valuable knowledge. 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.

My Contact

Warm Up

Main Discussion

Java SPI (Java Service Provider Interface) and ServiceLoader

SPI and ServiceLoader are two important keywords for creating extensible application. You can enhance your (legacy) application without influences to your original code base. And it uses technique Dependency Injection but for internal purpose like initializing Spring Framework, anything happened behind the scene.

At first, in this section, I will explain about Java SPI first because class ServiceLoader use SPI to instantiate object.

Java SPI

There are 2 terminologies related to SPI.

  • Service Provider Interface: is an interface or abstract class which act as endpoint to the service.
  • Service Provider:
    - Is specific implementation of the SPI.
    - Is configured and identified through a provider configuration file which we put in the resource directory META-INF/services in file jar. The configuration file name is the fully-qualified name of the SPI and his content is the fully-qualified name of the SPI implementation (Service Provider).
    - The only requirement enforced here is that Service Provider classes must have a zero-argument constructor so that they may be instantiated during lookup.

java.util.ServiceLoader

ServiceLoader class helps you to find, load user service providers by searching on application’s classpath. Thanks to the Runtime’s Service Provider Lookup Mechanism, ServiceLoader will find any jar file whose folder tree is META-INF/services. File’s name in that folder ( is interface) and file’s content (is implementation of interface) will be used to instantiate object.

For example, in the previous picture, there is a file named javax.servlet.ServletContainerInitializer (SPI) and the file’s content is org.springframework.web.SpringServletContainerInitializer (Service Provider). It means when we run application, SpringServletContainerInitializer will be loaded to initialize Spring Container. And you know, Spring Container is core component of Spring Framework.

We will discuss about ServletContainerInitializer and SpringServletContainerInitializer below.

javax.servlet.ServletContainerInitializer

Definition from Oracle Document:
interface ServletContainerInitializer is to allow a library/runtime to be notified of a web application’s startup phase and perform any required programmatic registration of servlet, filter and listener.

For further details, ServletContainerInitializer takes a vital role. Its method onStartup(Set<Class<?>>, ServletContext) will be invoked before init() method of Servlet or contextInitialized() of ServletListener. So it is the reason why it can perform any programmatic registration related to initialize another classes.

Implementation of this interface may be annotated with (in this case) @HandlesTypes(WebApplicationInitializer.class). The role of @HandlesTypes is to look for in the application’s classpath to find any class which is a subclass of WebApplicationInitializer. Then theses class will be passed as parameter of method onStartUp(Set<Class<?>>, ServletContext)

Moreover, any class implement ServletContainerInitializer must be declared by JAR file resource located inside the META-INF/services directory. I have explained the reason on above section.

org.springframework.web.SpringServletContainerIntializer

It is very important to annotated @HandlesTypes(). Without it, console will notify “No Spring WebApplicationInitializer types detected on classpath” and
onStartup(Set<Class<?>> , ServletContext) method will over.

In this method:

First, onStartUp() method receive 2 params:

  • Set<Class<?>> webApplicationIntializerClasses: a collection of sub classes whose parent is WebApplicationInitializer (because this method is annotated with @HandlesTypes(WebApplicationInitializer.class))
  • ServletContext: Root Application Context (in Spring) of this application

Then, a LinkedList of WebApplicationInitializer is instantiate for storing classes which are going to instantiate and invoke onStartup(ServletContext).

webApplicationIntializerClasses will be traversed. A suitable class is:

  • Not an interface: !waiClass.isInterface()
  • Not a abstract class: !Modifier.isAbstract(waiClass.getModifiers())
  • A subclass of WebApplicationInitializer: WebApplicationInitializer.class.isAssignableFrom(waiClass)

If a class passes all of these above conditions, it will be instantiate through ReflectionUtils.accessibleConstructor(waiClass).newInstance() before add to linked list.

For further details about ReflectionUtils.accessibleConstructor(waiClass).newInstance(). It will access to constructor of waiClass and then new with keyword .newInstance(). That is the reason why Service Provider can not have argument constructor.

Then, a LinkedList will be sorted based on @Order() annotation. If you want to set initial order of these WebApplicationInitializer. You can decorate @Order() at these class.

Finally, the LinkedList will be traversed and each item will invoked onStartup(ServletContext).

Let swing back to my previous topic. Did you remember there is a method named onStartup(ServletContext) of WebApplicationInitializer ?.

Now, the truth have been revealed, finally, a linked list of WebApplicationInitializer will be traversed and each of instance will invoke onStartup(ServletContext) method and pass ServletContext as parameter.

Explanation

At first, ServiceLoader will scan all of exist jar file on application classpath based on Runtime’s Service Provider Lookup Mechanism, i will assume that it found spring-web.jar whose directory form is META-INF/services/javax.servlet.ServletContainerInitializer. Then, ServiceLoader with static method load(Class<S> service) will load interface ServletContainerInitializer with its implementation and
onStartup(Set<Class<?>> c, ServletContext) is invoked. And then, onStartup(ServletContext) of subclasses of WebApplicationInitializer will be invoked in order.

--

--

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