Spring Core - BeanPostProcessor - Example
In Spring framework, the BeanPostProcessor is an interface that contains two callback methods: postProcessBeforeInitialization and postProcessAfterInitialization.
BeanPostProcessor allows custom modification of new bean instances that are created by Spring Bean Factory.
If we want to implement some custom logic such as checking for marker interfaces or wrapping beans with proxies after the Spring container finishes instantiating, configuring, and initializing a bean by plugging in one or more BeanPostProcessor implementations.
As we mentioned earlier, BeanPostProcessor consists of two callback methods:
1. postProcessBeforeInitialization: We can call this method to apply any custom logic (such as InitializingBean's afterPropertiesSet or a custom init-method) to the given new bean instance before any bean initialization callbacks.
2. postProcessAfterInitialization: We can call this method to apply any custom logic (such as InitializingBean's afterPropertiesSet or a custom init-method) to the given new bean instance after any bean initialization callbacks.
@Component
public class CustomBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(
Object bean, String beanName) throws BeansException {
// Your logic
return bean;
}
@Override
public Object postProcessAfterInitialization(
Object bean, String beanName) throws BeansException {
// Your logic
return bean;
}
}
As long as the BeanPostProcessor implements the Ordered or PriorityOrdered interface, you can configure several BeanPostProcessor interfaces and regulate the sequence in which these interfaces run by modifying the order property.
@Component
public class CustomBeanPostProcessor implements BeanPostProcessor, Ordered {
@Override
public Object postProcessBeforeInitialization(
Object bean, String beanName) throws BeansException {
// Your logic
return bean;
}
@Override
public Object postProcessAfterInitialization(
Object bean, String beanName) throws BeansException {
// Your logic
return bean;
}
@Override
public int getOrder() {
return HIGHEST_PRECEDENCE;
}
}
Complete example
We are creating a simple maven project. You could clone the code from our GitHub repo.
Final Project Directory
Complete pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.knf.dev.demo</groupId>
<artifactId>spring-beanpostprocessor-example</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>6.1.0</version>
</dependency>
</dependencies>
</project>
BeanPostProcessor Implementation
Create a CustomBeanPostProcessor class that implements the BeanPostProcessor interface and implements the two callback methods in it.
package com.knf.dev.demo;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Component;
@Component
public class CustomBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(
Object bean, String beanName) throws BeansException {
System.out.println(
"postProcessBeforeInitialization() is called for " + beanName);
return bean;
}
@Override
public Object postProcessAfterInitialization(
Object bean, String beanName) throws BeansException {
System.out.println(
"postProcessAfterInitialization() is called for " + beanName);
return bean;
}
}
Create UserService
Here we are customizing Spring Beans using init Method and destroy Method.initMethod is called after bean initialization and the destroyMethod is called before bean destruction by container.
package com.knf.dev.demo;
import org.springframework.stereotype.Component;
@Component
public class UserService {
public void init() {
System.out.println("Perform initialization task.");
}
public void destroy() {
System.out.println("Perform destructive task or release resources.");
}
public void printMessage() {
System.out.println("Hello");
}
}
Create Config.java
package com.knf.dev.demo;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@ComponentScan("com.knf.dev.demo")
public class Config {
@Bean(initMethod = "init", destroyMethod = "destroy")
public UserService userService() {
return new UserService();
}
}
Create Application.java
Create an Application class to get the bean and run the application.
package com.knf.dev.demo;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.AbstractApplicationContext;
public class Application {
public static void main(String[] args) {
AbstractApplicationContext context =
new AnnotationConfigApplicationContext(Config.class);
UserService myComponent = context.getBean(UserService.class);
myComponent.printMessage();
context.close();
}
}
The AbstractApplicationContext.close() method will close the application context, destroying all cached singleton beans and perform finalization like calling the destroy methods.
Console Output
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 (config, and userService).
Source Code