Spring注解驱动开发第18讲——如何使用@Value注解为bean的属性赋值呢?
发布日期:2021-06-30 17:56:08 浏览次数:2 分类:技术文章

本文共 8101 字,大约阅读时间需要 27 分钟。

写在前面

在之前的文章中,我们探讨了如何向Spring的IOC容器中注册bean组件,并且还讲解了有关bean组件的生命周期的知识。今天,我们就来一起聊聊@Value注解的用法。

@Value注解

Spring中的@Value注解可以为bean中的属性赋值。我们先来看看@Value注解的源码,如下所示。

在这里插入图片描述
从@Value注解的源码中我们可以看出,@Value注解可以标注在字段、方法、参数以及注解上,而且在程序运行期间生效。

@Value注解的用法

不通过配置文件注入属性的情况

通过@Value注解将外部的值动态注入到bean的属性中,一般有如下这几种情况:

  • 注入普通字符串

    @Value("李阿昀")private String name; // 注入普通字符串
  • 注入操作系统属性

    @Value("#{systemProperties['os.name']}")private String systemPropertiesName; // 注入操作系统属性
  • 注入SpEL表达式结果

    @Value("#{ T(java.lang.Math).random() * 100.0 }")private double randomNumber; //注入SpEL表达式结果
  • 注入其他bean中属性的值

    @Value("#{person.name}")private String username; // 注入其他bean中属性的值,即注入person对象的name属性中的值
  • 注入文件资源

    @Value("classpath:/config.properties")private Resource resourceFile; // 注入文件资源
  • 注入URL资源

    @Value("http://www.baidu.com")private Resource url; // 注入URL资源

通过配置文件注入属性的情况

首先,我们可以在项目的src/main/resources目录下新建一个属性文件,例如person.properties,其内容如下:

person.nickName=美美侠

然后,我们新建一个MainConfigOfPropertyValues配置类,并在该类上使用@PropertySource注解读取外部配置文件中的key/value并保存到运行的环境变量中。

package com.meimeixia.config;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.context.annotation.PropertySource;import com.meimeixia.bean.Person;@PropertySource(value={
"classpath:/person.properties"})@Configurationpublic class MainConfigOfPropertyValues {
@Bean public Person person() {
return new Person(); } }

加载完外部的配置文件以后,接着我们就可以使用${key}取出配置文件中key所对应的值,并将其注入到bean的属性中了。

package com.meimeixia.bean;import org.springframework.beans.factory.annotation.Value;public class Person {
@Value("李阿昀") private String name; @Value("#{20-2}") private Integer age; @Value("${person.nickName}") private String nickName; // 昵称 public String getNickName() {
return nickName; } public void setNickName(String nickName) {
this.nickName = nickName; } public String getName() {
return name; } public void setName(String name) {
this.name = name; } public Integer getAge() {
return age; } public void setAge(Integer age) {
this.age = age; } public Person(String name, Integer age) {
super(); this.name = name; this.age = age; } public Person() {
super(); // TODO Auto-generated constructor stub } @Override public String toString() {
return "Person [name=" + name + ", age=" + age + ", nickName=" + nickName + "]"; } }

@Value中#{···}和${···}的区别

我们在这里提供一个测试属性文件,例如advance_value_inject.properties,大致的内容如下所示。

server.name=server1,server2,server3author.name=liayun

然后,新建一个AdvanceValueInject类,并在该类上使用@PropertySource注解读取外部属性文件中的key/value并保存到运行的环境变量中,即加载外部的advance_value_inject.properties属性文件。

