Sunday, July 06, 2014

Hooking Into Container and Bean Life Cycle in Spring.

"What is the difference between BeanFactoryPostProcessor and BeanPostProcesser" This, said one of my colleagues, was part of his interview question, a question to which he promptly replied: "I don't know".

Once you pass the stage of actually getting Spring to work, passing the configuration huddle, in no time, the next couple of things you would probably run into would involve using or hooking into the various life-cycles in Spring and you start seeing things like BeanFactoryPostProcessor, BeanPostProcessor, DisposableBean, InitialzingBean, PostConstruct etc, which all seems to be callbacks mechanism that enables you plug in, somehow, into all the magic going on in Spring.

...And probably just like me, it all starts feeling like too much to grasp...Also, sooner or later, you run into the *Aware sets of interfaces too...

Dang! What are all these, How do they fit into the picture? I just want to write a web application, why do I have to grapple with all these what not?

I initially had all these concepts swirling all about without having any concrete mental model to attach them to or a good understanding of what actually is going on. I knew about the @PostConstruct annotation and maybe what it does, I also have come across various *Post Processors and maybe the IntializingBean interface a couple of times, but actually grokking and understanding where they fit did not happen until after spending some time working with other parts of Spring which allowed for a broader view of what is going, helping create some sort of mental model.



Inversion Of Control and Containers.

It all starts with Dependency Injection and Inversion Of Control.

Spring at its core provides an Inversion of Control Container. Therefore to understand a lot of what goes on when using Spring involves understanding what Inversion of Control is all about and what model to have in mind when programming using an IoC container.

The mental model I soon found myself assuming, that helped in filing these numerous interfaces and annotations neatly away was to take the Container word in "Inversion Of Control container" to be a literal metaphor. It is, probably, anyways.

Thus when building applications with Spring (or any other IoC container out there eg Guice) I now imagine I have an actual container or bucket or vessel, or canister (or...you get the idea?) that contains all my objects created, instantiated and initialized with all their dependencies in place ready for usage. And me writing business logic starts with calling out into this container and requesting the needed objects.

Check this StackOverFlow question: Inversion Of Control Versus Dependency Injection if you need some sort of refresher on Inversion of Control/Dependency Injection. It points to one of the most referenced article on the topic of IoC.

Spring takes care of getting this container populated at start up of the application; but not just that, it also provides opportunities of hooking into the bean population process and have you specify instructions to be executed at certain points.

BeanPostProcessor, BeanFactoryPostProcessor, IntializingBean and DisposableBean are all interfaces that can be used to write code that would be executed at different points of application start up and container population with managed beans. So also is @PostConstruct and @PreDestroy annotation which are JSR-250 annotations and init-method and destroy-method which are yet another Spring centric way of hooking into the bean creation phases.

The more formal term for the Spring IoC container is Application Context.

Spring IoC Initialization Life-cycle

We have established the fact that Spring IoC provides us with opportunities to hook into its life-cycle. The next question then is what does the life-cycle look like?

This is briefly enumerated:

1. Read and parse the Bean definitions (either as XML, JavaConfig)
2. Process BeanFactoryPostProcessors
3. Construct bean by calling its constructor
4. Call setters, dependencies injected
5. Inject the required beans as defined by the *Aware Interfaces
6. Call postProcessBeforeIntialization
7. Call the initializaion callbacks.(like InitializingBean's afterPropertiesSet or a custom init-method)
8. Call postProcessAfterInitialization


Let's quickly walk through what goes on in the Intiailization life-cycle.

Everything starts off by the reading in and parsing the Spring beans definitions as specified in either XML configuration or JavaConfig, At this point non of the beans are created yet, only the blueprint needed to start their creation. At this point Spring provides you an opportunity to hook into the process and modify the parsed bean definitions: the blueprints. You do this by having the logic you want executed at this phase in the postProcessBeanFactory method of the BeanFactoryPostProcessor interface. An example of such a BeanFactoryPostProcessor that comes with Spring is PropertyPlaceHolderConfigurer which is used to replace placeholders in bean definitions with actual values pulled from property files.

Implementing your own BeanFactoryPostProcessor would look thus:

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;

/**
 * @author Dadepo Aderemi.
 */
public class BFPP implements BeanFactoryPostProcessor {

  @Override
  public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory)
     throws BeansException {
      // You have the ConfigurableListableBeanFactory from which you have access to the beans defined
  }
}

