8.1 Overview of Spring BeanPost Processors
Quite often you will find yourself in a situation where you would need to perform some processing pre and post instantiationof the bean by Spring framework. Spring has provided BeanPostProcessor interface which defines a callback methods to achieve this functionality.
Classes that implements BeanPostProcessor interface needs to be defined in an ApplicationContext(spring bean configuration file) and will be applied on all the beans defined in an application context.
In case there are multiple BeanPostProcessor implementations configured in beans configuration files and they are dependent on each other ( processed object of one implementation can be an input to another) then the order in which post processors is important .To control the order in which post processor will be executed, bean post processor classes need to implement Ordered interface and implement its getOrder methodto define the order.
BeanPostProcessor interface provides us two extension points –
- To perform custom processing after the object is instantiated by Spring Container but before
- after the initialization.
The BeanPostProcessors operate on bean (or object) instances. This means Spring IoC container instantiates a bean instance and then BeanPostProcessor interfaces do their work.
Note: Notice that the init and destroy methods related to bean are different from bean post processors. BeanPostProcessors are common for all beans and gets executed before custom init methods .
8.2 BeanPostProcessor Interface
BeanPostProcessor interface is defined under org.springframework.beans.factory.config.BeanPostProcessor package and has two callback methods
a) postProcessBeforeInitialization– This method gets called after the object is instantiated but before initialization. Signature of this method is
public Object postProcessBeforeInitialization(Object bean, String beanName) throwsBeansException
b) postProcessAfterInitialization - This method gets called after the object is initialized . Signature of this method is
public Object postProcessAfterInitialization(Object bean, String beanName) throwsBeansException
Note: Both the methods returns Object type which means even a complete different object can be returned.
8.3 Example- Write an example to demonstrate the Spring bean post processors
Solution:
a) Create a bean “MessageBean” which will have custom init methods
publicclassMessageBean { private String message; publicMessageBean() { System.out.println("Constructor of bean is called !! "); } publicvoidinit() throws Exception { System.out.println("custom custom init method of bean is called !! "); } publicvoid destroy() throws Exception { System.out.println(" custom destroy method of bean is called !! "); } public String getMessage() { return message; } publicvoidsetMessage(String message) { this.message = message; } }
b) Create a bean post processor “MessageBeanPostProcessor” which will print messages
importorg.springframework.beans.BeansException; importorg.springframework.beans.factory.config.BeanPostProcessor; public class MessageBeanPostProcessor implements BeanPostProcessor{ @Override public Object postProcessAfterInitialization(Object bean, String beanName) throwsBeansException { System.out.println("Post Process After Initialization method is called : Bean Name " + beanName); if(bean instanceofMessageBean) { MessageBeanmessageBean = (MessageBean)bean; System.out.println("Value of Message is : " + messageBean.getMessage()); } return bean; } @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throwsBeansException { System.out.println("Post Process Before Initialization method is called : Bean Name " + beanName); if(bean instanceofMessageBean) { MessageBeanmessageBean = (MessageBean)bean; System.out.println("Value of Message is : " + messageBean.getMessage()); messageBean.setMessage("Updated Test Message"); } return bean; } }
c) Define a entry of MessageBeanPostProcessor and MessageBean in beans.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"> <bean id="messageBean" init-method="init" destroy-method="destroy" class="MessageBean" > <property name="message" value="Test Message"></property> </bean> <bean id="messageBeanPostProcessor" class="MessageBeanPostProcessor" /> </beans>
d) Create TestMessageBean program to test the bean post processors
importorg.springframework.context.ApplicationContext; importorg.springframework.context.support.AbstractApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class TestMessageBean { public static void main(String[] args) { ApplicationContext context = newClassPathXmlApplicationContext("beans.xml"); MessageBean bean = (MessageBean)context.getBean("messageBean"); ((AbstractApplicationContext) context).registerShutdownHook(); } }
e) Run the program
As you can see , we update the message in postProcessBeforeInitialization which is being reflected in postProcessPostInitialization method