The BeanFactoryPostProcessor


The concept of the BeanFactoryPostProcessor is similar to the BeanPostProcessor: the BeanFactoryPostProcessor executes after Spring has finished constructing the BeanFactory but before the BeanFactory constructs the beans.

Using the BeanFactoryPostProcessor, we can adapt the beans’ values according to the BeanFactory’s environment



BeanFactory Post-Processors in Spring


AspectJWeavingEnabler - This post-processor registers AspectJ’s ClassPreProcessorAgentAdapter to be used in Spring’s LoadTimeWeaver

CustomAutowireConfigurer - This one allows you to specify annotations, in addition to @Qualifier, to indicate that a bean is a candidate for automatic wiring.

CustomEditorConfigurer - This registers the PropertyEditor implementations that Spring will use in attempts to convert string values in the configuration files to types required by the beans.

CustomScopeConfigurer - Use this post-processor to configure custom scopes (in addition to singleton, prototype, request, session, and globalSession) in the configuration file. Set the scopes property to
a Map containing the scope name as key and the implementation of the Scope interface as value.

PreferencesPlaceholderConfigurer - This post-processor will replace the values in beans' properties using JDK 1.4’s Preferences API. The Preferences API states that it will try to resolve a value first from user preferences (Preferences.userRoot()), then system preferences (Preferences.systemRoot()), and finally from a preferences file.

PropertyOverrideConfigurer - This post-processor will replace values of beans’ properties from values loaded from the specified properties file. It will search the properties file for a property constructed from
the bean name and property: for property a of bean x, it will look for x.a in the properties file. If the property does not exist, the post-processor will leave the value found in the configuration file.

PropertyPlaceholderConfigurer - This post-processor will replace values of properties with values loaded from the configured properties file, if the values follow certain formatting rules (by default, ${property-name}).

ServletContextPropertyPlaceholderConfigurer This post-processor extends PropertyPlaceholderConfigurer; therefore, it replaces beans’ properties if they follow the specified naming convention. In addition to its
superclass, this processor will load values from context-param entries of the servlet that is hosting the application.



SimpleBean Configuration


<?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.bfpp.SimpleBean">
<property name="connectionString" value="${simpleBean.connectionString}"/>
<property name="password" value="${simpleBean.password}"/>
<property name="username" value="username"/>
</bean>

</beans>


Sample Application for the BeanFactoryPostProcessor


public class PropertyConfigurerDemo {
public static void main(String[] args) {
ConfigurableListableBeanFactory beanFactory = new XmlBeanFactory(
new ClassPathResource("/META-INF/spring/bfpp-context.xml")
);
System.out.println(beanFactory.getBean("simpleBean"));
}

}

SimpleBean{password='${simpleBean.password}', username='username', ➥

connectionString='${simpleBean.connectionString}'}

Modified 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="bfpp"
class="org.springframework.beans.factory.config.➥
PropertyPlaceholderConfigurer">
<property name="location" value="classpath:/META-INF/bfpp.properties"/>
</bean>
<bean id="simpleBean" class="com.apress.prospring2.ch04.bfpp.SimpleBean">
<property name="connectionString" value="${simpleBean.connectionString}"/>
<property name="password" value="${simpleBean.password}"/>
<property name="username" value="username"/>
</bean>

</beans>


Usage of the BeanFactoryPostProcessor Bean


public class PropertyConfigurerDemo {
public static void main(String[] args) {
ConfigurableListableBeanFactory beanFactory = new XmlBeanFactory(

new ClassPathResource("/META-INF/spring/bfpp-context.xml")

);
BeanFactoryPostProcessor bfpp =
(BeanFactoryPostProcessor)beanFactory.getBean("bfpp");
bfpp.postProcessBeanFactory(beanFactory);
System.out.println(beanFactory.getBean("simpleBean"));
}

}

Assuming we have the /META-INF/bfpp.properties file with definitions for simpleBean.
connectionString=Hello and simpleBean.password=won’t tell, the sample application will now print this:

