Java配置热更新案例如何实现

wen java案例 22

本文目录导读:

Java配置热更新案例如何实现

  1. Spring Cloud Config + Spring Cloud Bus
  2. 基于数据库的配置热更新
  3. 基于文件的配置热更新
  4. Apollo配置中心(生产推荐)
  5. 最佳实践建议

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);
    }
}

最佳实践建议

配置热更新注意事项:

  1. 线程安全:使用 ConcurrentHashMapReentrantReadWriteLock
  2. 事务一致性:配置更新和业务操作的事务边界
  3. 配置版本控制:记录配置变更历史
  4. 灰度发布:逐步推送配置到部分实例
  5. 回滚机制:支持配置快速回滚
  6. 监控告警:配置变更通知和异常告警

推荐方案选择:

场景 推荐方案 说明
微服务架构 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 等专业配置中心。

抱歉,评论功能暂时关闭!