当前位置: 首页 > 科技观察

SpringBoot的@Value注解太强大了,用起来爽!

时间:2023-03-13 04:05:01 科技观察

1.前言在日常开发中,经常需要在配置文件中存放List或Map数据。Spring原生支持这种数据类型。以List类型的配置为例。.yml文件的配置如下:test:list:-aaa-bbb-ccc.properties文件的配置如下:test.list[0]=aaatest.list[1]=bbbtest.list[2]=ccc当我们要在程序中使用它的时候,很自然的要使用@Value注解来读取这个值,就像下面这样:@Value("${test.list}")privateListtestList;你会发现程序直接报错,报错信息如下:java.lang.IllegalArgumentException:Couldnotresolveplaceholder'test.list'invalue"${test.list}"这个问题也是可以解决的,以我们要配置的key为test.list为例,创建一个test的配置类,将list作为配置类的一个属性:@Configuration@ConfigurationProperties("test")publicclassTestListConfig{privateListlist;publicListgetList(){returnlist;}publicvoidsetList(Listlist){this.list=list;}}在程序的其他地方使用。使用自动注入获取值:@AutowiredprivateTestListConfigtestListConfig;//testListConfig.getList();如您所见,这种方法非常不方便。最大的问题是配置和代码耦合度高。添加配置还需要更改配置类。其次,数组呢?说实话,要写的业务代码太多了,这种“老”的数据结构用起来远不如list,但是在解决上面的问题上却出奇的好用。测试:array1:aaa,bbb,cccarray2:111,222,333array3:11.1,22.2,33.3@Value("${test.array1}")privateString[]testArray1;@Value("${test.array2}")privateint[]testArray2;@Value("${test.array3}")privatedouble[]testArray3;这个可以直接使用,就是这么简单方便,如果你想支持程序的正常运行而不需要配置key,添加他们设置默认值即可:@Value("${test.array1:}")privateString[]testArray1;@Value("${test.array2:}")privateint[]testArray2;@Value("${test.array3:}")privatedouble[]testArray3;只多了一个:符号,冒号后面的值表示key不存在时使用的默认值,使用默认值时数组长度=0。总结一下使用数组的优缺点:优点:不用写配置类,用逗号分隔。一行配置即可完成多个值的注入,配置文件更加精简。缺点:业务代码中很少用到数组,基本需要将其转换成List来做contains、foreach等操作。3.替代方法那么,有没有什么方法可以让我们在解析list、map等类型的时候像数组一样方便呢?答案是肯定的,这要看EL表达式。3.1解析List以.yml文件为例,我们只需要像配置文件中的配置数组一样配置:test:list:aaa,bbb,ccc调用时,使用split()函数对EL表达式进行切分即可。@Value("#{'${test.list}'.split(',')}")privateListtestList;同理,为其添加一个默认值,避免未配置该键时程序出错:@Value("#{'${test.list:}'.split(',')}")privateListtestList;但是有一个问题,当不配置key值时,默认值为空字符串,它的length=1(不同于数组,length=0),所以解析出来的list的元素个数不为空。这个问题比较严重,因为它会导致代码中的空判断逻辑执行错误。这个问题也可以解决,只要在split()之前判断是否为空即可。@Value("#{'${test.list:}'.empty?null:'${test.list:}'.split(',')}")privateListtestList;如上,即作为最终版本,它具有数组方法的所有优点,更容易在业务代码中应用。3.2ParsingSet解析Set和解析List本质上是一样的,唯一不同的是Set会做去重。test:set:111,222,333,111`@Value("#{'${test.set:}'.empty?null:'${test.set:}'.split(',')}")privateSettestSet;//output:[111,222,333]3.3解析Map解析Map的写法如下,value是map的json格式,注意这里用的引号:整个json字符串用引号包裹起来,并且value值用引号括起来。test:map1:'{"name":"zhangsan","sex":"male"}'map2:'{"math":"90","english":"85"}'程序中,使用EL表达式注入:@Value("#{${test.map1}}")privateMapma??p1;@Value("#{${test.map2}}")privateMapmap2;注意,使用这种方法,必须在配置文件中配置键及其值。在网上找了很多资料,都没有找到使用EL表达式支持不配置key/value的方法。如果你真的需要这个功能,你必须自己编写解析方法。下面是一个使用fastjson进行解析的例子:(1)自定义解析方法publicclassMapDecoder{publicstaticMapdecodeMap(Stringvalue){try{returnJSONObject.parseObject(value,newTypeReference>(){});}catch(Exceptione){returnnull;}}}(2)在程序中指定解析方式@Value("#{T(com.github.jitwxs.demo.MapDecoder).decodeMap('${test.map1:}')}")privateMapma??p1;@Value("#{T(com.github.jitwxs.demo.MapDecoder).decodeMap('${test.map2:}')}")privateMapma??p2;四、后续以上是本文的全部内容。使用EL表达式甚至是我们自己的分析方法,都可以让我们使用Collection类型更方便的配置和配置文件。特别注意@Value注解不能和@AllArgsConstructor注解同时使用,否则会报错考虑在你的配置中定义类型为'java.lang.String'的abean。不漂亮,也不容易阅读。