SimpleBean{password='won't tell!', username='username', connectionString='hello'}



Implementing a BeanFactoryPostProcessor




we will implement a simple post-processor that removes potentially obscene property values (it is all too easy to leave something like "bollocks" in a bean definition; you certainly don’t want the users to see this in production)


Potentially Dangerous Bean Definition


<?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.bfpp.SimpleBean">
<property name="connectionString" value="bollocks"/>
<property name="password" value="winky"/>
<property name="username" value="bum"/>
</bean>
</beans>



The ObscenityRemovingBeanFactoryPostProcessor Implementation


public class ObscenityRemovingBeanFactoryPostProcessor
implements BeanFactoryPostProcessor {
private Set<String> obscenities;
public ObscenityRemovingBeanFactoryPostProcessor() {
this.obscenities = new HashSet<String>();
}
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
throws BeansException {
String[] beanNames = beanFactory.getBeanDefinitionNames();
for (String beanName : beanNames) {
BeanDefinition bd = beanFactory.getBeanDefinition(beanName);
StringValueResolver valueResolver = new StringValueResolver() {
public String resolveStringValue(String strVal) {
if (isObscene(strVal)) return "****";
return strVal;
}
};
BeanDefinitionVisitor visitor =
new BeanDefinitionVisitor(valueResolver);
visitor.visitBeanDefinition(bd);
}
}
private boolean isObscene(Object value) {
String potentialObscenity = value.toString().toUpperCase();
return this.obscenities.contains(potentialObscenity);
}
public void setObscenities(Set<String> obscenities) {
this.obscenities.clear();
for (String obscenity : obscenities) {
this.obscenities.add(obscenity.toUpperCase());
}
}
}



Updated BeanFactory Configuration


<?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="bfpp"
class="com.apress.prospring2.ch04.bfpp.➥
ObscenityRemovingBeanFactoryPostProcessor">
<property name="obscenities">
<set>
<value>bollocks</value>
<value>winky</value>
<value>bum</value>
<value>Microsoft</value>
</set>
</property>
</bean>
<bean id="simpleBean" class="com.apress.prospring2.ch04.bfpp.SimpleBean">
<property name="connectionString" value="bollocks"/>
<property name="password" value="winky"/>
<property name="username" value="bum"/>
</bean>
</beans>



Sample Application for the BeanFactoryPostProcessor


public class ObscenityCleaningDemo {
public static void main(String[] args) {
ConfigurableListableBeanFactory beanFactory = new XmlBeanFactory(
new ClassPathResource("/META-INF/spring/bfpp-context.xml")
);
BeanFactoryPostProcessor bfpp =
(BeanFactoryPostProcessor)beanFactory.getBean("bfpp");
bfpp.postProcessBeanFactory(beanFactory);
SimpleBean simpleBean = (SimpleBean) beanFactory.getBean("simpleBean");
System.out.println(simpleBean);
}
}



Modified ObscenityRemovingBeanFactoryPostProcessor


public class ObscenityRemovingBeanFactoryPostProcessor
implements BeanFactoryPostProcessor, BeanNameAware {
private Set<String> obscenities;
private Set<String> obscenitiesRemoved;
private String name;
public ObscenityRemovingBeanFactoryPostProcessor() {
this.obscenities = new HashSet<String>();
this.obscenitiesRemoved = new HashSet<String>();
}
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
throws BeansException {
String[] beanNames = beanFactory.getBeanDefinitionNames();
for (String beanName : beanNames) {
if (beanName.equals(this.name)) continue;
BeanDefinition bd = beanFactory.getBeanDefinition(beanName);
StringValueResolver valueResolver = new StringValueResolver() {
public String resolveStringValue(String strVal) {
if (isObscene(strVal)) {
obscenitiesRemoved.add(strVal);
return "****";
}
return strVal;
}
};
BeanDefinitionVisitor visitor=
new BeanDefinitionVisitor(valueResolver);
visitor.visitBeanDefinition(bd);
}
beanFactory.registerSingleton("obscenitiesRemoved",
this.obscenitiesRemoved);
}
private boolean isObscene(Object value) {
String potentialObscenity = value.toString().toUpperCase();
return this.obscenities.contains(potentialObscenity);
}
public void setObscenities(Set<String> obscenities) {
this.obscenities.clear();
for (String obscenity : obscenities) {
this.obscenities.add(obscenity.toUpperCase());
}
}


public void setBeanName(String name) {
this.name = name;
}
}


There are two modifications in the post-processor: first, we make it bean-name aware
(BeanNameAware) and check that we are not changing BeanDefinition for this bean. After all, the ObscenityRemovingBeanFactoryPostProcessor is an ordinary bean. Next, we maintain a set of all replacements we have made and register that set as a singleton bean with the "obscenitiesRemoved" name. If we add System.out.println(beanFactory.getBean("obscenitiesRemoved")); to the sample application, it will print this


SimpleBean{password='****', username='****', connectionString='****'}
[bum, bollocks, winky]

{ 1 comments... read them below or add one }

  1. i think you should learn first HTML CSS for proper website designing... plz dont mind... u should maintain this. not visible clearly

    ReplyDelete

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 -