BeanFactoryPostProcessor接口定义
接口作用:可以在创建bean实例之前,动态修改bean定义的属性值
public interface BeanFactoryPostProcessor {
/**
* Modify the application context's internal bean factory after its standard
* initialization. All bean definitions will have been loaded, but no beans
* will have been instantiated yet. This allows for overriding or adding
* properties even to eager-initializing beans.
* @param beanFactory the bean factory used by the application context
* @throws org.springframework.beans.BeansException in case of errors
*/
void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
}
应用举例
PropertyPlaceholderConfigurer类实现BeanFactoryPostProcessor接口,实现动态修改jdbc数据源dataSource的属性(属性如:url,name,password)值
<!-- properties引入配置 -->
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:jdbc.properties</value>
</list>
</property>
</bean>
jdbc.properties
#MySQL JDBC config
jdbc.url=jdbc:mysql://localhost:3306/managementsystem?useUnicode=true&characterEncoding=utf-8
jdbc.driveClass=com.mysql.jdbc.Driver
jdbc.username=root
jdbc.password=123456
jdbc.maxActive=5
jdbc.initialSize=2
Bean定义(dataSource)
<bean id="dataSource" class="org.apache.tomcat.jdbc.pool.DataSource">
<property name="poolProperties">
<bean class="org.apache.tomcat.jdbc.pool.PoolProperties">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</bean>
</property>
</bean>
源码分析
public abstract class PropertyResourceConfigurer extends PropertiesLoaderSupport
implements BeanFactoryPostProcessor, PriorityOrdered {
/******************************省略无关代码*************************************/
/**
* {@linkplain #mergeProperties Merge}, {@linkplain #convertProperties convert} and
* {@linkplain #processProperties process} properties against the given bean factory.
* @throws BeanInitializationException if any properties cannot be loaded
*/
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
try {
// 获取 jdbc.properties 属性值
Properties mergedProps = mergeProperties();
// Convert the merged properties, if necessary.
convertProperties(mergedProps);
// Let the subclass process the properties.
// 对bean的属性进行处理
processProperties(beanFactory, mergedProps);
}
catch (IOException ex) {
throw new BeanInitializationException("Could not load properties", ex);
}
}
/******************************省略无关代码*************************************/
}
PropertyPlaceholderConfigurer(属性占位符配置解析器)
作用:专门用来解析替换${...}属性值的
public class PropertyPlaceholderConfigurer extends PlaceholderConfigurerSupport {
/******************************省略无关代码*************************************/
@Override
protected void processProperties(ConfigurableListableBeanFactory beanFactoryToProcess, Properties props)
throws BeansException {
// ${...}属性解析器
StringValueResolver valueResolver = new PlaceholderResolvingStringValueResolver(props);
// 替换${...}占位符
doProcessProperties(beanFactoryToProcess, valueResolver);
}
/******************************省略无关代码*************************************/
}
PlaceholderConfigurerSupport(占位符解析功能)
作用:遍历所有的bean,并对bean定义属性值中的占位符进行解析
public abstract class PlaceholderConfigurerSupport extends PropertyResourceConfigurer
implements BeanNameAware, BeanFactoryAware {
/******************************省略无关代码*************************************/
protected void doProcessProperties(ConfigurableListableBeanFactory beanFactoryToProcess,
StringValueResolver valueResolver) {
BeanDefinitionVisitor visitor = new BeanDefinitionVisitor(valueResolver);
String[] beanNames = beanFactoryToProcess.getBeanDefinitionNames();
// 遍历所有的bean
for (String curName : beanNames) {
// Check that we're not parsing our own bean definition,
// to avoid failing on unresolvable placeholders in properties file locations.
if (!(curName.equals(this.beanName) && beanFactoryToProcess.equals(this.beanFactory))) {
// 获取bean定义
BeanDefinition bd = beanFactoryToProcess.getBeanDefinition(curName);
try {
// 访问bean定义进行属性替换
visitor.visitBeanDefinition(bd);
}
catch (Exception ex) {
throw new BeanDefinitionStoreException(bd.getResourceDescription(), curName, ex.getMessage(), ex);
}
}
}
// New in Spring 2.5: resolve placeholders in alias target names and aliases as well.
beanFactoryToProcess.resolveAliases(valueResolver);
// New in Spring 3.0: resolve placeholders in embedded values such as annotation attributes.
beanFactoryToProcess.addEmbeddedValueResolver(valueResolver);
}
}
BeanDefinitionVisitor(Bean属性定义访问器)
作用:解析属性或者构造方法里面的占位符,并且把解析的结果更新到 BeanDefinition 中
public class BeanDefinitionVisitor {
/******************省略无关代码**************************************/
/**
* Traverse the given BeanDefinition object and the MutablePropertyValues
* and ConstructorArgumentValues contained in them.
* @param beanDefinition the BeanDefinition object to traverse
* @see #resolveStringValue(String)
*/
public void visitBeanDefinition(BeanDefinition beanDefinition) {
visitParentName(beanDefinition);
visitBeanClassName(beanDefinition);
visitFactoryBeanName(beanDefinition);
visitFactoryMethodName(beanDefinition);
visitScope(beanDefinition);
// 访问bean定义的所有属性并进行占位符属性值替换
visitPropertyValues(beanDefinition.getPropertyValues());
ConstructorArgumentValues cas = beanDefinition.getConstructorArgumentValues();
visitIndexedArgumentValues(cas.getIndexedArgumentValues());
visitGenericArgumentValues(cas.getGenericArgumentValues());
}
protected void visitPropertyValues(MutablePropertyValues pvs) {
PropertyValue[] pvArray = pvs.getPropertyValues();
for (PropertyValue pv : pvArray) {
// 占位符属性值替换
Object newVal = resolveValue(pv.getValue());
if (!ObjectUtils.nullSafeEquals(newVal, pv.getValue())) {
pvs.add(pv.getName(), newVal);
}
}
}
protected Object resolveValue(Object value) {
if (value instanceof BeanDefinition) {
visitBeanDefinition((BeanDefinition) value);
}
else if (value instanceof BeanDefinitionHolder) {
visitBeanDefinition(((BeanDefinitionHolder) value).getBeanDefinition());
}
/************************省略无关部分代码*************************/
else if (value instanceof TypedStringValue) {
TypedStringValue typedStringValue = (TypedStringValue) value;
String stringValue = typedStringValue.getValue();
if (stringValue != null) {
// 将占位符替换成实际属性值
String visitedString = resolveStringValue(stringValue);
typedStringValue.setValue(visitedString);
}
}
else if (value instanceof String) {
return resolveStringValue((String) value);
}
return value;
}
}