The BeanPostProcessor


Sometimes, youmay find yourself in a position where you need to performsome additional processing immediately before and after Spring instantiates the bean. The processing can be as simple as modifying the bean or as complex as returning a completely different object! The BeanPostProcessor interface has two methods: postProcessBeforeInitialization, which is called before Spring calls any bean initialization hooks (such as InitializingBean.afterPropertiesSet or the init-method), and postProcessAfterInitialization, which Spring calls after the initialization hooks succeed.



Annotated Bean Example


public class SimpleBean {
@PostConstruct
public void initialize() {
System.out.println("Initializing bean " + getClass());
}
@PreDestroy
public void cleanUp() {
System.out.println("Cleaning up bean " + getClass());
}
}

We would like Spring to use these annotations automatically, so we do not want to specify the init-method or destroy-method attributes in the <bean> definition in the BeanFactory configuration.

However, we can use InitDestroyAnnotationBeanPostProcessor, an implementation of BeanPostProcessor that invokes all methods on the target bean with the configured initialization annotation. Because it also implements the DestructionAwareBeanPostProcessor, it invokes all methods on the target bean annotated
with the destruction annotation



BeanFactory Configuration File


<?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.xsd">
<bean id="simpleBean" class="com.apress.prospring2.ch04.bpp.SimpleBean"/>
<bean id="bpp" class="org.springframework.beans.factory.annotation.➥
InitDestroyAnnotationBeanPostProcessor">
<property name="initAnnotationType" value="javax.annotation.PostConstruct"/>
<property name="destroyAnnotationType" value="javax.annotation.PreDestroy"/>
</bean>
</beans>

You can see that we have declared the simpleBean bean without init-method or destroy-method. We have also declared the InitDestroyAnnotationBeanPostProcessor and set its initAnnotationType and destroyAnnotationType to the JSR 250 annotations. This code may look complicated, but it means that we can specify any type of annotation;



Sample Application for the InitDestroyAnnotationBeanPostProcessor


public class SimpleBeanDemo {
public static void main(String[] args) {
ConfigurableListableBeanFactory beanFactory = new XmlBeanFactory(
new ClassPathResource("/META-INF/spring/bpp-context.xml")
);
BeanPostProcessor bpp = (BeanPostProcessor)beanFactory.getBean("bpp");
beanFactory.addBeanPostProcessor(bpp);
SimpleBean sb = (SimpleBean)beanFactory.getBean("simpleBean");
System.out.println(sb);
beanFactory.destroySingletons();
}
}

INFO [main] XmlBeanDefinitionReader.loadBeanDefinitions(308) | ➥
Loading XML bean definitions from class path resource ➥
[META-INF/spring/bpp-context.xml]
Initializing bean class com.apress.prospring2.ch04.bpp.SimpleBean
com.apress.prospring2.ch04.bpp.SimpleBean@c16c2c0
INFO [main] DefaultSingletonBeanRegistry.destroySingletons(340) | ➥
Destroying singletons in org.springframework.beans.factory.xml.➥
XmlBeanFactory@2a4bd173: defining beans [simpleBean,bpp]; root of factory hierarchy
Cleaning up bean class com.apress.prospring2.ch04.bpp.SimpleBean



Implementing a BeanPostProcessor


Let’s create a simple BeanPostProcessor that can timestamp our beans. The aim is to set the Date fields annotated with the @Timestamp annotation



@Timestamp Annotation


@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Timestamp {
}


Modified SimpleBean with the @Timestamp Field


public class SimpleBean {
@Timestamp
Date creationDate;
@PostConstruct
public void initialize() {
System.out.println("Initializing bean " + getClass());
}
@PreDestroy
public void cleanUp() {
System.out.println("Cleaning up bean " + getClass());
}
@Override
public String toString() {
return "Bean was created at " + this.creationDate;
}
}


TimestampingBeanPostProcessor


public class TimestampingBeanPostProcessor implements BeanPostProcessor {
public Object postProcessBeforeInitialization(final Object bean,
final String beanName) throws BeansException {
ReflectionUtils.doWithFields(bean.getClass(),
new ReflectionUtils.FieldCallback() {
public void doWith(Field field) throws IllegalArgumentException,
IllegalAccessException {
field.set(bean, new Date());
}
}, new ReflectionUtils.FieldFilter() {
public boolean matches(Field field) {
return field.getType() == Date.class &&
field.getAnnotation(Timestamp.class) != null;
}
});
return bean;
}
public Object postProcessAfterInitialization(Object bean, String beanName)
throws BeansException {
return bean;
}
}



