【问题标题】:Reading a List from properties file and load with spring annotation @Value从属性文件中读取列表并使用弹簧注释@Value 加载
【发布时间】:2012-09-16 13:40:03
【问题描述】:

我想在 .properties 文件中有一个值列表,即:

my.list.of.strings=ABC,CDE,EFG

并将其直接加载到我的班级中,即:

@Value("${my.list.of.strings}")
private List<String> myList;

据我了解,这样做的另一种方法是将它放在 spring 配置文件中,并将其作为 bean 引用加载(如果我错了,请纠正我),即

<bean name="list">
 <list>
  <value>ABC</value>
  <value>CDE</value>
  <value>EFG</value>
 </list>
</bean>

但是有没有办法做到这一点?使用 .properties 文件? ps:如果可能的话,我想在没有任何自定义代码的情况下这样做。

【问题讨论】:

  • 如何使用@value 读取 List 范围

标签: java spring spring-properties


【解决方案1】:

答案

@Value("#{'${my.list.of.strings}'.split(',')}") 
private List<String> myList; 

对逗号分隔值按预期工作。 为处理 null(当未指定属性时)将默认值(': '在属性名称后)添加为空字符串,如下所示:

@Value("#{'${my.list.of.strings: }'.split(',')}")

【讨论】:

    【解决方案2】:

    我使用的是 Spring Boot 2.2.6

    我的属性文件:

    usa.big.banks= JP Morgan, Wells Fargo, Citigroup, Morgan Stanley, Goldman Sachs
    

    我的代码:

    @Value("${usa.big.banks}")
        private List<String> bigBanks;
    
    @RequestMapping("/bigbanks")
        public String getBanks() {
            System.out.println("bigBanks = " + bigBanks);
            return bigBanks.toString();
        }
    

    效果很好

    【讨论】:

      【解决方案3】:

      我的首选方式(尤其是字符串)是以下一种:

      admin.user={'Doe, John','Headroom, Max','Mouse, Micky'}
      

      并使用

      @Value("#{${admin.user}}")
      private List<String> userList;
      

      这样,您还可以在参数中包含逗号。它也适用于 Set。

      【讨论】:

      • 为 Spring 进行此转换的底层代码是什么/在哪里?
      【解决方案4】:

      在我的整数列表的例子中是这样的:

      @Value("#{${my.list.of.integers}}")
      private List<Integer> listOfIntegers;
      

      属性文件:

      my.list.of.integers={100,200,300,400,999}
      

      【讨论】:

      • 或 @Value("#{${my.set.of.integers}}") 私有 Set setOfIntegers;
      【解决方案5】:

      如果您使用的是 Spring Boot 2,它可以按原样工作,无需任何额外配置。

      my.list.of.strings=ABC,CDE,EFG
      
      @Value("${my.list.of.strings}")
      private List<String> myList;
      

      【讨论】:

      • 对我不起作用,我必须使用如上所示的 Spring EL。
      • 甚至private List&lt;String&gt; myList;
      • 是的,它也对我有用:我使用的是 Spring Boot 2.2.6
      【解决方案6】:

      如果您使用的是最新的 Spring 框架版本(我相信是 Spring 3.1+),则不需要在 SpringEL 中进行那些字符串拆分,

      只需在 Spring 的 Configuration 类中添加 PropertySourcesPlaceholderConfigurer 和 DefaultConversionService (带有 Configuration 注释的类),例如,

      @Configuration
      public class AppConfiguration {
      
          @Bean
          public static PropertySourcesPlaceholderConfigurer propertyPlaceholderConfigurer() {
              return new PropertySourcesPlaceholderConfigurer();
          }
      
          @Bean public ConversionService conversionService() {
              return new DefaultConversionService();
          }
      }
      

      在你的班级里

      @Value("${list}")
      private List<String> list;
      

      在属性文件中

      list=A,B,C,D,E
      

      如果没有 DefaultConversionService,当您将值注入字段时,您只能将逗号分隔的字符串转换为字符串数组,但 DefaultConversionService 为您做了一些方便的魔术,并将它们添加到 Collection、Array 等中。(检查实现是否你想了解更多)

      有了这两个,它甚至可以处理所有多余的空格,包括换行符,所以你不需要添加额外的逻辑来修剪它们。

      【讨论】:

      • 此配置的添加正在工作,但发生了一些奇怪的事情:我不能使用@Value 作为文件类型,我必须使用资源更改文件。
      【解决方案7】:

      我认为这对于抓取数组和剥离空格来说更简单:

      @Value("#{'${my.array}'.replace(' ', '').split(',')}")
      private List<String> array;
      

      【讨论】:

        【解决方案8】:

        使用 Spring EL:

        @Value("#{'${my.list.of.strings}'.split(',')}") 
        private List<String> myList;
        

        假设您的属性文件已正确加载以下内容:

        my.list.of.strings=ABC,CDE,EFG
        

        【讨论】:

        • 我使用您使用的相同版本再次检查了它。完全按照帖子中的方式复制 Spring EL,它可以工作。但不同的是,如果我在我的 EL 中出错,我会得到 org.springframework.expression.spel.SpelEvaluationException 异常而不是 javax.el.ELException。您的对象是 Spring 创建的吗?
        • 与 Spring 3.2 完美配合。
        • 空属性my.list.of.strings=怎么样?我希望这样的功能会在此处返回一个项目(空字符串)的空列表,不是吗?
        • 另请注意,建议的解决方案不会进行修剪,因此像 item1, item2, item3 这样的值可能会给您带来意想不到的结果(提示:空格)。
        • 如果您需要修剪空格,请使用正则表达式作为拆分参数.. 类似于 @Value("#{'${my.list.of.strings}'.split(',\\s*')}")
        【解决方案9】:

        如果您正在阅读本文并且您正在使用 Spring Boot,那么您还有 1 个选项可以使用此功能

        通常逗号分隔的列表对于现实世界的用例来说非常笨拙 (如果您想在配置中使用逗号,有时甚至不可行):

        email.sendTo=somebody@example.com,somebody2@example.com,somebody3@example.com,.....
        

        使用 Spring Boot,您可以这样编写(索引从 0 开始):

        email.sendTo[0]=somebody@example.com
        email.sendTo[1]=somebody2@example.com
        email.sendTo[2]=somebody3@example.com
        

        并像这样使用它:

        @Component
        @ConfigurationProperties("email")
        public class EmailProperties {
        
            private List<String> sendTo;
        
            public List<String> getSendTo() {
                return sendTo;
            }
        
            public void setSendTo(List<String> sendTo) {
                this.sendTo = sendTo;
            }
        
        }
        
        
        @Component
        public class EmailModel {
        
          @Autowired
          private EmailProperties emailProperties;
        
          //Use the sendTo List by 
          //emailProperties.getSendTo()
        
        }
        
        
        
        @Configuration
        public class YourConfiguration {
            @Bean
          public EmailProperties emailProperties(){
                return new EmailProperties();
          }
        
        }
        
        
        #Put this in src/main/resource/META-INF/spring.factories
          org.springframework.boot.autoconfigure.EnableAutoConfiguration=example.compackage.YourConfiguration
        

        【讨论】:

        • 我有一个问题,这里描述的其他解决方案由于无法识别转义逗号而无法工作。有没有办法用 Spring 4 来解决这个问题?
        【解决方案10】:

        从 Spring 3.0 开始,可以添加如下一行

        <bean id="conversionService" 
            class="org.springframework.context.support.ConversionServiceFactoryBean" />
        

        到您的applicationContext.xml(或您配置的地方)。 正如 Dmitry Chornyi 在评论中指出的那样,基于 Java 的配置如下所示:

        @Bean public ConversionService conversionService() {
            return new DefaultConversionService();
        }
        

        这将激活支持将String 转换为Collection 类型的新配置服务。 如果您不激活此配置服务,Spring 将使用其遗留的属性编辑器作为配置服务,不支持这种转换。

        转换为其他类型的集合也可以:

        @Value("${my.list.of.ints}")
        private List<Integer> myList
        

        将使用类似的行

         my.list.of.ints= 1, 2, 3, 4
        

        那里的空白没有问题,ConversionServiceFactoryBean 会处理它。

        http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#core-convert-Spring-config

        在 Spring 应用程序中,您通常为每个 Spring 容器(或 ApplicationContext)配置一个 ConversionService 实例。该 ConversionService 将被 Spring 拾取,然后在框架需要执行类型转换时使用。 [...] 如果没有在 Spring 中注册 ConversionService,则使用原始的基于 PropertyEditor 的系统。

        【讨论】:

        • Java 配置:@Bean public ConversionService conversionService() { return new DefaultConversionService(); }
        • 除了避免在每个表达式中重复使用split(),它还可以正确处理空列表而不是给你[null]
        • 如果属性被覆盖(存在于多个属性源中),它将不起作用。
        【解决方案11】:

        考虑使用公共配置。它具有将属性文件中的条目分解为数组/列表的内置功能。结合 SpEL 和 @Value 应该可以满足您的需求


        根据要求,这里是你需要的(没有真正尝试过代码,可能有一些错别字,请多多包涵):

        在 Apache Commons Configuration 中,有 PropertiesConfiguration。它支持将分隔字符串转换为数组/列表的功能。

        例如,如果您有一个属性文件

        #Foo.properties
        foo=bar1, bar2, bar3
        

        使用以下代码:

        PropertiesConfiguration config = new PropertiesConfiguration("Foo.properties");
        String[] values = config.getStringArray("foo");
        

        会给你一个["bar1", "bar2", "bar3"]的字符串数组

        要与 Spring 一起使用,请在您的应用上下文 xml 中包含此内容:

        <bean id="fooConfig" class="org.apache.commons.configuration.PropertiesConfiguration">
            <constructor-arg type="java.lang.String" value="classpath:/Foo.properties"/>
        </bean>
        

        并在你的 spring bean 中有这个:

        public class SomeBean {
        
            @Value("fooConfig.getStringArray('foo')")
            private String[] fooArray;
        }
        

        我相信这应该可行:P

        【讨论】:

        • 您能否更具体地了解要使用的方法和类,实际的示例代码片段会很棒。
        【解决方案12】:

        如果使用属性占位符,则 ser1702544 示例将变为

        @Value("#{myConfigProperties['myproperty'].trim().replaceAll(\"\\s*(?=,)|(?<=,)\\s*\", \"\").split(',')}") 
        

        使用占位符 xml:

        <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">   
            <property name="properties" ref="myConfigProperties" />
            <property name="placeholderPrefix"><value>$myConfigProperties{</value></property>
        </bean>    
        
        <bean id="myConfigProperties" class="org.springframework.beans.factory.config.PropertiesFactoryBean">
             <property name="locations">
                 <list>
                        <value>classpath:myprops.properties</value>
                 </list>
             </property>
        </bean> 
        

        【讨论】:

          【解决方案13】:

          注意值中的空格。我可能是错的,但我认为逗号分隔列表中的空格不会使用@Value 和 Spel 截断。名单

          foobar=a, b, c
          

          将作为字符串列表读入

          "a", " b", " c"
          

          在大多数情况下,您可能不想要空格!

          表达式

          @Value("#{'${foobar}'.trim().replaceAll(\"\\s*(?=,)|(?<=,)\\s*\", \"\").split(',')}")
          private List<String> foobarList;
          

          会给你一个字符串列表:

          "a", "b", "c".
          

          正则表达式会删除逗号前后的所有空格。值内的空格不会被删除。所以

          foobar = AA, B B, CCC
          

          应该产生值

          "AA", "B B", "CCC".
          

          【讨论】:

          • split() 方法使用内部正则表达式作为分隔符,因此您的示例可以简化:
            @Value("#{'${foobar}'.trim().split( *, *)}")
          【解决方案14】:

          你可以用这样的注释来做到这一点

           @Value("#{T(java.util.Arrays).asList('${my.list.of.strings:a,b,c}')}") 
              private List<String> mylist;
          

          这里 my.list.of.strings 将从属性文件中选择,如果不存在,则使用默认值 a,b,c

          在你的属性文件中,你可以有这样的东西

          my.list.of.strings=d,e,f

          【讨论】:

            【解决方案15】:

            您是否考虑过 @Autowireding 构造函数或 setter 以及 String.split()ing 在正文中?

            class MyClass {
                private List<String> myList;
            
                @Autowired
                public MyClass(@Value("${my.list.of.strings}") final String strs) {
                    myList = Arrays.asList(strs.split(","));
                }
            
                //or
            
                @Autowired
                public void setMyList(@Value("${my.list.of.strings}") final String strs) {
                    myList = Arrays.asList(strs.split(","));
                }
            }
            

            我倾向于以其中一种方式进行自动装配,以增强代码的可测试性。

            【讨论】:

              【解决方案16】:

              以上所有答案都是正确的。但是你可以在一行中实现这一点。 请尝试以下声明,您将在字符串列表中获得所有逗号分隔的值。

              private @Value("#{T(java.util.Arrays).asList(projectProperties['my.list.of.strings'])}") List<String> myList;
              

              您还需要在 xml 配置中定义以下行。

              <util:properties id="projectProperties" location="/project.properties"/>
              

              只需替换属性文件的路径和文件名。你很高兴。 :)

              希望这对您有所帮助。干杯。

              【讨论】:

              • 这对我有用,但我不得不这样写注释:@Value("#{T(java.util.Arrays).asList('${my.list.of.strings}')}")
              【解决方案17】:

              通过在 .properties 文件中指定 my.list.of.strings=ABC,CDE,EFG 并使用

              @Value("${my.list.of.strings}") private String[] myString;

              您可以获得字符串数组。而使用CollectionUtils.addAll(myList, myString),可以得到字符串列表。

              【讨论】:

              • 我只得到第一个字符串“ABC”
              猜你喜欢
              • 2015-12-15
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2015-11-14
              • 1970-01-01
              • 2022-10-21
              相关资源
              最近更新 更多