接入 Apollo 后,普通配置修改能很快看到新值,数据库连接配置却没有变化。这种情况应拆成三层检查:客户端是否拿到新配置,Spring 对象是否更新,以及连接池是否实际使用了新配置。
配置变化不等于连接已经重建
直接通过 Config API 读取时,可以取得客户端当前配置;通过 Spring 注入的值,还取决于注入方式、集成配置与版本。即使 Bean 上某个字段已经变化,之前创建的数据源、已有连接和正在运行的事务也不会因此自动替换。
@Value 与 @ConfigurationProperties 的处理机制不同,不要看到前者能刷新,就假设后者及其创建的所有组件也会刷新。相关用法可对照 Apollo Java 客户端指南中对应的 Spring 集成说明。
对 @ConfigurationProperties,指南还给出了结合 EnvironmentChangeEvent 或 RefreshScope 的用法。它们涉及属性重绑定或 Bean 刷新,但不能替代对已有连接、事务和连接池关闭时机的设计;实际效果也取决于项目的 Spring 集成与版本。
先验证客户端是否收到变化
下面是 Config API 的监听片段;需要使用与项目匹配的 Apollo Client 依赖:
import com.ctrip.framework.apollo.Config;
import com.ctrip.framework.apollo.ConfigService;
Config config = ConfigService.getAppConfig();
config.addChangeListener(event -> {
boolean changed = event.changedKeys().stream()
.anyMatch(key -> key.startsWith("spring.datasource."));
if (changed) {
// 记录配置变更事件,交给受控的刷新流程处理。
// 不在这里输出密码,也不要直接关闭正在使用的连接池。
}
});
监听器只说明收到了变化,不是一套数据源切换实现。密码、连接串中的敏感信息不能直接写入日志。使用多个 namespace 时,还要监听真正存放这些配置的 namespace。
有状态数据源怎样处理
一个较清楚的切换流程是:
- 读取同一组配置,校验地址、驱动和必要凭据是否齐全。
- 按连接池支持的方式创建或更新目标数据源。
- 用受控检查确认新数据源可用,再让新请求进入。
- 给旧连接和已有事务保留明确的退出策略。
- 记录切换结果;新配置失败时,不把整个系统切到不可用状态。
多个字段分次发布时,要避免读到“新地址+旧凭据”的混合状态。变更事件的合并、版本检查和重复处理也应纳入设计。
Apollo dynamic-datasource 用例可以帮助理解如何连接配置监听与数据源,但接入时仍须选择匹配的版本,并核对自己使用的连接池和事务方式,不能仅复制一个刷新注解。
判断是否真的生效
分别观察配置读取结果、实际使用的数据源对象,以及新建连接的目标。仅看到配置页面更新或字段值改变,不足以证明数据库访问已切换。
最后检查已有事务、连接回收、并发请求和失败回退。配置中心负责分发变化,有状态组件的生命周期仍需要应用明确管理;这就是普通属性能刷新、数据库连接却可能继续沿用旧配置的原因。