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

如何通过数据库动态配置application.properties实现产品属性实时获取?

动态从数据库加载产品属性的解决方案

一、自定义配置源(Spring Boot 环境)

如果是基于Spring Boot的项目,可通过实现PropertySource将数据库属性整合到Spring配置体系,支持运行时读取与动态刷新。

1. 实现自定义PropertySource

  • 先定义对应数据库表的实体类(示例表字段:product_code, config_key, config_value):
public class ProductConfig {
    private String productCode;
    private String configKey;
    private String configValue;
    // getter、setter略
}
  • 实现PropertySource,重写属性查询逻辑:
public class DbPropertySource extends PropertySource<JdbcTemplate> {
    private static final String NAME = "DbPropertySource";
    private final JdbcTemplate jdbcTemplate;

    public DbPropertySource(JdbcTemplate jdbcTemplate) {
        super(NAME, jdbcTemplate);
        this.jdbcTemplate = jdbcTemplate;
    }

    @Override
    public Object getProperty(String name) {
        // 约定属性名格式为 product.{产品编码}.{配置键},比如 product.pay.maxAmount
        if (name.startsWith("product.")) {
            String[] parts = name.split("\\.", 3);
            if (parts.length == 3) {
                String productCode = parts[1];
                String key = parts[2];
                String sql = "SELECT config_value FROM product_config WHERE product_code = ? AND config_key = ?";
                try {
                    return jdbcTemplate.queryForObject(sql, new Object[]{productCode, key}, String.class);
                } catch (EmptyResultDataAccessException e) {
                    return null; // 无匹配属性时返回null,不影响原有配置逻辑
                }
            }
        }
        return null;
    }
}
  • 通过EnvironmentPostProcessor将自定义源注册到Spring环境:
public class DbPropertySourceProcessor implements EnvironmentPostProcessor {
    @Override
    public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
        // 直接从环境获取数据源,避免循环依赖
        DataSource dataSource = environment.getRequiredProperty("spring.datasource", DataSource.class);
        JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
        DbPropertySource dbPropertySource = new DbPropertySource(jdbcTemplate);
        // 优先使用数据库配置,将其添加到属性源最前面
        environment.getPropertySources().addFirst(dbPropertySource);
    }
}
  • 在src/main/resources/META-INF/spring.factories中注册处理器:
org.springframework.boot.env.EnvironmentPostProcessor=com.yourpackage.DbPropertySourceProcessor

2. 支持动态刷新

若需修改数据库配置后实时生效,结合@RefreshScope与刷新接口实现:

@RestController
public class ConfigRefreshController {
    private final ConfigurableEnvironment environment;
    private final JdbcTemplate jdbcTemplate;
    private final ContextRefresher contextRefresher;

    public ConfigRefreshController(ConfigurableEnvironment environment, JdbcTemplate jdbcTemplate, ContextRefresher contextRefresher) {
        this.environment = environment;
        this.jdbcTemplate = jdbcTemplate;
        this.contextRefresher = contextRefresher;
    }

    @PostMapping("/refresh-product-config")
    public String refresh() {
        // 移除旧的数据库属性源,添加新实例
        MutablePropertySources propertySources = environment.getPropertySources();
        propertySources.remove(DbPropertySource.NAME);
        propertySources.addFirst(new DbPropertySource(jdbcTemplate));
        // 触发RefreshScope注解的Bean刷新
        contextRefresher.refresh();
        return "产品配置已刷新";
    }
}

注意:需引入spring-boot-starter-actuator依赖,并在配置中开启refresh端点。

二、轻量配置服务封装(非Spring生态/简单场景)

如果项目不依赖Spring体系,可自行封装配置服务类,结合缓存+定时刷新实现动态读取:

public class ProductConfigService {
    private static ProductConfigService instance;
    private final Map<String, Map<String, String>> productConfigCache = new ConcurrentHashMap<>();
    private final JdbcTemplate jdbcTemplate;
    private static final long REFRESH_INTERVAL = 5 * 60 * 1000; // 5分钟刷新一次缓存

    private ProductConfigService(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
        loadConfigToCache();
        startRefreshTask();
    }

    public static synchronized ProductConfigService getInstance(JdbcTemplate jdbcTemplate) {
        if (instance == null) {
            instance = new ProductConfigService(jdbcTemplate);
        }
        return instance;
    }

    private void loadConfigToCache() {
        String sql = "SELECT product_code, config_key, config_value FROM product_config";
        List<ProductConfig> configs = jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(ProductConfig.class));
        productConfigCache.clear();
        for (ProductConfig config : configs) {
            productConfigCache.computeIfAbsent(config.getProductCode(), k -> new ConcurrentHashMap<>())
                    .put(config.getConfigKey(), config.getConfigValue());
        }
    }

    private void startRefreshTask() {
        ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor(r -> {
            Thread t = new Thread(r);
            t.setDaemon(true);
            return t;
        });
        executor.scheduleAtFixedRate(this::loadConfigToCache, REFRESH_INTERVAL, REFRESH_INTERVAL, TimeUnit.MILLISECONDS);
    }

    public String getConfig(String productCode, String key) {
        return productConfigCache.getOrDefault(productCode, Collections.emptyMap()).get(key);
    }
}

业务代码中直接调用ProductConfigService.getInstance(jdbcTemplate).getConfig("pay", "maxAmount")即可获取最新配置,无需重启服务。

三、关键注意事项

  • 数据库表优化:添加update_time字段,刷新时仅查询更新时间晚于上次刷新时间的记录,提升性能
  • 容错机制:数据库查询失败时保留旧缓存,避免服务不可用
  • 实时性需求:若需配置变更立即生效,可通过数据库触发器、消息队列(如RabbitMQ)发送变更通知,触发缓存刷新

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 09:10:44