Spring BeanPostProcessor beans are a special kind of beans that get created before any other beans and Spring allows you to assign customize callbacks to it. Spring provides the BeanPostProcessor interface, you can implement its methods to provide your own instantiation logic and dependency resolution logic.

NOTE – the following before working with BeanPostProcessor.

  • BeanPostProcessor methods are executed after the Spring IoC finishes instantiating, configuring, and initializing a bean.
  • You can plug in one or more custom BeanPostProcessor implementations.
  • When working with multiple Bean Postprocessors, you should implement the Ordered interface to control the order in which these processors get executed.
  • Remember, the BeanPostProcessor instances are scoped per container.

1. Customizing Spring Beans with BeanPostProcessor Interface

All you need to do is to implement the interface BeanPostProcessor in your custom class. The interface looks as below, which means you can implement the method that you like and each of them returns bean by default.

BeanPostProcessor.java
public interface BeanPostProcessor {

  @Nullable
  default Object postProcessBeforeInitialization(Object bean, String beanName) 
      throws BeansException {
        return bean;
  }
  
  @Nullable
  default Object postProcessAfterInitialization(Object bean, String beanName) 
      throws BeansException {
        return bean;
   }
}

All you need to do is implement the interface and implement the callback methods. Below code explains the simple use of the Spring BeanPostProcessor.

TraceBeanPostProcessor
@Component
public class TraceBeanPostProcessor implements BeanPostProcessor {

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

  @Override
  public Object postProcessAfterInitialization(Object bean, String beanName)
      throws BeansException {
    System.out.println("Inside postProcessAfterInitialization - " + beanName);
    return bean;
  }
}
  • The postProcessBeforeInitialization method is overridden to perform custom logic before a bean is initialized. It prints a message indicating that it’s inside the method, along with the name of the bean being processed.
  • Similarly, the postProcessAfterInitialization method is overridden to perform custom logic after a bean is initialized. It also prints a message indicating that it’s inside the method, along with the name of the bean being processed.

2. Customizing Spring Beans using @PostConstruct and @PreDestroy

The initData method is annotated with @PostConstruct, indicating that it should be invoked after the bean has been constructed by the Spring container. This method contains custom initialization code, which will be executed when the bean is initialized.

Similarly, the clearData method is annotated with @PreDestroy, indicating that it should be invoked before the bean is destroyed by the Spring container. This method contains custom cleanup or destruction code, which will be executed when the bean is being destroyed.

Both methods provide a way to customize the initialization and destruction lifecycle of the bean, allowing developers to execute specific tasks before or after the bean’s lifecycle events. This can be useful for tasks such as resource allocation, cleanup, or releasing resources associated with the bean.

ExampleBean
@Component
public class ExampleBean {

  @PostConstruct
  public void initData() {
    System.out.println("Your custom initialization code goes here...");
  }

  @PreDestroy
  public void clearData() {
    System.out.println("Your custom destroy code goes here...");
  }
}
ExampleConfig
@Configuration
@ComponentScan("core.bean.postprocessor")
public class ExampleConfig {
  //Extra config goes
}
TestExampleBean
public class TestExampleBean {
  public static void main(String[] args) {
    ConfigurableApplicationContext context
        = new AnnotationConfigApplicationContext(ExampleConfig.class);
    context.getBean(ExampleBean.class);
    //This is important
    context.registerShutdownHook();
  }
}

Output:

Inside postProcessBeforeInitialization exampleConfig
Inside postProcessAfterInitialization exampleConfig
Inside postProcessBeforeInitialization exampleBean
Your custom initialization code goes here...
Inside postProcessAfterInitialization exampleBean
Your custom destroy code goes here...

As you can see in the above output, the bean post-processor methods get invoked twice, once per bean. This is because Spring IoC creates 2 beans here (exampleConfig, and exampleBean).

You can have multiple custom BeanPostProcessor classes in your Spring application, but remember to implement the Ordered interface as well.

A Practical use case of BeanPostProcessor

A practical use case of a bean Post Processor is when you want to wrap the original IoC-created bean in a proxy instance for example when you use @Transactional, Spring-AOP or BeanValidationPostProcessor. I have listed some of the Spring framework classes that make use of the bean post-processor interface.

I hope to have provided enough information on this topic. Please share your thoughts in the comments below. I highly encourage you to check out the article related to the Spring bean lifecycle.


By |Last Updated: April 1st, 2024|Categories: Spring Framework|