他可以获取beanfactory可以加载到的配置信息,然后可以修改这些信息,导致创建的bean得到了你期望的修改。
BeanFactoryPostProcessor的概念跟BeanPostProcessor相似:BeanFactoryPostProcessor会在Spring构建完BeanFactory之后,BeanFactory构建其他bean之前执行。
(提示:实际上,Spring可以检测到BeanFactoryPostProcessor bean并在BeanFactory初始化其他任何bean之前初始化他们)
Spring中BeanFactory的回调处理器:
AspectJWeavingEnabler:此回调处理器注册AspectJ的ClassPreProcessorAgentAdapter类并在Spring的LoadTimeWeaver中使用。
Post-processor that registers AspectJ's org.aspectj.weaver.loadtime.ClassPreProcessorAgentAdapter with the Spring application context's default org.springframework.instrument.classloading.LoadTimeWeaver.
CustomAutowireConfigurer:此类可以让你指定注解,除了@Qualifier之外,标识一个bean是自动织入的志愿者。
A org.springframework.beans.factory.config.BeanFactoryPostProcessor implementation that allows for convenient registration of custom autowire qualifier types.
<bean id="customAutowireConfigurer" class="org.springframework.beans.factory.annotation.CustomAutowireConfigurer">
<property name="customQualifierTypes">
<set>
<value>mypackage.MyQualifier</value>
</set>
</property>
</bean>
CustomEditorConfigurer:此类注册一个PropertyEditor实现,该实现用户将配置文件中的字符串值转换为bean需要的类型。
BeanFactoryPostProcessor implementation that allows for convenient registration of custom property editors.
As of Spring 2.0, the recommended usage is to use custom PropertyEditorRegistrar implementations that in turn register any desired editors on a given registry. Each PropertyEditorRegistrar can register any number of custom editors.
<bean id="customEditorConfigurer" class="org.springframework.beans.factory.config.CustomEditorConfigurer">
<property name="propertyEditorRegistrars">
<list>
<bean class="mypackage.MyCustomDateEditorRegistrar"/>
<bean class="mypackage.MyObjectEditorRegistrar"/>
</list>
</property>
</bean>
Alternative configuration example with custom editor classes:
<bean id="customEditorConfigurer" class="org.springframework.beans.factory.config.CustomEditorConfigurer">
<property name="customEditors">
<map>
<entry key="java.util.Date" value="mypackage.MyCustomDateEditor"/>
<entry key="mypackage.MyObject" value="mypackage.MyObjectEditor"/>
</map>
</property>
</bean>
Also supports "java.lang.String[]"-style array class names and primitive class names (e.g. "boolean"). Delegates to ClassUtils for actual class name resolution.
CustomScopeConfigurer:使用回调处理器在配置文件中配置自定义作用域(除了单例、原型、请求、会话和全局会话之外)。赋值作用域属性到一个Map类型,他包含作用域名的键,并使用作用域接口的实现作为值。
Simple BeanFactoryPostProcessor implementation that registers custom Scope(s) with the containing ConfigurableBeanFactory.
Will register all of the supplied scopes with the ConfigurableListableBeanFactory that is passed to the postProcessBeanFactory(ConfigurableListableBeanFactory) method.
This class allows for declarative registration of custom scopes. Alternatively, consider implementing a custom BeanFactoryPostProcessor that calls ConfigurableBeanFactory.registerScope programmatically.
PreferencesPlaceholderConfigurer:此回调处理器将JDK1.4Preperences API替换bean属性中的值,此Preperences API标识他将解析来自用户Preperences的值,然后系统Preperences获得值,最后从一个引用文件获得值。
Subclass of PropertyPlaceholderConfigurer that supports JDK 1.4's Preferences API (java.util.prefs).
Tries to resolve placeholders as keys first in the user preferences, then in the system preferences, then in this configurer's properties. Thus, behaves like PropertyPlaceholderConfigurer if no corresponding preferences defined.
Supports custom paths for the system and user preferences trees. Also supports custom paths specified in placeholders ("myPath/myPlaceholderKey"). Uses the respective root node if not specified.
PropertyOverrideConfigurer:此回调处理器将替换bean属性值,而值是从指定属性文件装载的。他将从属性文件搜索使用bean名和参数构造的属性。对于bean x,他将在属性文件中查找x.a。若属性并不存在,回调处理器将不会理睬从配置文件中发现的值。
Property resource configurer that overrides bean property values in an application context definition. It pushes values from a properties file into bean definitions.
Configuration lines are expected to be of the following form:
beanName.property=value
Example properties file:
dataSource.driverClassName=com.mysql.jdbc.Driver
dataSource.url=jdbc:mysql:mydb
In contrast to PropertyPlaceholderConfigurer, the original definition can have default values or no values at all for such bean properties. If an overriding properties file does not have an entry for a certain bean property, the default context definition is used.
Note that the context definition is not aware of being overridden; so this is not immediately obvious when looking at the XML definition file.
In case of multiple PropertyOverrideConfigurers that define different values for the same bean property, the last one will win (due to the overriding mechanism).
Property values can be converted after reading them in, through overriding the convertPropertyValue method. For example, encrypted values can be detected and decrypted accordingly before processing them.
PropertyPlaceholderConfigurer:此回调处理器将替换从已配置的属性文件装载的属性值。只要值符合某种格式规则,就会发生替换。
A property resource configurer that resolves placeholders in bean property values of context definitions. It pulls values from a properties file into bean definitions.
The default placeholder syntax follows the Ant / Log4J / JSP EL style:
${...}
Example XML context definition:
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName"><value>${driver}</value></property>
<property name="url"><value>jdbc:${dbname}</value></property>
</bean>
Example properties file:
driver=com.mysql.jdbc.Driver
dbname=mysql:mydb
PropertyPlaceholderConfigurer checks simple property values, lists, maps, props, and bean names in bean references. Furthermore, placeholder values can also cross-reference other placeholders, like:
rootPath=myrootdir
subPath=${rootPath}/subdir
In contrast to PropertyOverrideConfigurer, this configurer allows to fill in explicit placeholders in context definitions. Therefore, the original definition cannot specify any default values for such bean properties, and the placeholder properties file is supposed to contain an entry for each defined placeholder.
If a configurer cannot resolve a placeholder, a BeanDefinitionStoreException will be thrown. If you want to check against multiple properties files, specify multiple resources via the "locations" setting. You can also define multiple PropertyPlaceholderConfigurers, each with its own placeholder syntax.
Default property values can be defined via "properties", to make overriding definitions in properties files optional. A configurer will also check against system properties (e.g. "user.dir") if it cannot resolve a placeholder with any of the specified properties. This can be customized via "systemPropertiesMode".
Note that the context definition is aware of being incomplete; this is immediately obvious to users when looking at the XML definition file. Hence, placeholders have to be resolved; any desired defaults have to be defined as placeholder values as well (for example in a default properties file).
Property values can be converted after reading them in, through overriding the convertPropertyValue method. For example, encrypted values can be detected and decrypted accordingly before processing them.
ServletContextPropertyPlaceholderConfigurer:此回调处理器泛化了PropertyPlaceholderConfigurer类。因此,只要bean属性遵照指定命名规范,他就替换bean的属性。除了他的超类,此处理器还将从处理应用程序的servlet上下文参数入口装载值。
Subclass of PropertyPlaceholderConfigurer that resolves placeholders as ServletContext init parameters (that is, web.xml context-param entries).
Can be combined with "locations" and/or "properties" values in addition to web.xml context-params. Alternatively, can be defined without local properties, to resolve all placeholders as web.xml context-params (or JVM system properties).
If a placeholder could not be resolved against the provided local properties within the application, this configurer will fall back to ServletContext parameters. Can also be configured to let ServletContext init parameters override local properties (contextOverride=true).
Optionally supports searching for ServletContext attributes: If turned on, an otherwise unresolvable placeholder will matched against the corresponding ServletContext attribute, using its stringified value if found. This can be used to feed dynamic values into Spring's placeholder resolution.
If not running within a WebApplicationContext (or any other context that is able to satisfy the ServletContextAware callback), this class will behave like the default PropertyPlaceholderConfigurer. This allows for keeping ServletContextPropertyPlaceholderConfigurer definitions in test suites.
例子:
- <?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>
调用获取BeanFactoryPostProcessor:
- 下面的获取可以让你明白什么情况下也使用了BeanFactoryPostProcessor,或者BeanFactoryPostProcessor的作用。
- ConfigurableListableBeanFactory beanFactory = new XmlBeanFactory(
- new ClassPathResource("/META-INF/spring/bfpp2-context.xml")
- );
- BeanFactoryPostProcessor bfpp = (BeanFactoryPostProcessor)beanFactory.getBean("bfpp");
- bfpp.postProcessBeanFactory(beanFactory);
- System.out.println(beanFactory.getBean("simpleBean"));
编写一个BeanFactoryPostProcessor:
- package cn.partner4java.beanfactorypostprocessor;
- import java.util.HashSet;
- import java.util.Set;
- import org.springframework.beans.BeansException;
- import org.springframework.beans.factory.BeanNameAware;
- import org.springframework.beans.factory.config.BeanDefinition;
- import org.springframework.beans.factory.config.BeanDefinitionVisitor;
- import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
- import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
- import org.springframework.util.StringValueResolver;
- /**
- * 删除非法字符
- * @author partner4java
- *
- */
- public class ObscenityRemovingBeanFactoryPostProcessor implements
- BeanFactoryPostProcessor, BeanNameAware {
- /** bean的名称 */
- private String name;
- /** 注册过滤文字 */
- private Set<String> obscenities;
- /** 返回过滤掉的文字 */
- private Set<String> obscenitiesRemoved;
- public ObscenityRemovingBeanFactoryPostProcessor() {
- this.obscenities = new HashSet<String>();
- this.obscenitiesRemoved = new HashSet<String>();
- }
- /**
- * 主要业务处理。
- */
- public void postProcessBeanFactory(
- ConfigurableListableBeanFactory beanFactory) throws BeansException {
- String[] beanNames = beanFactory.getBeanDefinitionNames();
- //下面两个类是用来替换参数的
- //Simple strategy interface for resolving a String value.
- StringValueResolver valueResolver = new StringValueResolver() {
- public String resolveStringValue(String strVal) {
- if(isObscene(strVal)){
- obscenitiesRemoved.add(strVal);
- return "****";
- }
- return strVal;
- }
- };
- //Visitor class for traversing BeanDefinition objects, in particular the property values and constructor argument values contained in them, resolving bean metadata values.
- //Used by PropertyPlaceholderConfigurer to parse all String values contained in a BeanDefinition, resolving any placeholders found.
- BeanDefinitionVisitor visitor = new BeanDefinitionVisitor(valueResolver);
- for(String beanName:beanNames){
- if(beanName.equals(this.name)) continue;
- //如果不是实体就应该是参数,获取参数
- BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName);
- visitor.visitBeanDefinition(beanDefinition);
- }
- 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 obscentity:obscenities){
- this.obscenities.add(obscentity.toUpperCase());
- }
- }
- public void setBeanName(String name) {
- this.name = name;
- }
- }
配置文件:
- <?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="cn.partner4java.beanfactorypostprocessor.ObscenityRemovingBeanFactoryPostProcessor">
- <property name="obscenities">
- <set>
- <value>winky</value>
- <value>bum</value>
- </set>
- </property>
- </bean>
- <bean id="simpleBean" class="cn.partner4java.beanfactorypostprocessor.SimpleBean">
- <property name="connectionString" value="bollocks"/>
- <property name="password" value="winky"/>
- <property name="username" value="bum"/>
- </bean>
- </beans>
调用:
- ConfigurableListableBeanFactory beanFactory = new XmlBeanFactory(
- new ClassPathResource("/META-INF/spring/spring-beanfactorypostprocessor.xml")
- );
- BeanFactoryPostProcessor bfpp = (BeanFactoryPostProcessor)beanFactory.getBean("bfpp");
- bfpp.postProcessBeanFactory(beanFactory);
- SimpleBean simpleBean = (SimpleBean) beanFactory.getBean("simpleBean");
- System.out.println(simpleBean);
- System.out.println(beanFactory.getBean("obscenitiesRemoved"));
后台打印:
SimpleBean{password='****', username='****', connectionString='bollocks'}
[bum, winky]