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

如何重新初始化标注@Document的Spring Bean并自动同步集合更新

实现MongoDB配置变更时自动更新Spring注入的ConfigData Bean

我有一个标注了@Document的Spring Bean(ConfigData类),已经通过@Bean配置使其可以通过@Autowired注入。现在希望当MongoDB集合中的数据发生变化时,@Autowired注入的ConfigData实例能自动获取这些变更,请问该如何实现?

ConfigData类代码

@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
@ToString
@Document(collection = CollectionNames.CONFIG_DATA)
public class ConfigData {
    @Id
    private String id;
    private Profiles profiles;
    private EmailConfig emailConfig;
    private ScheduledConfig scheduledConfig;

    @Getter
    @Setter
    @AllArgsConstructor
    @NoArgsConstructor
    @ToString
    public static class EmailConfig {
        private String email;
        private String password;
    }

    @Getter
    @Setter
    @AllArgsConstructor
    @NoArgsConstructor
    @ToString
    public static class ScheduledConfig {
        private Long time;
        private TimeUnit timeUnit;

        public long convertToMilliseconds(long value, TimeUnit unit) {
            return switch (unit) {
                case HOURS -> java.util.concurrent.TimeUnit.HOURS.toMillis(value);
                case MINUTES -> java.util.concurrent.TimeUnit.MINUTES.toMillis(value);
                case SECONDS -> java.util.concurrent.TimeUnit.SECONDS.toMillis(value);
            };
        }

        public enum TimeUnit {
            HOURS, MINUTES, SECONDS
        }
    }
}

配置类代码

@Configuration
public class MongoConfig {
    @Autowired
    private ConfigDataService configDataService;
    @Autowired
    private Environment environment;

    @Bean
    public ConfigData configData() {
        return configDataService.getConfigDataByProfile(Profiles.valueOf(environment.getActiveProfiles()[0].toUpperCase(Locale.ROOT)));
    }
}

尝试过的无效方法

  1. 使用DefaultSingletonBeanRegistry的destroySingleton和registerSingleton方法销毁并重新注册Bean,执行报错;
  2. 添加定时任务尝试更新ConfigData,未生效,定时任务代码如下:
@Service
public class TestOne {
    @Autowired
    private MongoConfig mongoConfig;
    @Autowired
    private ConfigData configData;

    @Scheduled(fixedRate = 1000)
    public void test() {
        ConfigData configData1 = mongoConfig.configData();
        configData.setScheduledConfig(configData1.getScheduledConfig());
    }
}

可行解决方案

方法一:利用MongoDB Change Stream实时监听变更

Spring Data MongoDB支持监听MongoDB的Change Stream,当目标集合数据发生增删改时会触发事件,可通过该特性实时更新Bean内容。

  1. 确保Spring Data MongoDB版本在2.2+(Spring Boot 2.2+默认满足);
  2. 创建监听类,通过@DocumentListener处理变更事件:
@Component
public class ConfigDataChangeListener {
    private final ConfigData configData;
    private final ConfigDataService configDataService;
    private final Environment environment;

    public ConfigDataChangeListener(ConfigData configData, ConfigDataService configDataService, Environment environment) {
        this.configData = configData;
        this.configDataService = configDataService;
        this.environment = environment;
    }

    @DocumentListener
    public void handleConfigUpdate(AfterSaveEvent<ConfigData> event) {
        ConfigData updatedDoc = event.getSource();
        Profiles activeProfile = Profiles.valueOf(environment.getActiveProfiles()[0].toUpperCase(Locale.ROOT));
        
        // 仅更新当前激活环境对应的配置
        if (activeProfile.equals(updatedDoc.getProfiles())) {
            configData.setEmailConfig(updatedDoc.getEmailConfig());
            configData.setScheduledConfig(updatedDoc.getScheduledConfig());
            // 其他字段按需同步
        }
    }
}

该方式无需轮询,仅在数据变更时触发更新,实时性强。

方法二:优化定时任务方案

之前的定时任务未生效,大概率是缺少@EnableScheduling注解,或逻辑存在疏漏,优化后的代码如下:

  1. 在启动类添加@EnableScheduling启用定时任务;
  2. 修改定时任务类:
@Service
public class ConfigDataRefreshTask {
    private final ConfigData configData;
    private final ConfigDataService configDataService;
    private final Environment environment;

    public ConfigDataRefreshTask(ConfigData configData, ConfigDataService configDataService, Environment environment) {
        this.configData = configData;
        this.configDataService = configDataService;
        this.environment = environment;
    }

    @Scheduled(fixedRate = 5000) // 根据需求调整轮询间隔
    public void refreshConfig() {
        Profiles activeProfile = Profiles.valueOf(environment.getActiveProfiles()[0].toUpperCase(Locale.ROOT));
        ConfigData latestData = configDataService.getConfigDataByProfile(activeProfile);
        
        // 同步最新配置到已注入的Bean实例
        configData.setEmailConfig(latestData.getEmailConfig());
        configData.setScheduledConfig(latestData.getScheduledConfig());
    }
}

方法三:分布式场景用Spring Cloud Config(可选)

如果是多服务分布式架构,可搭建Spring Cloud Config配置中心,配合Spring Cloud Bus实现配置的集中管理和全局自动刷新,适合多服务共享配置的场景。


关键注意事项

  • 禁止手动销毁/重新注册Singleton Bean:Spring容器会管理Singleton Bean的生命周期,手动操作会破坏容器依赖关系,导致异常;
  • 直接修改现有Bean属性:Singleton Bean是全局共享实例,修改其属性后,所有注入该Bean的地方都会获取到最新值;
  • 保证线程安全:若存在多线程读写配置的场景,需给ConfigData的set方法添加synchronized,或使用线程安全的存储结构。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 14:28:21