You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring PropertyPlaceholderConfigurer如何同时从文件与数据库加载属性并实现依赖

Got it, let's work through this problem together. The root issue here is that Spring's default property loading tries to resolve all placeholders in one go—so when it tries to load properties from the database, the JDBC config in your jdbc.properties hasn't been resolved yet, hence the failure.

The fix is to split the property loading into two distinct phases: first load the JDBC config from the properties file, then use that config to connect to the database and load your application properties. Here's how to implement this:

解决方案:分阶段配置PropertyPlaceholderConfigurer

1. 先加载JDBC属性文件

First, create a placeholder configurer that only loads your jdbc.properties file, and set it to run first (using the order property—lower values mean higher priority). This ensures the database connection details are available in the Spring context before we try to access the database.

XML配置示例

<!-- Load JDBC config first -->
<bean class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer">
    <property name="order" value="1"/>
    <property name="locations">
        <list>
            <value>classpath:jdbc.properties</value>
        </list>
    </property>
    <property name="ignoreUnresolvablePlaceholders" value="false"/>
</bean>

JavaConfig配置示例

@Configuration
public class AppConfig {

    // Load JDBC properties first, highest priority
    @Bean
    public static PropertySourcesPlaceholderConfigurer jdbcPropertyConfigurer() {
        PropertySourcesPlaceholderConfigurer configurer = new PropertySourcesPlaceholderConfigurer();
        configurer.setOrder(1);
        configurer.setLocations(new ClassPathResource("jdbc.properties"));
        configurer.setIgnoreUnresolvablePlaceholders(false);
        return configurer;
    }
}

2. 配置数据源并加载数据库属性

Next, create a DataSource bean using the JDBC properties we just loaded. Then create a second placeholder configurer that uses this datasource to fetch properties from the database, setting it to run after the first one.

XML配置示例

<!-- DataSource using the JDBC properties from the first configurer -->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    <property name="driverClassName" value="${jdbc.driverClassName}"/>
    <property name="url" value="${jdbc.url}"/>
    <property name="username" value="${jdbc.username}"/>
    <property name="password" value="${jdbc.password}"/>
</bean>

<!-- Load properties from database, runs after JDBC config is loaded -->
<bean class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer">
    <property name="order" value="2"/>
    <property name="ignoreUnresolvablePlaceholders" value="true"/>
    <property name="properties">
        <bean class="org.springframework.jdbc.core.JdbcTemplate">
            <property name="dataSource" ref="dataSource"/>
            <property name="query">
                <!-- Replace with your actual query to fetch config key-value pairs -->
                <value>SELECT config_key, config_value FROM app_config</value>
            </property>
            <property name="rowMapper">
                <bean class="org.springframework.jdbc.core.BeanPropertyRowMapper">
                    <constructor-arg value="java.util.Map.Entry"/>
                </bean>
            </property>
        </bean>
    </property>
</bean>

JavaConfig配置示例

@Configuration
public class AppConfig {

    // ... (keep the jdbcPropertyConfigurer bean from step 1)

    // DataSource using resolved JDBC properties
    @Bean
    public DataSource dataSource(
            @Value("${jdbc.driverClassName}") String driverClassName,
            @Value("${jdbc.url}") String url,
            @Value("${jdbc.username}") String username,
            @Value("${jdbc.password}") String password) {
        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setDriverClassName(driverClassName);
        dataSource.setUrl(url);
        dataSource.setUsername(username);
        dataSource.setPassword(password);
        return dataSource;
    }

    // Load properties from database, runs after JDBC config
    @Bean
    public static PropertySourcesPlaceholderConfigurer dbPropertyConfigurer(DataSource dataSource) {
        PropertySourcesPlaceholderConfigurer configurer = new PropertySourcesPlaceholderConfigurer();
        configurer.setOrder(2);
        configurer.setIgnoreUnresolvablePlaceholders(true);
        
        // Fetch properties from database using JdbcTemplate
        JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
        Properties dbProperties = new Properties();
        List<Map<String, Object>> configRows = jdbcTemplate.queryForList(
                "SELECT config_key, config_value FROM app_config");
        
        for (Map<String, Object> row : configRows) {
            dbProperties.put(row.get("config_key"), row.get("config_value"));
        }
        
        configurer.setProperties(dbProperties);
        return configurer;
    }
}

关键注意事项

  • Table Structure: Make sure your database table (like app_config in the examples) has two columns: one for the property key (config_key) and one for the value (config_value), storing your app config as key-value pairs.
  • Order Property: The order property is critical—lower values run first. The first configurer loads JDBC details, the second uses those to load database properties.
  • Ignore Unresolvable Placeholders: Set ignoreUnresolvablePlaceholders=true on the second configurer so it doesn't throw errors for placeholders that were already resolved by the first configurer (or will be resolved elsewhere).

This approach ensures that your database connection details are fully resolved before Spring tries to connect to the database and load your application properties—exactly what you need!

内容的提问来源于stack exchange,提问作者Jonny

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 07:49:19