[Spring] 多个 PropertyPlaceholderConfigurer 导致占位符未替换问题

这是一个 Spring 项目,
第一个 PropertyPlaceholderConfigurer ,在 context-aaa.xml 主要是配置 JDBC properties


    <bean id="jdbcPropertyPlaceholder"
          class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="order" value="0"/>
        <property name="ignoreUnresolvablePlaceholders" value="true"/>
        <property name="location">
            <value>classpath:jdbc.properties</value>
        </property>
    </bean>
    

其中,jdbc.properties 的内容如下:

test.datasource.url=jdbc:mysql://192.168.0.66:3306/dev
test.datasource.username=root
test.datasource.password=123456

第二个 PropertyPlaceholderConfigurer ,在 context-bbb.xml ,功能是从数据里加载 properties


    <bean id="commonsConfigurationPropertyPlaceholder"
          class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="order" value="1"/>
        <property name="ignoreUnresolvablePlaceholders" value="true"/>
        <property name="properties" ref="commonsConfigurationFactoryBean"/>
    </bean>

    <bean name="commonsConfigurationFactoryBean"
          class="org.springmodules.commons.configuration.CommonsConfigurationFactoryBean">
        <constructor-arg ref="configuration"/>
    </bean>
    
    <bean id="configuration" class="org.apache.commons.configuration.DatabaseConfiguration">
        <constructor-arg type="javax.sql.DataSource" ref="druidDataSource"/>
        <constructor-arg index="1" value="configuration"/>
        <constructor-arg index="2" value="name"/>
        <constructor-arg index="3" value="value"/>
    </bean>
                

    <bean id="druidDataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="url"      value="${test.datasource.url}"/>
        <property name="username" value="${test.datasource.username}"/>
        <property name="password" value="${test.datasource.password}"/>
    </bean>

问题来了,加载 DruidDataSource 时,占位符并没有被替换。

我已经加了 PropertyPlaceholderConfigurer 的 order 属性排序,以及 ignoreUnresolvablePlaceholders 为 true 了,但是问题依旧。

DruidDataSource 作为第二个 PropertyPlaceholderConfigurer 的依赖,它的配置占位符不会被处理吗?
我断点发现,BeanFactoryPostProcessor 的处理,在程序的报错之后才执行,是怎么回事?

https://jira.spring.io/browse...

我找到了解决方案:
The alternative is to

(a) use the new PropertySourcesPlaceholderConfigurer instead of the traditional PropertyPlaceholderConfigurer;

(b) eliminate the first PropertySourcesPlaceholderConfigurer ;

(c) register a PropertySource with the ApplicationContext's Environment that contains the properties for the placeholders that need replacement in the PropertySourcesPlaceholderConfigurer

我想问第三步怎么操作啊?

阅读 4.6k
2 个回答

检查一下是否是加了 PropertyPlaceholderConfigurer 的 order 属性排序,以及 ignoreUnresolvablePlaceholders 为 true 后xml文件没有生效的原因。

如果我没有理解错,你的执行逻辑是:

DruidDataSource属性 依赖 -> jdbc.properties
其他beans属性 依赖 -> DruidDataSource

那么你需要做的是在spring创建beans后

做后处理之前为DruidDataSource设置属性

做后处理之后为其他beans创建PropertyPlaceholder

如下方式可供参考(代码需要根据你的情况修改后才能用):

package com.bixuebihui;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;


public class BeanPostPrcessorImpl implements BeanPostProcessor {
    private Properties properties="jdbc.properties";
    
    // Bean 实例化之前进行的处理
    public Object postProcessBeforeInitialization(Object bean, String beanName)
           throws BeansException {
       //System.out.println("对象" + beanName + "开始实例化");
        if(beanName.equals("druidDataSource")){
            try {
                //set druidDataSource's properties use properties
                ((DruidDataSource)bean).setUrl(properties.getProperty("url"));
                ......
            } catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {
                e.printStackTrace();
            }
        }
       return bean;
    }

    // Bean 实例化之后进行的处理
    public Object postProcessAfterInitialization(Object bean, String beanName)
           throws BeansException {
       //System.out.println("对象" + beanName + "实例化完成");
        //<bean class="com.spring.test.di.BeanPostPrcessorImpl"/>
       return bean;
    }
    
    public String getProperties() {
        return properties;
    }

    public void setProperties(Properties properties) {
        this.properties = properties;
    }
}
    <bean id="properties"
      class="org.springframework.beans.factory.config.PropertiesFactoryBean">
    <property name="locations">
        <list>
        <value>classpath:jdbc.properties</value>
        </list>
    </property>
    </bean>

    <bean class="com.bixuebihui.BeanPostPrcessorImpl">
        <property name="properties" value="properties" />
    </bean>

参考:
https://segmentfault.com/a/11...

推荐问题
宣传栏