The TimestampingBeanPostProcessor Bean


<bean id="bpp2" lass="com.apress.prospring2.ch04.bpp.TimestampingBeanPostProcessor"/>

The modification to the sample application is very simple too;



Modified Sample Application


public class SimpleBeanDemo {
public static void main(String[] args) {
ConfigurableListableBeanFactory beanFactory = new XmlBeanFactory(
new ClassPathResource("/META-INF/spring/bpp-context.xml")
);
BeanPostProcessor bpp = (BeanPostProcessor)beanFactory.getBean("bpp");
BeanPostProcessor bpp2 = (BeanPostProcessor)beanFactory.getBean("bpp2");
beanFactory.addBeanPostProcessor(bpp);
beanFactory.addBeanPostProcessor(bpp2);
SimpleBean sb = (SimpleBean)beanFactory.getBean("simpleBean");
System.out.println(sb);
beanFactory.destroySingletons();
}
}

INFO [main] XmlBeanDefinitionReader.loadBeanDefinitions(308) | ➥
Loading XML bean definitions from class path resource ➥
[META-INF/spring/bpp-context.xml]
Initializing bean class com.apress.prospring2.ch04.bpp.SimpleBean
Bean was created at Fri Mar 28 11:00:02 GMT 2008
INFO [main] DefaultSingletonBeanRegistry.destroySingletons(340) | ➥
Destroying singletons in org.springframework.beans.factory.xml.➥
XmlBeanFactory@f292738: defining beans [simpleBean,bpp,bpp2]; ➥
root of factory hierarchy
Cleaning up bean class com.apress.prospring2.ch04.bpp.SimpleBean


SimpleBean with the @Autowired, @PostConstruct, and @PreDestroy Annotations


public class SimpleBean {
@Timestamp
Date creationDate;
@Autowired
String dependency;
@PostConstruct
public void initialize() {
System.out.println("Initializing bean " + getClass());
}
@PreDestroy
public void cleanUp() {
System.out.println("Cleaning up bean " + getClass());
}
@Override
public String toString() {
return "Bean was created at " + this.creationDate + " with " +
this.dependency;
}
}



Using InstantiationAwareBeanPostProcessorAdapter


public class TypedDependencyBeanPostProcessor extends
InstantiationAwareBeanPostProcessorAdapter {
public Class predictBeanType(Class beanClass, String beanName) {
if (beanClass.equals(Dependency.class)) {
return String.class;
}
return beanClass;
}
public Object postProcessBeforeInitialization(final Object bean,
final String beanName)
throws BeansException {
if (bean.getClass().equals(Dependency.class)) {
return "Hello, world";
}
return bean;
}
public Object postProcessAfterInitialization(Object bean, String beanName)
throws BeansException {
return bean;
}
}

The BeanPostProcessor implementation is very simple: we turn all Dependency objects into String objects, but we also predict that we’ll do just that in the predictBeanType method. Running the sample application now shows that Spring can automatically wire our String property:

INFO [main] XmlBeanDefinitionReader.loadBeanDefinitions(308) | ➥
Loading XML bean definitions from class path resource ➥
[META-INF/spring/bpp2-context.xml]
Initializing bean class com.apress.prospring2.ch04.bpp.SimpleBean
Bean was created at Fri Mar 28 11:44:59 GMT 2008 with Hello, world
INFO [main] DefaultSingletonBeanRegistry.destroySingletons(340) | ➥
Destroying singletons in org.springframework.beans.factory.xml.➥
XmlBeanFactory@6e681db8: defining beans ...

Cleaning up bean class com.apress.prospring2.ch04.bpp.SimpleBean

Leave a Reply

Subscribe to Posts | Subscribe to Comments

About This Site

Howdy! My name is Suersh Rohan and I am the developer and maintainer of this blog. It mainly consists of my thoughts and opinions on the technologies I learn,use and develop with.

Blog Archive

Powered by Blogger.

- Copyright © My Code Snapshots -Metrominimalist- Powered by Blogger - Designed by Suresh Rohan -