18-19属性赋值

Spring注解驱动开发第18讲——如何使用@Value注解为bean的属性赋值呢?

在之前的文章中,我们探讨了如何向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并保存到运行的环境变量中。


@PropertySource(value={"classpath:/person.properties"})
@Configuration
public class MainConfigOfPropertyValues {

	@Bean
	public Person person() {
		return new Person();
	}
	
}

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



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,server3
author.name=liayun

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


@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<String> severs;

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

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

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

答案是不能。因为Spring执行KaTeX parse error: Expected 'EOF', got '#' at position 9: {}的时机要早于#̲{},当Spring执行外层的{}时,内部的#{}为空,所以会执行失败!

小结

#{···}:用于执行SpEl表达式,并将内容赋值给属性
${···}:主要用于加载外部属性文件中的值
KaTeX parse error: Expected 'EOF', got '#' at position 7: {···}和#̲{···}可以混合使用,但是必…{}在里面

@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容器中了,如下所示。


@Configuration
public class MainConfigOfPropertyValues {

	@Bean
	public Person person() {
		return new Person();
	}
	
}

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

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对象的信息,如下所示。


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的属性赋值,那么可以通过如下配置的方式来实现。

<bean id="person" class="com.meimeixia.bean.Person">
    <property name="age" value="18"></property>
    <property name="name" value="liayun"></property>
</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。

Spring注解驱动开发第19讲——使用@PropertySource加载配置文件,我只看这一篇!!

简单介绍一下@PropertySource和@PropertySources这俩注解

1,@PropertySource注解概述

从@PropertySource的源码中可以看出,我们可以通过@PropertySource注解指定多个properties文件,使用的形式如下所示。

@PropertySource(value={"classpath:/person.properties", "classpath:/car.properties"})

细心的读者可以看到,在@PropertySource注解的上面标注了如下的注解信息。

@Repeatable(PropertySources.class)

2 @PropertySources

@PropertySources(value={
    @PropertySource(value={"classpath:/person.properties"}),
    @PropertySource(value={"classpath:/car.properties"}),
})

@PropertySource注解概述

@PropertySource注解是Spring 3.1开始引入的配置类注解。通过@PropertySource注解可以将properties配置文件中的key/value存储到Spring的Environment中,Environment接口提供了方法去读取配置文件中的值,参数是properties配置文件中定义的key值。当然了,也可以使用@Value注解用${}占位符为bean的属性注入值。

我们来看一下@PropertySource注解的源代码,如下所示。
在这里插入图片描述

从@PropertySource的源码中可以看出,我们可以通过@PropertySource注解指定多个properties文件,使用的形式如下所示。

@PropertySource(value={"classpath:/person.properties", "classpath:/car.properties"})

细心的读者可以看到,在@PropertySource注解的上面标注了如下的注解信息。

@Repeatable(PropertySources.class)

看到这里,小伙伴们是不是有种恍然大悟的感觉呢?没错,我们也可以使用@PropertySources注解来指定properties配置文件。

@PropertySources注解概述

首先,我们也来看下@PropertySources注解的源码,如下所示。

在这里插入图片描述
@PropertySources注解的源码比较简单,只有一个PropertySource[]数组类型的value属性,那我们如何使用@PropertySources注解指定配置文件呢?其实也很简单,使用如下所示的方式就可以了。

@PropertySources(value={
    @PropertySource(value={"classpath:/person.properties"}),
    @PropertySource(value={"classpath:/car.properties"}),
})

是不是很简单呢?接下来,我们就以一个小案例来说明@PropertySource注解的用法。

一个小案例来说明@PropertySource注解的用法

准备工作

首先,我们在工程的src/main/resources目录下创建一个配置文件,例如person.properties,该文件的内容如下所示。

person.nickName=小甜甜

然后,我们在Person类中新增一个nickName字段,如下所示。

package com.meimeixia.bean;

import org.springframework.beans.factory.annotation.Value;

public class Person {
	
