【问题标题】:What is the best way to store and change global app properties in Spring Boot in a thread safe way以线程安全的方式在 Spring Boot 中存储和更改全局应用程序属性的最佳方法是什么
【发布时间】:2021-01-08 20:52:31
【问题描述】:

我正在使用 Spring Boot,并在我的应用程序启动时在 @Configuration bean 中加载/生成应用程序属性,并将它们放置在 HashMap 中,例如:

@Configuration
public class Config {

  @Bean(name = "appConfig")
  public Map<String, String> getApplicationConfig() {

    Map<String, String> appConfig = new HashMap<>();

    //load or generate global config varibles
    appConfig.put("GLOBAL_CONFIG", "VALUE 1");
    return appConfig;
}

我在几个 bean 中注入了这个属性映射,例如:

@RestController
@RequestMapping("/getglobalconfig")
public class ConfigController {

  @Value("#{appConfig}")
  private Map<String, String> appConfig;

  @GetMapping
  public String getGlobalConfig() { return appConfig.get("GLOBAL_CONFIG"); }
}

在某些事件之后,我想以线程安全的方式更改例如我的 appConfig HashMap GLOBAL_CONFIG 值的值,以便在所有注入的 bean 中更新它,例如在上面的 ConfigController 示例中。

以线程安全的方式完成此任务并让我的 bean 重新加载值而不重新初始化它们或重新启动应用程序的最佳模式是什么? Spring cloud config 看起来很有趣,但不幸的是我无法使用它。

我不限于 HashMap 属性,我只需要线程安全地重新加载全局属性,以便在重新加载后在注入的 bean 中可见。

【问题讨论】:

    标签: java spring multithreading spring-boot concurrency


    【解决方案1】:

    Spring 默认创建单例,因此所有 bean 都将具有对属性映射的相同引用。但是,并发访问简单地图可能会产生错误。

    因此所需的更改最少

     Map<String, String> appConfig = new java.util.concurrent.ConcurrentHashMap<>();
    
     //load or generate global config varibles
     appConfig.put("GLOBAL_CONFIG", "VALUE 1");
     return appConfig;
    

     Map<String, String> appConfig = new HashMap<>();
    
     //load or generate global config varibles
     appConfig.put("GLOBAL_CONFIG", "VALUE 1");
      return java.util.Collections.synchronizedMap(appConfig);
    

    但是,您使用的方法意味着其他 bean 也可以更改属性。我会在 map 周围创建新的 wrapper bean,它只提供一种方法

    public class ReadOnlyConfig {
      private  final Map map;
      public ReadOnlyConfig (Map map) { this.map = map; }
      String getProperty(String name) { return map.get(name); }
    }
    

    @Configuration
    public class Config {
    
      @Bean(name = "appConfig")
      public Map<String, String> getApplicationConfig() {
    
        Map<String, String> appConfig = new java.util.concurrent.ConcurrentHashMap<>();
    
        //load or generate global config varibles
        appConfig.put("GLOBAL_CONFIG", "VALUE 1");
        return appConfig;
    }
    
      @Bean(name = "readOnlyConfig")
      public ReadOnlyConfig getReadOnlyApplicationConfig(  @Qualifier(name = "appConfig") Map<String, String> map) {
    
        return new ReadOnlyConfig(map);
    }
    
    

    【讨论】:

    • 将 GLOBAL_CONFIG 的值从 VALUE 1 更改为 VALUE 2 的最佳方法是什么。我不希望属性映射为只读,这是我的主要用例。跨度>
    • 如果需要,您仍然可以访问"appConfig",它是可读写的
    猜你喜欢
    • 2012-03-07
    • 2010-12-05
    • 1970-01-01
    • 2010-12-31
    • 2014-03-07
    • 1970-01-01
    • 2021-09-25
    • 2016-04-17
    • 2011-12-19
    相关资源
    最近更新 更多