概述
本文介绍了@Value各种使用方法。
普通变量获取配置信息
可以通过@Value注解在字段上给字段赋值,@Value与bean标签中的value配置作用一致,因此用法也一致。
示例:
@Component
public class Person {
/**
* 1. @Value类似于bean标签中的value配置;
* <bean id = "person" class="xxxxx">
* <property name="address" value="xxx"></property>
* </bean>
* 2. bean中的value可以配置:字面量;${key}获取环境变量、配置文件中的key值,#{SpEl}spring的EL表达式;
* 因此@Value也可以配置上面的三种值。
* 3. @Value获取配置信息,可以不写get/set方法。
*/
@Value("小明")
private String name;
@Value("#{11*2}")
private int age;
@Value("${person.address}")
private String address;
private List<Object> like;
private Map<String, Object> maps;
private Dog dog;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public List<Object> getLike() {
return like;
}
public void setLike(List<Object> like) {
this.like = like;
}
public Map<String, Object> getMaps() {
return maps;
}
public void setMaps(Map<String, Object> maps) {
this.maps = maps;
}
public Dog getDog() {
return dog;
}
public void setDog(Dog dog) {
this.dog = dog;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", address='" + address + '\'' +
", like=" + like +
", maps=" + maps +
", dog=" + dog +
'}';
}
}
@Value注解配置默认值
@Value在注解模式下读取配置文件注入属性值
示例:
@Value("${name}")
private String name;
但是,如果配置文件中没有设置name的值,spring在启动的时候会报错。这时需要给name配置默认值,代码如下:
@Value("${name:bob}")
private String name;
除了String类型外,其他类型也可配置默认值:
@Value("${age:18}")
private int age;
@Value注入列表或者数组
可以使用split()方法在一行中注入“列表”。
配置如下:
config.properties
server.name=hydra,zeus
server.id=100,102,103
AppConfigTest.java
package com.mkyong.analyzer.test;
import java.util.List;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
@Configuration
@PropertySource(value="classpath:config.properties")
public class AppConfigTest {
@Value("#{'${server.name}'.split(',')}")
private List<String> servers;
@Value("#{'${server.id}'.split(',')}")
private List<Integer> serverId;
//To resolve ${} in @Value
@Bean
public static PropertySourcesPlaceholderConfigurer propertyConfigInDev() {
return new PropertySourcesPlaceholderConfigurer();
}
}
注意如果配置项已逗号分隔,无需使用split方法,spring默认支持逗号的分隔。
可以指定默认值,下面的3种写法Spring都是支持的。
@Value("#{'${server.id:127.0.0.1,192.168.1.18}'.split(',')}")
private List<String> serverId;
@Value("${server.id:127.0.0.1,192.168.1.18}")
private List<String> serverId;
@Value("${server.id:127.0.0.1,192.168.1.18}")
private String[] serverId;
@Value给静态变量注入值
- @Value不能直接给静态变量赋值,即使编译不报错,但是结果赋值不成功。
@Value("${fastdfs.cache.redis.expireTime:86400}")
public static int EXPIRE_TIME;
- 静态变量赋值,@Value注解需要放在方法上
类上加上@Component注解,方法名(例如setExpireTime,方法名可以随便写,通常以set开头)和参数名(例如expireTime,参数名也可以随便写),如下所示:
/**
* 缓存过期时间,单位秒
*/
public static int EXPIRE_TIME;
/**
*
* @param expireTime 过期时间
*/
@Value("${fastdfs.cache.redis.expireTime:86400}")
public void setExpireTime(int expireTime) {
EXPIRE_TIME = expireTime;
}
@Value其他用法举例
- 注入操作系统属性
@Value("#{systemProperties['os.name']}")
private String systemPropertiesName; // 注入操作系统属性
- 注入其他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资源
@ConfigurationProperties与@Value的区别
@ConfigurationProperties | @Value | |
---|---|---|
功能 | 可以批量注入配置文件中的属性 | 只能一个个的指定 |
松散语法绑定(对象中的小驼峰命名与配置文件中-命令相互转换,比如:字段:lastName,可以在配置文件中写出last-name/last_name) | 支持 | 不支持 |
SPEL表达式(Spring 表达式) | 不支持 | 支持 |
JSR303数据校验(Java Specification Requests,JSR-303 是JAVA EE 6 中的一项子规范,叫做Bean Validation,Hibernate Validator 是 Bean Validation 的参考实现 . Hibernate Validator 提供了 JSR 303 规范中所有内置 constraint 的实现,除此之外还有一些附加的 constraint。) | 支持 | 不支持 |
复杂类型获取(对象、Map、数组) | 支持 | 不支持 |
配置文件yaml或者properties格式都行。
如果说,我们只是在某个业务逻辑中需要获取一下配置文件中的某项值,使用@Value;
如果说,我们专门编写了一个javaBean来和配置文件进行映射,我们就直接使用@ConfigurationProperties;
@PropertySource注解通过配置文件注入属性
首先,我们可以在项目的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"})
@Configuration
public 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,server3
author.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<String> severs;
上面片段的代码执行顺序:通过KaTeX parse error: Expected ‘EOF’, got ‘#’ at position 88: …lit(‘,’)}。 在上文中#̲{}在外面,{}在里面可以执行成功,那么反过来是否可以呢?
// 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: {…}和#̲{}可以混合使用,但是必须#{…{}在里面。
参考
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/100236.html