本文目录导读:

Java配置热更新是指在应用运行时动态修改配置,无需重启服务即可生效,以下是几种常见实现方案及案例:
Spring Cloud Config + Spring Cloud Bus
方案特点:基于消息总线,支持配置中心统一管理
实现步骤:
// 1. 配置类 - 支持热更新
@Configuration
@RefreshScope
public class AppConfig {
@Value("${app.timeout:1000}")
private int timeout;
@Value("${app.feature.enabled:false}")
private boolean featureEnabled;
// getter方法
}
// 2. 配置刷新端点
@RestController
@RefreshScope
public class ConfigController {
@Autowired
private AppConfig appConfig;
@GetMapping("/config")
public Map<String, Object> getConfig() {
return Map.of(
"timeout", appConfig.getTimeout(),
"featureEnabled", appConfig.isFeatureEnabled()
);
}
}
配置刷新方式:
# 手动刷新 curl -X POST http://localhost:8080/actuator/refresh # 通过消息总线刷新所有节点 curl -X POST http://localhost:8080/actuator/bus-refresh
基于数据库的配置热更新
方案特点:灵活,支持动态修改,适合需要持久化配置的场景
实现示例:
// 1. 配置实体
@Entity
@Table(name = "system_config")
public class SystemConfig {
@Id
private String configKey;
private String configValue;
private String description;
// getter/setter
}
// 2. 配置管理器 - 支持热更新
@Component
public class DynamicConfigManager implements ApplicationContextAware {
private static final Map<String, String> configCache = new ConcurrentHashMap<>();
private ApplicationContext applicationContext;
@Autowired
private SystemConfigRepository configRepository;
// 初始加载配置
@PostConstruct
public void init() {
loadConfigFromDatabase();
}
// 从数据库加载配置到缓存
public void loadConfigFromDatabase() {
List<SystemConfig> configs = configRepository.findAll();
configs.forEach(config ->
configCache.put(config.getConfigKey(), config.getConfigValue())
);
}
// 获取配置值
public String getConfig(String key, String defaultValue) {
return configCache.getOrDefault(key, defaultValue);
}
// 更新配置(热更新)
@Transactional
public void updateConfig(String key, String value) {
SystemConfig config = configRepository.findByConfigKey(key)
.orElse(new SystemConfig());
config.setConfigKey(key);
config.setConfigValue(value);
configRepository.save(config);
// 更新缓存
configCache.put(key, value);
// 发布配置变更事件
applicationContext.publishEvent(new ConfigChangeEvent(this, key, value));
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
}
// 3. 配置变更事件监听
@Component
public class ConfigChangeListener {
private static final Logger logger = LoggerFactory.getLogger(ConfigChangeListener.class);
@EventListener
public void handleConfigChange(ConfigChangeEvent event) {
logger.info("配置变更: key={}, newValue={}", event.getKey(), event.getValue());
// 根据配置key执行相应的业务逻辑
switch(event.getKey()) {
case "app.timeout":
// 更新连接池超时设置
break;
case "app.feature.enabled":
// 启用/禁用功能
break;
}
}
}
基于文件的配置热更新
方案特点:简单直接,适合单机部署
实现示例:
// 1. 文件监控配置
@Component
public class FileConfigWatcher {
private static final Logger logger = LoggerFactory.getLogger(FileConfigWatcher.class);
private static final Map<String, Object> config = new ConcurrentHashMap<>();
@PostConstruct
public void startWatching() throws IOException {
// 使用 WatchService 监控配置文件变化
WatchService watchService = FileSystems.getDefault().newWatchService();
Path configPath = Paths.get("/app/config");
configPath.register(watchService,
StandardWatchEventKinds.ENTRY_MODIFY);
// 启动监控线程
new Thread(() -> {
while (true) {
try {
WatchKey key = watchService.take();
List<WatchEvent<?>> events = key.pollEvents();
for (WatchEvent<?> event : events) {
if (event.kind() == StandardWatchEventKinds.ENTRY_MODIFY) {
Path changedFile = (Path) event.context();
if (changedFile.toString().endsWith(".properties")) {
reloadConfig(changedFile);
}
}
}
key.reset();
} catch (Exception e) {
logger.error("配置监控异常", e);
}
}
}).start();
// 初始加载
loadInitialConfig(configPath);
}
private void reloadConfig(Path file) {
try {
Properties props = new Properties();
try (InputStream input = Files.newInputStream(file)) {
props.load(input);
}
props.forEach((key, value) -> config.put((String) key, value));
logger.info("配置文件已热更新: {}", file);
// 发布配置变更事件
} catch (IOException e) {
logger.error("配置文件加载失败", e);
}
}
}
Apollo配置中心(生产推荐)
方案特点:企业级配置中心,支持实时推送、灰度发布
配置示例:
// 1. Maven依赖
<dependency>
<groupId>com.ctrip.framework.apollo</groupId>
<artifactId>apollo-client</artifactId>
<version>1.9.1</version>
</dependency>
// 2. 配置监听器
@Configuration
@EnableApolloConfig
public class ApolloConfig {
@ApolloConfig
private Config config;
@ApolloConfigChangeListener
public void onChange(ConfigChangeEvent changeEvent) {
for (String key : changeEvent.changedKeys()) {
ConfigChange change = changeEvent.getChange(key);
logger.info("配置变更: key={}, oldValue={}, newValue={}, changeType={}",
key, change.getOldValue(), change.getNewValue(), change.getChangeType());
// 执行热更新逻辑
switch(key) {
case "app.timeout":
// 更新超时设置
break;
}
}
}
// 3. 获取配置值
@Value("${app.name:default}")
private String appName;
// 或者通过Config对象获取
public String getConfig(String key) {
return config.getProperty(key, null);
}
}
最佳实践建议
配置热更新注意事项:
- 线程安全:使用
ConcurrentHashMap或ReentrantReadWriteLock - 事务一致性:配置更新和业务操作的事务边界
- 配置版本控制:记录配置变更历史
- 灰度发布:逐步推送配置到部分实例
- 回滚机制:支持配置快速回滚
- 监控告警:配置变更通知和异常告警
推荐方案选择:
| 场景 | 推荐方案 | 说明 |
|---|---|---|
| 微服务架构 | Apollo/Spring Cloud Config | 企业级功能,支持灰度发布 |
| 单机应用 | 文件监控/数据库 | 简单易实现 |
| 配置频繁变更 | 数据库方案 | 持久化,支持审计 |
| 实时性要求高 | Apollo/Nacos | 毫秒级推送 |
| 预算有限 | 开源Nacos | 功能全面,免费 |
完整示例项目结构:
// 配置热更新管理器基类
public abstract class ConfigManager<T> {
protected volatile T config;
protected final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
public T getConfig() {
lock.readLock().lock();
try {
return config;
} finally {
lock.readLock().unlock();
}
}
protected void updateConfig(T newConfig) {
lock.writeLock().lock();
try {
this.config = newConfig;
} finally {
lock.writeLock().unlock();
}
}
}
// 使用示例
@Component
public class TimeoutConfigManager extends ConfigManager<Integer> {
public TimeoutConfigManager(@Value("${app.timeout:1000}") int timeout) {
this.config = timeout;
}
@EventListener
public void onConfigChange(ConfigChangeEvent event) {
if ("app.timeout".equals(event.getKey())) {
updateConfig(Integer.parseInt(event.getValue()));
}
}
}
选择哪种方案取决于你的具体需求:配置变更频率、实时性要求、部署架构、团队技术栈等因素,生产环境推荐使用 Apollo 或 Nacos 等专业配置中心。