天天看點

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