BeanFactoryPostProcessor的作用

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&amp;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;
	}
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值