Spring的@Value注解使用实践及一个经典的易错场景

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的值:

image

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);
    }
}

启动项目,控制台打印出来我们自定义的属性值:

image

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对象的属性:

image

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,但是结果却不是这样的。

image

我们可以看到控制打印出的结果是usename====cc,cc是博主的电脑用户名。

之所以出现这样的结果,是因为user.name正好与博主的系统变量冲突了,Spring优先读取了系统变量,而忽略了我们的自定义变量。

Spring查找匹配变量时,采用的是策略是匹配即返回,并不会一直匹配到最后一个属性,我们可以在PropertySourcesPropertyResolver#getProperty方法中找到Spring匹配属性的逻辑,感兴趣的朋友可以翻阅源码看一看。

建议我们在自定义属性值时,可以使用比较独特的前缀,比如业务+属性名,尽量和一些重合度比较高的属性名避开,这样可以最大程度的避免这些错误。

最后

本文主要介绍了@Value注解的使用方法,及一个容易出错的写法。在实际业务场景中,一般用于读取自定义配置,提升代码的扩展性,方便后期的维护。

学习技术,分享技术,期待与大家共同进步,也感谢您的点赞与关注。

你可能感兴趣的:(Spring的@Value注解使用实践及一个经典的易错场景)