1. @Value
1.1 @Value 介绍
@Value 注解是 Spring 基础注解包 org.springframework.beans.factory.annotation
中的注解,常用来将配置文件中定义的属性值注入到 Java 对象中来。
需要注意的是,@Value 默认注入的变量应该是非静态的,因为 @Value 是受 Spring 容器管理,需要在 Bean 加载的过程中实现属性的赋值操作。
1.2 读取配置文件
读取项目配置文件内容是 @Value 最常使用的一种方式,通过 @Value 注解可以将默认配置文件或指定配置文件中的配置内容注入到属性中。
-
对于默认的配置文件
application.properties
,Spring 会自动加载该文件,因此使用时只需要使用@Value("${key}")
就可以注入其中定义的内容 -
对于非默认的配置文件,如
dev.properties
,需要在程序中使用 @PropertySource 将配置文件引入,之后便可以使用@Value("${key}")
进行注入操作
1.3 读取非配置文件
除了可以注入项目的配置文件内容,@Value 还可以注入其他非配置文件内容,此时会使用到 Spring 表达式进行操作,即 SpEL(Spring Expression Language),如注入字符串、文件资源、URL 等信息。
-
@Value("Str"),直接注入字符串
-
@Value("classpath:mybatis.xml"),注入文件资源,需要使用 Resource 对象接收
-
@Value("www.juejin.com"),注入 URL 资源,使用 URL 对象接收
对于使用 @Value 注入非配置文件的情况比较少见,本次不做讲解,只看一下注入配置文件时的使用。
2. @Value 使用
使用 @Value 注解注入配置文件内容时,配合简单的 SpEl 可以比较自由的实现各种内容的注入,如指定配置的默认值可以在读取不到配置时自动使用默认值。
2.1 ${}
和 #{}
${}
和 #{}
是 @Value 注解使用时两种取值方式,其中声明需要获取值的 key,程序执行时就会根据 key 注入对应的 value。
-
${…}
,主要用于加载外部属性文件中的值,即配置文件中定义的属性 -
#{…}
,用于执行SpEl表达式,并将内容赋值给属性 -
#{…}
和${…}
可以混合使用,但使用时必须保证#{}
在外面,${}
在里面
2.2 注入 String
Spring 的配置文件中默认是以 key=value 方式定义的,且 key 和 value 默认是 String 类型,因此对于定义的内容最方便的就是注入到 String 类型的属性中。
- 针对 name 属性注入 server.name 配置时设置不同的默认值
// 常用配置方式,无默认值,没有对应配置时会报错
@Value("${server.name}")
private String name;
// 默认值是空字符串 ""
@Value("${server.name:}")
private String name;
// 默认值 null
@Value("${server.name:null}")
private String name;
// 默认值 defaultValue
@Value("${server.name:defaultValue}")
private String name;
2.3 注入 Array
除了普通的 String 类型,@Value 注解还可以注入 Array 类型内容,需要在配置文件中指定时使用逗号间隔
server.array=array1,array2,array3
server:
array: array1,array2,array3
- 注入 Array 属性值
//默认值为空数组 []
@Value("${server.array:}")
private String[] array;
//默认值为 [1,2,3]
@Value("${server.array:1,2,3}")
private String[] array;
2.4 注入 List
List 类型与 Array 类似,注入 List 类型内容时在配置文件中指定时也要使用逗号作为间隔
server.list=list1,list2,list3
server:
list: list1,list2,list3
- 注入时可以使用 SpEL 表达式指定使用的间隔符号,如果不指定,则默认使用逗号间隔
//默认值为空 list
@Value("${server.list:}")
private String[] list;
//默认值为 [1,2,3]
@Value("${server.list:1,2,3}")
private String[] list;
//指定间隔符号为逗号,默认值为空 list
@Value("#{'${server.list:,}'.split(',')}")
private String[] list;
//指定间隔符号为逗号,默认值为 list 中有个空字符串
@Value("#{'${server.list:}'.split(',')}")
private String[] list;
//指定间隔符号为逗号,默认值为 [1,2,3]
@Value("#{'${server.list:[1,2,3]}'.split(',')}")
private String[] list;
2.5 注入 Map
Map 类型本身就是 key-value 的形式,此时在配置文件定义时要按照对象的方式声明,其中 key 可以不带单引号,value 必须带单引号,形式如下:
server.user={tom:'value1',lily:'value2'}
server
user: {tom:'value1',lily:'value2'}
- Map 内容注入时,必须使用 SpEL 表达式才可以完成
//默认值为 null
@Value("#{${server.user:{}}}")
private String[] user;
//默认值为 null
@Value("#{${server.user:null}")
private String[] user;
//默认值为 {"a":"1","b":"2"}
@Value("#{${server.user:{a:'1', b:'2'}}}")
private String[] user;
2.6 @ConfigurationProperties 注解
@ConfigurationProperties 是 SpringBoot 中提供的一种更加方便的注入配置文件内容的注解,使用 @ConfigurationProperties 可以标准在一个类上,并指定一组固定前缀的配置属性,注入到 JavaBean 中对应的属性中。
使用 @ConfigurationProperties 注解注入时,对于 List 和 Map 类型可以根据属性名称自动注入,使用更方便。
需要注意的是,使用 @ConfigurationProperties 时还要为 Java 类使用 @Configuration 或其他注解以保证交由容器管理,另外还需要保证类中的属性有 set 方法才可以满足注入条件。
@ConfigurationProperties 注解的使用也不作为本次讲解对象。
3. 使用 @Value 为静态变量赋值
@Value 不支持直接为静态变量注入值,使用时需要保证类交由容器管理,并自动注入到容器对象中。
如果想要为静态变量赋值配置文件中的内容,则需要通过转发操作实现,类似还有:实现 JavaBean 注入到静态变量中。
3.1 通过 set 方法注入到静态属性变量中
与其他注入方式一样, @Value 注解也可以用到 setter 方法上
public static String name;
@Value("${server.name}")
public void setName(String name){
name = name;
}
3.2 通过 @PostConstruct 注解实现
@PostConstruct 是在 Bean 初始化(initializeBean)过程中调用的,且是在 @Value 之后调用的,可以通过该方式实现对静态变量赋值。
@Value("${server.name}")
public String nameTemp;
public static String name;
@PostConstruct
private void init(){
name = this.nameTemp;
}
3.3 实现 InitializingBean 接口
还可以通过实现 InitializingBean 接口并重写其中的 afterPropertiesSet() 方法来实现静态变量赋值,InitializingBean 接口也是在 Bean 初始化(initializeBean)过程中调用的,因此可以满足在 Bean 初始化时将内容注入到静态变量中,具体可以了解下 Spring Bean 的实例化过程。
public class IndexController implements InitializingBean {
@Value("${server.name}")
public String nameTemp;
public static String name;
@Override
public void afterPropertiesSet() throws Exception {
name = nameTemp;
}
}