	@Value("李阿昀")
	private String name;
	@Value("#{20-2}")
	private Integer age;

	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 + "]";
	}
	
}

目前,我们并没有为Person类的nickName字段赋值,所以,此时Person类的nickName字段的值为空。我们可以运行IOCTest_PropertyValue类中的test01()方法来看下输出结果,如下所示。

可以看到,Person类的nickName字段的值确实输出了null。

使用XML配置文件方式获取值

如果我们需要在XML配置文件中获取person.properties文件中的值,那么我们首先需要在Spring的XML配置文件中引入context名称空间,并且使用context命名空间导入person.properties文件,之后在bean的属性字段中使用如下方式将person.properties文件中的值注入到Person类的nickName字段上。

<context:property-placeholder location="classpath:person.properties" />

<!-- 注册组件 -->
<bean id="person" class="com.meimeixia.bean.Person">
    <property name="age" value="18"></property>
    <property name="name" value="liayun"></property>
    <property name="nickName" value="${person.nickName}"></property>
</bean>

此时,整个beans.xml文件的内容如下所示。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p"
	xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans 
						http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
						http://www.springframework.org/schema/context 
						http://www.springframework.org/schema/context/spring-context-4.2.xsd">

	<context:property-placeholder location="classpath:person.properties" />
	
	<!-- 注册组件 -->
	<bean id="person" class="com.meimeixia.bean.Person">
		<property name="age" value="18"></property>
		<property name="name" value="liayun"></property>
		<property name="nickName" value="${person.nickName}"></property>
	</bean>
	
</beans>

这样就可以将person.properties文件中的值注入到Person类的nickName字段上了。

然后,我们在IOCTest_PropertyValue类中创建一个test02()测试方法,如下所示。

@Test
public void test02() {
    ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:beans.xml");
    Person person = (Person) applicationContext.getBean("person");
    System.out.println(person);
}

接着,运行以上test02()方法,输出的结果信息如下所示。

使用注解方式获取值

如果我们使用注解的方式,那么该如何做呢?首先,我们需要在MainConfigOfPropertyValues配置类上添加一个@PropertySource注解,如下所示。


// 使用@PropertySource读取外部配置文件中的key/value保存到运行的环境变量中,加载完外部的配置文件以后,使用${}取出配置文件中的值
@PropertySource(value={"classpath:/person.properties"})
@Configuration
public class MainConfigOfPropertyValues {

	@Bean
	public Person person() {
		return new Person();
	}
	
}

这里使用的@PropertySource(value={“classpath:/person.properties”})注解就相当于XML配置文件中使用的<context:property-placeholder location=“classpath:person.properties” />。

然后,我们就可以在Person类的nickName字段上使用@Value注解来获取person.properties文件中的值了,如下所示。

@Value("${person.nickName}")
private String nickName; // 昵称

配置完成后,我们再次运行IOCTest_PropertyValue类中的test01()方法来看下输出结果,如下所示。

可以看到,此时Person类的nickName字段已经注入小甜甜这个值了。

使用Environment获取值

上面我已经说过,使用@PropertySource注解读取外部配置文件中的key/value之后,是将其保存到运行的环境变量中了,所以我们也可以通过运行环境来获取外部配置文件中的值。

这里,我们可以稍微修改一下IOCTest_PropertyValue类中的test01()方法,即在其中添加一段使用Environment获取person.properties文件中的值的代码,如下所示。

@Test
public void test01() {
    printBeans(applicationContext);
    System.out.println("===================");
    
    Person person = (Person) applicationContext.getBean("person");
    System.out.println(person);
    
    ConfigurableEnvironment environment = applicationContext.getEnvironment();
    String property = environment.getProperty("person.nickName");
    System.out.println(property);
    
    // 关闭容器
    applicationContext.close();
}

运行以上test01()方法,可以看到输出的结果信息如下所示。
在这里插入图片描述
可以看到,使用Environment确实能够获取到person.properties文件中的值。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值