spring@Value注解的多维度使用

参考:https://zhuanlan.zhihu.com/p/420351920
value

1 @Value的中文注入(properties中文乱码 yml不会)

#张三 转义
susan.test.userName=\u5f20\u4e09
@Value("${susan.test.userName}")
private String userName;

@Value注解中定义的系统属性名需要与配置文件中属性名一致,如果不一样,启动项目时会直接报错。

假如在配置文件中配置中文的张三:

susan.test.userName=张三

最后获取数据时,你会发现userName竟然出现了乱码:

å¼ ä¸‰
为什么会出现乱码?

答:在springboot的CharacterReader类中,默认的编码格式是ISO-8859-1,该类负责.properties文件中系统属性的读取。如果系统属性包含中文字符,就会出现乱码。
在这里插入图片描述
那么,如何解决乱码问题呢?

目前主要有如下三种方案:

  • 1.手动将ISO-8859-1格式的属性值,转换成UTF-8格式。
  • 2.设置encoding参数,不过这个只对@PropertySource注解有用。
  • 3.将中文字符用unicode编码转义。

假如使用方案1,具体实现代码如下:

@Service
public class UserService {

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

    public String test() {
        String userName1 = new String(userName.getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8);
        System.out.println();
        return userName1;
    }
}

确实可以解决乱码问题。但如果项目中包含大量中文系统属性值,每次都需要加这样一段特殊转换代码。出现大量重复代码,有没有觉得有点恶心?反转我被恶心到了。那么,如何解决代码重复问题呢?答:将属性值的中文内容转换成unicode。类似于这样的:susan.test.userName=\u5f20\u4e09
这种方式同样能解决乱码问题,不会出现恶心的重复代码。但需要做一点额外的转换工作,不过这个转换非常容易,因为有现成的在线转换工具。
推荐使用这个工具转换:http://www.jsons.cn/unicode/

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

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

2 关于@Value注入的默认值问题

如果@Value没有取到值,那么启动的时候就会报错,如何避免这个问题

错误做法:

@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注解时,最好给参数设置一个默认值,以防止出现类似的问题。

3 @ConfigurationProperties注解

在@ConfigurationProperties配置类中,定义的参数名可以跟配置文件中的系统属性名不同。
比如,在配置类MyConfig类中定义的参数名是userName:

@Configuration
@ConfigurationProperties(prefix = "susan.test")
@Data
public class MyConfig {
    private String userName;
}

而配置文件中配置的系统属性名是:susan.test.user-name=\u5f20\u4e09
类中用的userName,而配置文件中用的user-name,不一样。
但测试之后,发现该功能能够正常运行。

配置文件中的系统属性名用 驼峰标识 或 小写字母加中划线的组合,spring都能找到配置类中的属性名userName进行赋值。

由此可见,配置文件中的系统属性名,可以跟配置类中的属性名不一样。不过,有个前提,前缀susan.test必须相同。

4 如何注入静态变量

假如将上面的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用在方法上的场景其实不多。

5 注入不同的变量类型

众所周知,在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;

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

L-960

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值