Spring提供了@Value注解帮助我们注入一个自定义属性或者对象,大大简化了我们的操作。但是如果对其原理不清楚,有时也会遇到一些不可预期的bug。
本文主要介绍了@Value注解使用的常见场景及使用方法,以及分享一个比较经典的易错场景。
如何使用
常见的使用方式有以下四种,请注意使用方式的不同。
//直接注入一个字符串
@Value("我是字符串")
private String str;
//注入系统参数、环境变量或者配置文件中的值
//注意此处用的是 ${}
@Value("${application.name}")
private String applicationName;
//注入一个Bean的属性,其中person为bean的ID,name为其属性
//注意此处用的是 #{}
@Value("${person.name}")
private String name;
//注入一个bean,person是我们定义的一个bean
//注意注入bean时使用是 #{}
@Value("#{person}")
private Person person;
实践
1,注入一个字符串
@SpringBootApplication(scanBasePackages = "com.shishan.demo2023.*")
public class Demo2023Application {
public static void main(String[] args) {
SpringApplication.run(Demo2023Application.class, args);
}
@Value("我是常量字符串")
private String str;
@PostConstruct
public void init() {
//打印常量字符串
System.out.println("str====" + str);
}
}
启动我们的项目,可以看到控制台打印出我们注入的str的值:
2,注入一个自定义属性
在application.properties配置文件中配置以下属性:
spring.application.name=demo2023
server.port=8080
username=shishan
userpassword=123456
@SpringBootApplication(scanBasePackages = "com.shishan.demo2023.*")
public class Demo2023Application {
public static void main(String[] args) {
SpringApplication.run(Demo2023Application.class, args);
}
@Value("${username}")
private String username;
@PostConstruct
public void init() {
//打印自定义属性
System.out.println("username====" + username);
}
}
启动项目,控制台打印出来我们自定义的属性值:
3,注入一个bean
先定义一个bean,并通过@Bean注入Spring容器
@Data
public class Person {
private String name;
private Integer age;
}
@Component
public class PersonConfig {
@Bean
public Person person(){
Person person = new Person();
person.setName("男人or女人");
person.setAge(18);
return person;
}
}
通过@Value注入person对象:
@SpringBootApplication(scanBasePackages = "com.shishan.demo2023.*")
public class Demo2023Application {
public static void main(String[] args) {
SpringApplication.run(Demo2023Application.class, args);
}
@Value("#{person}")
private Person person;
@PostConstruct
public void init() {
//打印自定义属性
System.out.println("person====" + person);
}
}
启动项目,可以看到控制台打印出了person对象的属性:
4,注入一个对象的属性
还以上面的person对象为例,使用@Value注入person.name。
public class Demo2023Application {
public static void main(String[] args) {
SpringApplication.run(Demo2023Application.class, args);
}
@Value("#{person.name}")
private String personName;
@PostConstruct
public void init() {
//打印personName
System.out.println("personName====" + personName);
}
}
启动项目,可以看到控制打印出了personName:
[图片上传失败...(image-4c9b88-1670064150218)]
总结:使用@Value可以直接注入一个常量字符串,如果要注入一个自定义属性,请使用$符,如果要注入一个对象或者对象的属性,要使用#号。
重点:注入自定义属性用${},注入对象用#{}。
@Value容易出错的一个经典场景
当我们使用@Value注入一个自定义的属性值时,有一个容易出错的经典场景就是:我们自定义的属性与系统环境变量属性冲突了,系统环境变量会覆盖掉我们的自定义属性值,并且不会报错。
场景复现:
在application.properties配置文件中配置如下属性:
spring.application.name=demo2023
server.port=8080
//定义user.name为shishan
user.name=shishan
尝试注入user.name:
@SpringBootApplication(scanBasePackages = "com.shishan.demo2023.*")
public class Demo2023Application {
public static void main(String[] args) {
SpringApplication.run(Demo2023Application.class, args);
}
@Value("${user.name}")
private String username;
@PostConstruct
public void init() {
//打印username
System.out.println("username====" + this.username);
}
}
按照我们的预期,控制台应该打印出username=shishan,但是结果却不是这样的。
我们可以看到控制打印出的结果是usename====cc,cc是博主的电脑用户名。
之所以出现这样的结果,是因为user.name正好与博主的系统变量冲突了,Spring优先读取了系统变量,而忽略了我们的自定义变量。
Spring查找匹配变量时,采用的是策略是匹配即返回,并不会一直匹配到最后一个属性,我们可以在PropertySourcesPropertyResolver#getProperty方法中找到Spring匹配属性的逻辑,感兴趣的朋友可以翻阅源码看一看。
建议我们在自定义属性值时,可以使用比较独特的前缀,比如业务+属性名,尽量和一些重合度比较高的属性名避开,这样可以最大程度的避免这些错误。
最后
本文主要介绍了@Value注解的使用方法,及一个容易出错的写法。在实际业务场景中,一般用于读取自定义配置,提升代码的扩展性,方便后期的维护。
�
学习技术,分享技术,期待与大家共同进步,也感谢您的点赞与关注。