How to perform custom initialization of beans in Spring / How to call a method before bean creation in Spring / Callback methods in Spring Beans

There are scenarios where we want to take some actions before a bean is fully constructed and put into service such as

  • giving a specific name to the bean other than that given in the configuration,
  • setting the application context into a bean property,
  • making a log entry immediately after bean initialization etc.

This can be possible if we are able to receive a callback after / before a bean is created. In other words, we are able to call a method after / before bean creation wherein we may write our custom action code which we want to perform prior to bean creation.

Spring provides various ways to define such callback methods. They are :

  1. Callback methods.
  2. Callback Interfaces.
  3. Callback Annotations.
  4. Aware Interfaces.

Let’s elaborate these in detail ahead.

    1. Callback Methods

This one is strictly related to XML configuration of beans. A bean in the Spring configuration XML is defined as below :

< bean class="com.codippa.lifecycle.MyBean"></bean>

This declaration will simply create a bean and register it in Spring application context. Now if I want to call a method automatically before this bean is created and when this bean is destroyed. What should I do??

Spring provides a pretty handy way of doing this.

  • Just change the above bean declaration to :
< bean class="com.codippa.lifecycle.MyBean" init-method="initFromXml" destroy-method="destroyFrmXml"></bean>
  • And add methods with name initFromXml and destroyFrmXml.

init-method attribute of the bean declaration tag instructs the Spring container to call the method with the name given as the value of this attribute before bean creation. This method should be present in the same bean class for which the init-method attribute is defined.

Similarly, destroy-method attribute of the bean declaration tag instructs the Spring container to call the method with the name given as the value of this attribute before the bean is destroyed. This method should also be present in the same bean class for which the destroy-method attribute is defined.

If a method name is given in init-method attribute but is not defined in the bean class then an error Couldn’t find an init method named ‘initFromXml’ on bean with name ‘com.codippa.spring.lifecycle.MyBean will be thrown.

     2. Callback Interfaces

Spring provides a couple of interfaces which, when implemented by a bean make it eligible for callback method calls before initialization and destruction. These interfaces are :

                 A. InitializingBean –  This interface has a method afterPropertiesSet(). When a bean implements this interface, it must provide an implementation of this method and this method is called automatically before the bean is created but only after all the properties of the bean have been set !!! The signature of this method is public void afterPropertiesSet() throws Exception and you can not change it while implementing otherwise this will result in a compiler error.

              B. DisposableBean – This interface has a method destroy(). When a bean implements this interface, it must provide an implementation of this method and this method is called when the bean is destroyed. The signature of this method is public void destroy() throws Exception and you can not change it while implementing otherwise this will result in a compiler error.

A bean declaring these interfaces can be simply declared in Spring configuration and it need not use any additional attributes (such as init-method in previous example) in this method. Also, it is NOT necessary to implement both these interfaces at the same time. A bean may implement InitializingBean but not DisposableBean.

     3. Callback Annotations

Again, Spring provides a couple of method level annotations for a method to become a callback method and get called automatically upon bean creation and destruction. The annotations are :

                A. @PostConstruct –  A method annotated with this annotation is called immediately after the bean has been initialized but before the bean is put into service. Thus, any custom operation can be performed on the bean fields in this method. According to Spring docs,

 The PostConstruct annotation is used on a method that needs to be executed after dependency injection is done to perform any initialization. This method MUST be invoked before the class is put into service. This annotation MUST be supported on all classes that support dependency injection.

               B. @PreDestroy – A method annotated with this annotation is called just before the bean instance is about to be destroyed or about to be removed from service. This method may be used to free up any resources being used by the bean during its service. Spring docs of this annotation state:

The PreDestroy annotation is used on methods as a callback notification to signal that the instance is in the process of being removed by the container. The method annotated with PreDestroy is typically used to release resources that it has been holding.

    4. Aware Interfaces

Spring supports various Aware interfaces which when implemented by a bean make it eligible for notification of events specific to that interface.

When a bean implements an Aware interface, it gets access to a framework object which is provided to the method defined in that interface as an argument. Moreover, this method is automatically called by Spring as a callback style method. Let’s make it more clear.

If a Bean class implements ApplicationContextAware interface, it has to implement the method

void setApplicationContext(ApplicationContext applicationContext) throws BeansException;

This method when defined in a bean class is called by Spring and gives that bean, access to ApplicationContext in which it is running. So a bean implementing this interface would look like:

    public class MyBean implements ApplicationContextAware {
       // instance variable
       private void ApplicationContext applicationContext;
       /*
       * Callback method invoked by Spring
       */
       void setApplicationContext(ApplicationContext applicationContext) throws BeansException() {
          // store application context in class variable for later use
          this.applicationContext = applicationContext;
       }        
    }

Similarly, if a bean implements BeanNameAware interface, then it has to implement the method

  void setBeanName(String name);

This method is called by Spring container with the name of the bean passed as an argument. The name of the bean is the id provided in bean declaration in Spring configuration file.

There are various Aware interfaces such as ApplicationEventPublisherAware which gives access to framework’s ApplicationEventPublisher object, BeanFactoryAware giving access to BeanFactory object, ServletContextAware giving access to ServletContext object in case of web applications etc.
All Aware interfaces extend org.springframework.beans.factory.Aware interface.

Let’s tweak in :

  1. The method annotated with @PostConstruct annotation should be a no-argument method otherwise it will raise a runtime exception as Lifecycle method annotation requires a no-arg method: public void com.codippa.spring.lifecycle.MyBeanOne.init(java.lang.String).
  2. Similarly, a method annotated with @PreDestroy annotation should also be a no-argument method.
  3. If a bean implements InitializingBean interface, which means it has an afterPropertiesSet() method defined and also has a method annotated with @PostConstruct annotation, then the method annotated with @PostConstruct will be called before afterPropertiesSet() method.
  4. When providing initialization/destruction methods using @PostConstruct / @PreDestroy annotations or init-method / destroy-method bean tag attributes you can return a value from those methods such as a flag indicating successful completion but when implementing InitializingBean / DisposableBean interface you cannot do that.
  5. All child interfaces of org.springframework.beans.factory.Aware interface have just one method.
  6. setBeanName method of BeanNameAware interface is invoked after the bean properties have been initialized but before calling any of the initialization method (either afterPropertiesSet() or that declared through init-method attribute) described above.

 

If you are here, means you grasped this post. Mark your impression by providing your feedback / queries in the space below (specially reserved for this purpose).

0

Leave a Reply