After the BeanFactoryPostProcessors are called, then the beans can be instantiated. The Spring IoC does this by calling the respective constructors. Once the beans are constructed the next thing that would be done is calling required setters and making sure the defined dependencies are injected.

Next in line would be to then inject any defined Infrastructred dependencies as defined by any of the *Aware Interfaces. For example if a bean implements ServletContextAware Interface, then the required overriden metthod is called with the ServletContext provided.

At this point in the container life-cyle, the beans are created and all in existence. It is at this point that the BeanPostProcessor's can kick in. The BeanPostProcessor's would define two methods: postProcessorBeforeInitialization and postProcessorAfterInitialization.

But what is the difference between these two methods defined by the BeanPostProcessor Interface? To answer that question, we would look into the bean life-cycle

Bean Life-Cycle

Spring also allows you to hook into stages that are specific to a bean's life-cycle. A bean would normally pass through a creation phase and a destroy phase. With Spring you can specify logic that should be executed right after a bean is created or just before a bean is destroyed. You can do this in various ways:

init-method

init-method is a Spring centric way of defining logic to be executed right after a bean has been created. It allows you to perform other bean intialization outside constructor of setter methods. It involves writing a method and then defining the method as an init-method in the Spring configuration.

For example:


import org.springframework.beans.factory.InitializingBean;

import javax.annotation.PostConstruct;

/**
 * @author Dadepo Aderemi.
 */
public class LifeCycle  {

    public void callAfterCreation() {
        System.out.println("Init");
    }

}

and having the following definitions




would make the callAfterCreation method be called just after the bean is instantiated. destroy-method is the destroy counterpart that allows you to specify method to be called just before a bean is destroyed and removed from the IoC container.

InitializingBean Interface.

Another Spring specific way of specifying logic to be executed right after a bean is instantiated is having the bean implements the InitializingBean interface and have the required logic to be excuted just after bean creation in the afterPropertiesSet method of the InitializingBean Interface. For example:

import org.springframework.beans.factory.InitializingBean;

import javax.annotation.PostConstruct;

/**
 * @author Dadepo Aderemi.
 */
public class LifeCycle implements InitializingBean {

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("After Property Set");
    }

}


The DisposableBean interface is the destroy counterpart of InitializingBean and instead of afterPropertiesSet, a destroy method would need to be implemented.


@PostConstruct
Using the @PostConstruct is a standard way (not only Spring specific) of hooking logic into the bean lifecycle right after the bean is constructed. It would always be called before the two Spring specific methods (init-method and InitializingBean Interface). But just as the other Spring specific methods it is used to specify methods that needs to be executed after dependency injection is done to perform any initialization on the bean. For example:

import org.springframework.beans.factory.InitializingBean;

import javax.annotation.PostConstruct;

/**
 * @author Dadepo Aderemi.
 */
public class LifeCycle {

    @PostConstruct
    public void construct() {
        System.out.println("Construct");
    }

}

The destroy counterpart of @PostConstruct is @PreDestroy.

So we have seen ways of hooking into bean lifecycle. How does this help us answer the question: What is the difference between postProcessorBeforeIntialization and postProcessorAfterInitialization? It should be straight forward by now. Logic in postProcessorBeforeIntialization is executed before any @PostConstruct, init-method, InitializationBean's afterPropertiesSet method, while postProcessorAfterInitialization is executed after.

After the postProcessAfterInitialization, method of BeanPostProcessor, the startup lifecycle of the Spring IoC is completed and your bean is ready and available for use with all intercepted logic at various startup phase executed.

Summary

It should not be that confusing anymore: the difference between say BeanFactoryPostProcessor and BeanPostProcessor?

BeanFactoryPostProcessor kicks in at the phase of the container life-cycle, when no bean has been created but the bean definition has already been parsed, while BeanPostProcessor comes into play after bean creation.

Also what InitializingBean or DisposableBean is all about should now be clearer, so also should the init-method and destroy-method and where @PostConstruct (or @PreDestroy) fits into all this.

It does becomes obvious that BeanFactoryPostProcessor and BeanPostProcessor are the ones used to extend the framework,  as the functionality defined by them would apply to all beans created by Spring, while the other mechanism (InitalizingBean, DisposableBean, @PostConstruct, @PreConstruct, init-method, destroy-method) only act on the individual bean where they are defined for.

1 comment:

Han Li said...

Greate post!
Thanks for sharing~!