@Value竟然能玩出这么多花样 (2)

因为.yml或.yaml格式的配置文件,最终会使用UnicodeReader类进行解析,它的init方法中,首先读取BOM文件头信息,如果头信息中有UTF8、UTF16BE、UTF16LE,就采用对应的编码,如果没有,则采用默认UTF8编码。

@Value竟然能玩出这么多花样

需要注意的是:乱码问题一般出现在本地环境,因为本地直接读取的.properties配置文件。在dev、test、生产等环境,如果从zookeeper、apollo、nacos等配置中心中获取系统参数值,走的是另外的逻辑,并不会出现乱码问题。

4.默认值

有时候,默认值是我们非常头疼的问题。

为什么这样说呢?

因为很多时候使用java的默认值,并不能满足我们的日常工作需求。

比如有这样一个需求:如果配置了系统属性,userName就用配置的属性值。如果没有配置,则userName用默认值susan。

有些朋友可能认为可以这样做:

@Value(value = "${susan.test.userName}") private String userName = "susan";

在定义参数时直接给个默认值,但如果仔细想想这招是行不通的的。因为设置userName默认值的时机,比@Value注解依赖注入属性值要早,也就是说userName初始化好了默认值,后面还是会被覆盖。

那么,到底该如何设置默认值呢?

答:使用:。

例如:

@Value(value = "${susan.test.userName:susan}") private String userName;

在需要设置默认值的系统属性名后,加:符号。紧接着,在:右边设置默认值。

建议大家平时在使用@Value时,尽量都设置一个默认值。如果不需要默认值,宁可设置一个空。比如:

@Value(value = "${susan.test.userName:}") private String userName;

为什么这么说?

假如有这种场景:在business层中包含了UserService类,business层被api服务和job服务都引用了。但UserService类中@Value的userName只在api服务中有用,在job服务中根本用不到该属性。

对于job服务来说,如果不在.properties文件中配置同名的系统属性,则服务启动时就会报错。

这个坑,我之前踩过多次。所以,建议大家,使用@Value注解时,最好给参数设置一个默认值,以防止出现类似的问题。

5. static变量

前面我们已经见识过,如何使用@Value注解,给类的成员变量注入系统属性值。

那么,问题来了,静态变量可以自动注入系统属性值不?

我们一起看看,假如将上面的userName定义成static的:

@Value("${susan.test.userName}") private static String userName;

程序可以正常启动,但是获取到userName的值却是null。

由此可见,被static修饰的变量通过@Value会注入失败。

作为好奇宝宝的你,此时肯定想问:如何才能给静态变量注入系统属性值呢?

答:这就需要使用如下的骚代码了:

@Service public class UserService { private static String userName; @Value("${susan.test.userName}") public void setUserName(String userName) { UserService.userName = userName; } public String test() { return userName; } }

提供一个静态参数的setter方法,在该方法上使用@Value注入属性值,并且同时在该方法中给静态变量赋值。

有些细心的朋友可能会发现,@Value注解在这里竟然使用在setUserName方法上了,也就是对应的setter方法,而不是在变量上。

有趣,有趣,这种用法有点高端喔。

不过,通常情况下,我们一般会在pojo实体类上,使用lombok的@Data、@Setter、@Getter等注解,在编译时动态增加setter或getter方法,所以@Value用在方法上的场景其实不多。

6.变量类型

上面的内容,都是用的字符串类型的变量进行举例的。其实,@Value注解还支持其他多种类型的系统属性值的注入。

6.1 基本类型

众所周知,在Java中的基本数据类型有4类8种,然我们一起回顾一下:

整型:byte、short、int、long

浮点型:float、double

布尔型:boolean

字符型:char

相对应地提供了8种包装类:

整型:Byte、Short、Integer、Long

浮点型:Float、Double

布尔型:Boolean

字符型:Character

@Value注解对这8中基本类型和相应的包装类,有非常良好的支持,例如:

@Value("${susan.test.a:1}") private byte a; @Value("${susan.test.b:100}") private short b; @Value("${susan.test.c:3000}") private int c; @Value("${susan.test.d:4000000}") private long d; @Value("${susan.test.e:5.2}") private float e; @Value("${susan.test.f:6.1}") private double f; @Value("${susan.test.g:false}") private boolean g; @Value("${susan.test.h:h}") private char h; @Value("${susan.test.a:1}") private byte a1; @Value("${susan.test.b:100}") private Short b1; @Value("${susan.test.c:3000}") private Integer c1; @Value("${susan.test.d:4000000}") private Long d1; @Value("${susan.test.e:5.2}") private Float e1; @Value("${susan.test.f:6.1}") private Double f1; @Value("${susan.test.g:false}") private Boolean g1; @Value("${susan.test.h:h}") private Character h1;

有了这些常用的数据类型,我们在定义变量类型时,可以非常愉快的玩耍了,不用做额外的转换。

6.2 数组

但只用上面的基本类型是不够的,特别是很多需要批量处理数据的场景中。这时候可以使用数组,它在日常开发中使用的频率很高。

我们在定义数组时可以这样写:

@Value("${susan.test.array:1,2,3,4,5}") private int[] array;

spring默认使用逗号分隔参数值。

如果用空格分隔,例如:

@Value("${susan.test.array:1 2 3 4 5}") private int[] array;

spring会自动把空格去掉,导致数据中只有一个值:12345,注意千万别搞错了。

顺便说一下,定义数组的时候,里面还是有挺多门道的。比如上面列子中,我的数据是:1,2,3,4,5。

如果我们把数组定义成:short、int、long、char、string类型,spring是可以正常注入属性值的。

但如果把数组定义成:float、double类型,启动项目时就会直接报错。

@Value竟然能玩出这么多花样


小伙伴们,下巴惊掉了没?

按理说,1,2,3,4,5用float、double是能够表示的呀,为什么会报错?

如果使用int的包装类,比如:

@Value("${susan.test.array:1,2,3,4,5}") private Integer[] array;

启动项目时同样会报上面的异常。

此外,定义数组时一定要注意属性值的类型,必须完全一致才可以,如果出现下面这种情况:

@Value("${susan.test.array:1.0,abc,3,4,5}") private int[] array;

属性值中包含了1.0和abc,显然都无法将该字符串转换成int。

6.3 集合类

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zwgxwy.html