Monday, July 6, 2020

BeanPostProcessor in Spring Framework

If you want to implement some additional custom logic after the Spring container finishes instantiating, configuring, and initializing a bean, you can plug in one or more BeanPostProcessor implementations.

The BeanPostProcessor interface in the Spring framework defines callback methods that you can implement to perform custom logic on the bean instances. Note that BeanPostProcessors operate on bean instances; the Spring IoC container instantiates a bean instance and then BeanPostProcessors do their work on those created instances. These instances are passed as argument to the callback methods. BeanPostProcessor callback methods are called on each bean created by the Springcontainer.

A bean post-processor typically checks for callback interfaces or may wrap a bean with a proxy.

BeanPostProcessor callback methods

The org.springframework.beans.factory.config.BeanPostProcessor interface has the following two callback methods.

  • Object postProcessBeforeInitialization(Object bean, String beanName)- This callback method is called before container initialization methods (such as InitializingBean’s afterPropertiesSet() and any declared init method) are called
  • Object postProcessAfterInitialization(Object bean, String beanName) - This method is called after any bean initialization callbacks.

Configuring more than one BeanPostProcessor

You can configure multiple BeanPostProcessor instances. You can also control the order in which these BeanPostProcessors execute by setting the order property. For that the BeanPostProcessor implemenation class must implement the Ordered interface too.

Spring BeanPostProcessor Example

A typical use case for BeanPostProcessor is if you want to have some callback methods for specific type of bean.

Let’s say you have an interface IPayment and two implementation classes CashPayment and CardPayment. For these two beans only (out of all the configured beans) you want some logic to be performed (like doing some validation, checking some value) then you can create a BeanPostProcessor and in it’s callback method postProcessAfterInitialization you can use instanceOf operator to verify if bean is of specific type and then call the method you want.

Inerface IPayment

public interface IPayment extends PaymentCallBack {
 void executePayment();
}

Interface PaymentCallBack

public interface PaymentCallBack {
 void processInstance(IPayment bean);
}

CashPayment.java

public class CashPayment implements IPayment{
 public void executePayment() {
  System.out.println("Perform Cash Payment "); 
 }
 @PostConstruct
 public void annoInitMethod(){
  System.out.println("Calling InitMethod for CashPayment");
 }
 @Override
 public void processInstance(IPayment bean) {
  System.out.println("processInstance method called with bean " + bean);  
 }
}

CardPayment.java

public class CardPayment implements IPayment{
 public void executePayment() {
  System.out.println("Perform Card Payment "); 
 }
 @PostConstruct
 public void annoInitMethod(){
  System.out.println("Calling InitMethod for CardPayment");
 }
 @Override
 public void processInstance(IPayment bean) {
  System.out.println("processInstance method called with bean " + bean);
 }
}

In these classes you can see that Spring bean life cycle initialization method annotated with @PostConstruct is used to see when bean is actually initialized.

BeanPostProcessor Class

A custom bean post processor class in Spring implements BeanPostProcessor interface and provides implementation of callback methods postProcessBeforeInitialization() and postProcessAfterInitialization().

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.core.Ordered;

public class InstantiationBeanPostProcessor implements BeanPostProcessor, Ordered {

 @Override
 public Object postProcessBeforeInitialization(Object bean, String beanName)
   throws BeansException {
  System.out.println("In postProcessBeforeInitialization method");
  return bean;
 }

 @Override
 public Object postProcessAfterInitialization(Object bean, String beanName)
   throws BeansException {

  System.out.println("In postProcessAfterInitialization method");
  if(bean instanceof IPayment){
   ((IPayment) bean).processInstance((IPayment)bean); 
  }
  return bean;
 }

 @Override
 public int getOrder() {
  // TODO Auto-generated method stub
  return 0;
 }
}

XML Configuration

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:util="http://www.springframework.org/schema/util" 
  xmlns:p="http://www.springframework.org/schema/p"
  xsi:schemaLocation="http://www.springframework.org/schema/beans 
  http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
  http://www.springframework.org/schema/util 
  http://www.springframework.org/schema/util/spring-util.xsd">
    
  <bean class="org.springframework.context.annotation.CommonAnnotationBeanPostProcessor" />
 
  <bean id="cashPaymentBean" class="org.netjs.exp.Spring_Example.CashPayment" />
  <bean id="cardPaymentBean" class="org.netjs.exp.Spring_Example.CardPayment" />
    
  <bean class="org.netjs.exp.Spring_Example.InstantiationBeanPostProcessor"/> 
</beans>

Notice how the InstantiationBeanPostProcessor is simply defined that's all is needed to register a BeanPostProcessor. It does not even have a name, and because it is a bean it can be dependency-injected just like any other bean.

You can use the following code to run the preceding code and configuration.
public class App {
 public static void main( String[] args ){
   
  ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("appcontext.xml");
  //System.out.println("Loading AnnotationConfig app context");
  IPayment cashBean = (IPayment) context.getBean("cashPaymentBean");
  IPayment cardBean = (IPayment) context.getBean("cardPaymentBean");
  context.close();
 }
}

Output

In postProcessBeforeInitialization method
Calling InitMethod for CashPayment
In postProcessAfterInitialization method
processInstance method called with bean org.netjs.exp.Spring_Example.CashPayment@1e397ed7
In postProcessBeforeInitialization method
Calling InitMethod for CardPayment
In postProcessAfterInitialization method
processInstance method called with bean org.netjs.exp.Spring_Example.CardPayment@490ab905

That's all for this topic BeanPostProcessor in Spring Framework. If you have any doubt or any suggestions to make please drop a comment. Thanks!

>>>Return to Spring Tutorial Page


Related Topics

  1. Bean Scopes in Spring With Examples
  2. Bean Definition Inheritance in Spring
  3. How to Inject Prototype Scoped Bean in Singleton Bean
  4. Lazy Initialization in Spring Using lazy-init And @Lazy Annotation
  5. Injecting Inner Bean in Spring

You may also like-

  1. Spring JdbcTemplate Insert, Update And Delete Example
  2. Run Time Injection Using Spring Expression Language(SpEL)
  3. Using depends-on Attribute in Spring
  4. Autodiscovery of Bean Using component-scan in Spring
  5. How ArrayList Works Internally in Java
  6. Object Cloning in Java
  7. Spliterator in Java
  8. static Block in Java