【问题标题】:Is it possible to create multiple beans depending on prefix in application.properties in springboot是否可以根据springboot中application.properties中的前缀创建多个bean
【发布时间】:2018-08-17 11:44:51
【问题描述】:

我的 springboot 应用程序 (1.5.4.RELEASE) 中的 application.properties 中有以下内容

my.prefix.one.id=id01
my.prefix.one.name=one

my.prefix.two.id=id02
my.prefix.two.name=two

还有一个像下面这样的类

public class MyClass{
 private String id;
 private String name;
 //getters and setters
}

如果我使用 @ConfigurationProperties(prefix="my.prefix.one") 那么我会得到一个带有 id 字段“id01”的 MyClass bean。

有没有办法指示springboot扫描扫描所有带有前缀“my.prefix”的属性并创建多个bean。在这种情况下,两个 bean - id 字段为“id01”的 bean 和 id 字段为“id02”的 bean?

【问题讨论】:

    标签: java spring spring-boot


    【解决方案1】:

    您应该使用弹簧@ConfigurationProperties 并在您的MyClass 中使用嵌套类

    @ConfigurationProperties(prefix="my.prefix")
    public class MyClass{
    
      private One id01;
      private Two id02;
      //GETTER SETTER
    
      public static class One {
        private String id;
        // GETTER SETTER
      }
    
      public static class Two {
        private String id;
        // GETTER SETTER
      }
    }
    

    然后你就可以像访问它了

    myClass.getOne().getId();
    

    最好的办法是通读https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html#boot-features-external-config-typesafe-configuration-properties


    更新:OP 不想使用嵌套类来检索这些字段

        @ConfigurationProperties(prefix="my.prefix")
        public class MyClass{
          private String id01;
          private String id02;
    
          @NotNull
          private One one;
          @NotNull
          private Two two;
    
          public getId01(){
            return one.id;
          }
          public getId02(){
            return two.id;
          }
    
          public static class One {
            private String id;
            // GETTER SETTER
          }
    
          public static class Two {
            private String id;
            // GETTER SETTER
          }
        }
    

    现在你可以像这样使用它们了

       myClass.getId01();
       myClass.getId02();
    

    【讨论】:

    • 但我不想创建两个类定义 MyClass.One 和 MyClass.Two。它们都具有相同的结构
    • 具有相同的结构应该不是问题。我已经修改了 myClass 吸气剂以符合您的要求。希望你想这样使用它。你是吗?
    • 他不关心它们是否具有相同的结构,他不想为每个实例创建一个类。
    • @pavankumar 我仍在等待 OP 通过回答我的问题来确认。
    • @Amit,您对我刚刚提出的答案有何看法?即,使用多个配置方法而不是多个嵌套类。
    【解决方案2】:

    我已经尝试过类似的操作,据我所知,创建多个实例的唯一方法是获取具有指定前缀的 all 属性并自己解析它们。对于您的示例,您可以像这样构造一个@Configuration:

    @Configuration
    public class MyConfig {
    
        @Bean
        @ConfigurationProperties(prefix = "my.prefix")
        protected Map<String, String> myProperties() {
            return new HashMap<>();
        }
    
        @Bean
        public List<MyClass> myObjects(@Qualifier("myProperties") final Map<String, String> myProperties) {
    
            final Map<String, Map<String, String>> mappedSources = new HashMap<>();
            myProperties.forEach((key1, value) -> {
                final String[] key = key1.split("\\.");
                final Map<String, String> myInstanceParams = mappedSources.computeIfAbsent(key[0], s -> new HashMap<>(2));
                myInstanceParams.put(key[1], value);
            });
            return mappedSources.values().stream()
                    .map(stringStringMap -> new MyClass(stringStringMap.get("id"), stringStringMap.get("name")))
                    .collect(Collectors.toList());
        }
    }
    

    在这个简单的例子中,@Qualifier 不需要在 myObjects() 参数列表中,但是如果你在想要做类似的地方引入第二个前缀,那么你需要限定将哪个字符串映射传递到 @987654325 @ 方法,所以我建议从一开始就包含它。

    这是一个简单的例子,但更健壮的实现会检查缺失的属性和属性有效性等。我也不能说这个解决方案是否是好的实践/好的 Spring 实践。

    【讨论】:

      【解决方案3】:

      由于你使用的是springboot,你也可以这样做:

      @Configuration
      public class AppBeanConfig {
          @Bean
          @ConfigurationProperties(prefix="my.prefix.one")  
          public MyClass myClassOne(){
            return new MyClass();
         }
      
          @Bean
          @ConfigurationProperties(prefix="my.prefix.two")  
          public MyClass myClassTwo(){
            return new MyClass();
         }
      }
      

      我不知道有什么有意义的方法可以避免配置单个 bean。

      但是,如果您真的想要这样做,您可以访问 ApplicationContext 并手动处理属性并将 bean 注入 Applicationcontext,我个人更喜欢将多个 bean 方法添加到配置类而不是直接操作 ApplicationContext。

      【讨论】:

      • 上述解决方案有什么问题?你能给我推荐一个更简单的解决方案吗?我认为在父级中拥有内部战略类和两个实例并不比拥有两个 break 方法更好。
      【解决方案4】:

      如果一、二的属性相同,只需使用同一个类即可。 Lombok 可帮助您自动创建 getter/setter 方法,这是使其正常工作所必需的

      @Getter
      @Setter
      @Configuration
      @ConfigurationProperties(prefix="my.prefix")
      public class MyClass {
      
        private Child one;
        private Child two;
      
        @Getter
        @Setter
        public static class Child {
      
          @NotNull
          private String id;
          @NotNull
          private String name;
        }
      }
      

      【讨论】:

      • 您可以创建两个带有正确注释的海滩方法的bean,而不是创建嵌套的静态类。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-04-09
      • 1970-01-01
      • 1970-01-01
      • 2017-12-31
      • 1970-01-01
      相关资源
      最近更新 更多