package com.meimeixia.bean;import org.springframework.context.annotation.PropertySource;import org.springframework.stereotype.Component;@Component@PropertySource(value={
"classpath:/advance_value_inject.properties"})public class AdvanceValueInject {
// ··· }

以上准备工作做好之后,下面我们就来看看${···}的用法。

${···}的用法

{}里面的内容必须符合SpEL表达式,通过@Value("${spelDefault.value}")我们可以获取属性文件中对应的值,但是如果属性文件中没有这个属性,那么就会报错。不过,我们可以通过赋予默认值来解决这个问题,如下所示。

@Value("${author.name:meimeixia}")private String name;

上述代码的含义是表示向bean的属性中注入属性文件中的author.name属性所对应的值,如果属性文件中没有author.name这个属性,那么便向bean的属性中注入默认值meimeixia。

#{···}的用法

{}里面的内容同样也是必须符合SpEL表达式。例如,

// SpEL:调用字符串Hello World的concat方法@Value("#{'Hello World'.concat('!')}")private String helloWorld;// SpEL:调用字符串的getBytes方法,然后再调用其length属性@Value("#{'Hello World'.bytes.length}")private String helloWorldBytes;

${···}和#{···}的混合使用

${···}#{···}可以混合使用,例如,

// SpEL:传入一个字符串,根据","切分后插入列表中, #{}和${}配合使用时,注意不能反过来${}在外面,而#{}在里面@Value("#{'${server.name}'.split(',')}")private List
severs;

上面片段的代码的执行顺序:通过${server.name}从属性文件中获取值并进行替换,然后就变成了执行SpEL表达式{'server1,server2,server3'.split(',')}

在上文中#{}在外面,${}在里面可以执行成功,那么反过来是否可以呢?也就是说能否让${}在外面,#{}在里面,就像下面这样呢?

// SpEL:注意不能反过来,${}在外面,而#{}在里面,因为这样会执行失败@Value("${#{'HelloWorld'.concat('_')}}")private List
severs2;

答案是不能。因为Spring执行${}的时机要早于#{},当Spring执行外层的${}时,内部的#{}为空,所以会执行失败!

小结

  • #{···}:用于执行SpEl表达式,并将内容赋值给属性
  • ${···}:主要用于加载外部属性文件中的值
  • ${···}#{···}可以混合使用,但是必须#{}在外面,${}在里面

@Value注解案例

这里,我们还是以一个小案例的形式来说明。

首先,我们创建一个Person类来作为测试用的bean组件,如下所示。

package com.meimeixia.bean;public class Person {
private String name; private Integer age; public String getName() {
return name; } public void setName(String name) {
this.name = name; } public Integer getAge() {
return age; } public void setAge(Integer age) {
this.age = age; } public Person(String name, Integer age) {
super(); this.name = name; this.age = age; } public Person() {
super(); // TODO Auto-generated constructor stub } @Override public String toString() {
return "Person [name=" + name + ", age=" + age + "]"; } }

然后,创建一个新的配置类,例如MainConfigOfPropertyValues,用来配置Spring的bean组件。我们在该配置类中将Person类的对象注册到IOC容器中了,如下所示。

package com.meimeixia.config;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import com.meimeixia.bean.Person;@Configurationpublic class MainConfigOfPropertyValues {
@Bean public Person person() {
return new Person(); } }

接着,我们再来创建一个测试类,例如IOCTest_PropertyValue,在该测试类中创建一个test01()测试方法,在该测试方法中我们所要做的事情就是通过MainConfigOfPropertyValues配置类来创建AnnotationConfigApplicationContext对象,并打印出目前IOC容器中存在的组件的名称,如下所示。

package com.meimeixia.test;import org.junit.Test;import org.springframework.context.annotation.AnnotationConfigApplicationContext;import com.meimeixia.config.MainConfigOfPropertyValues;public class IOCTest_PropertyValue {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfPropertyValues.class); @Test public void test01() {
printBeans(applicationContext); // 关闭容器 applicationContext.close(); } private void printBeans(AnnotationConfigApplicationContext applicationContext) {
String[] definitionNames = applicationContext.getBeanDefinitionNames(); for (String name : definitionNames) {
System.out.println(name); } }}

紧接着,我们运行IOCTest_PropertyValue测试类中的test01()方法,输出的结果信息如下所示。

在这里插入图片描述
从输出的结果信息中可以看出,IOC容器中除了Spring框架注册的bean之外,还包含我们自己向IOC容器中注册的bean组件,即mainConfigOfPropertyValues和person。

接下来,我们改造下IOCTest_PropertyValue测试类中的test01()方法,让其输出Person对象的信息,如下所示。

package com.meimeixia.test;import org.junit.Test;import org.springframework.context.annotation.AnnotationConfigApplicationContext;import com.meimeixia.bean.Person;import com.meimeixia.config.MainConfigOfPropertyValues;public class IOCTest_PropertyValue {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfPropertyValues.class); @Test public void test01() {
printBeans(applicationContext); System.out.println("==================="); Person person = (Person) applicationContext.getBean("person"); System.out.println(person); // 关闭容器 applicationContext.close(); } private void printBeans(AnnotationConfigApplicationContext applicationContext) {
String[] definitionNames = applicationContext.getBeanDefinitionNames(); for (String name : definitionNames) {
System.out.println(name); } }}

此时,再次运行以上test01()方法,输出的结果信息如下所示。

在这里插入图片描述
可以看到,向IOC容器中注册的Person对象的name属性为null,age属性也为null。那如何向Person对象中的name属性和age属性赋值呢?此时,Spring中的@Value注解就派上用场了。

如果我们通过XML配置文件为bean的属性赋值,那么可以通过如下配置的方式来实现。

如果使用注解,那么该如何实现呢?别急,往下看!

我们可以在Person类的属性上使用@Value注解为属性赋值,如下所示。

package com.meimeixia.bean;import org.springframework.beans.factory.annotation.Value;public class Person {
@Value("李阿昀") private String name; @Value("#{20-2}") private Integer age; public String getName() {
return name; } public void setName(String name) {
this.name = name; } public Integer getAge() {
return age; } public void setAge(Integer age) {
this.age = age; } public Person(String name, Integer age) {
super(); this.name = name; this.age = age; } public Person() {
super(); // TODO Auto-generated constructor stub } @Override public String toString() {
return "Person [name=" + name + ", age=" + age + "]"; } }

此时,我们再次运行IOCTest_PropertyValue测试类中的test01()方法,输出的结果信息如下所示。

在这里插入图片描述
可以看到,使用@Value注解已经向Person对象的name属性中注入了李阿昀,向age属性中注入了18。

转载地址:https://liayun.blog.csdn.net/article/details/110480915 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:Spring注解驱动开发第19讲——使用@PropertySource加载配置文件,我只看这一篇!!
下一篇:Spring注解驱动开发第17讲——BeanPostProcessor在Spring底层是如何使用的?看完这篇我懂了!!

发表评论

最新留言

网站不错 人气很旺了 加油
[***.192.178.218]2024年04月16日 22时44分45秒

关于作者

    喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!

推荐文章