In this post under Spring Core, I will explain with example the purpose and how to use “BeanPostProcessor” interface.
In Spring framework when a bean is created, It is first constructed by calling its constructor, then dependencies are injected and initialization logic if any is executed.
It is during this initialization phase that we can add our own logic that will be executed before and after initialization phase by the help of “BeanPostProcessor” interface.
We can have multiple “BeanPostProcessor” implementations and we can also control the order in which these “BeanPostProcessor” implementations are executed.
Classes that implement “BeanPostProcessor” interface are special classes according to Spring framework. These classes and its dependencies are created first before creating other beans.
Once all classes that implement “BeanPostProcessor” interface are created and Spring starts creating normal bean, these “BeanPostProcessor” implementations are called during the initialization of these
normal beans.
“BeanPostProcessor” implementations are specific to particular container. So if we have container hierarchy, say container “A” contains container “B”, then “BeanPostProcessor” implementations defined
in container “A” will be called when creating beans defined by container “A” only and it doesn’t get called by container “B” for beans created by it.
“BeanPostProcessor” interface has two method “postProcessBeforeInitialization” and “postProcessAfterInitialization” that we have to provide implementations.
For our example lets create two “BeanPostProcessor” implementations one using “@Component” and another using “@Bean”.
Below are the class structure
Log4jBeanPostProcessor
package core.package50;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Component;
@Component
public class Log4jBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("Logging by Log4j before initialization of bean: " + beanName);
return BeanPostProcessor.super.postProcessBeforeInitialization(bean, beanName);
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("Logging by Log4j after initialization of bean: " + beanName);
return BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);
}
}
LogbackBeanPostProcessor
package core.package50;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
public class LogbackBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("Logging by Logback before initialization of bean: " + beanName);
return BeanPostProcessor.super.postProcessBeforeInitialization(bean, beanName);
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("Logging by Logback after initialization of bean: " + beanName);
return BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);
}
}
As you can see from the above code both “Log4jBeanPostProcessor” and “LogbackBeanPostProcessor” implement “BeanPostProcessor” interface and provide logic to interface method “postProcessBeforeInitialization”
and “postProcessAfterInitialization”.
Next we will create two normal beans whose class structure is as shown below
FileManager
package core.package50;
import org.springframework.stereotype.Component;
@Component
public class FileManager {
public void upload(String fileName) {
System.out.println("Uploading file with name: " + fileName);
}
}
OTPManager
package core.package50;
import org.springframework.stereotype.Component;
@Component
public class OTPManager {
public void generateOtp() {
System.out.println("Generating OTP");
}
}
Below is the main class for your reference
Main class
package core.package50;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@ComponentScan(basePackages = "core.package50")
public class Example50 {
@Bean
public BeanPostProcessor logbackBeanPostProcessor() {
return new LogbackBeanPostProcessor();
}
public static void main(String[] args) {
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(Example50.class);
}
}
When the main class code is executed, below output is generated
Output
Logging by Log4j before initialization of bean: fileManager
Logging by Logback before initialization of bean: fileManager
Logging by Log4j after initialization of bean: fileManager
Logging by Logback after initialization of bean: fileManager
Logging by Log4j before initialization of bean: OTPManager
Logging by Logback before initialization of bean: OTPManager
Logging by Log4j after initialization of bean: OTPManager
Logging by Logback after initialization of bean: OTPManager
As you can see from the output for each normal bean created, the “BeanPostProcessor” implementations are called.
In this way we can use “BeanPostProcessor” interface.