目录
默认值
比如有这样一个需求:如果配置了系统属性,userName就用配置的属性值。如果没有配置,则userName用默认值nieyp。
错误用法:
@Value(value = "${susan.test.userName}")
private String userName = "susan";设置userName默认值的时机,比@Value注解依赖注入属性值要早,也就是说userName初始化好了默认值,后面还是会被覆盖
正确用法:
@Value(value = "${susan.test.userName:nieyp}")
private String userName;如果配置了系统属性,userName就用配置的属性值。如果没有配置,则userName用默认值nieyp。
建议:
假如有这种场景:在business层中包含了UserService类,business层被api服务和job服务都引用了。但UserService类中@Value的userName只在api服务中有用,在job服务中根本用不到该属性。
对于job服务来说,如果不在.properties文件中配置同名的系统属性,则服务启动时就会报错。
这个坑,我之前踩过多次。所以,建议大家,使用@Value注解时,最好给参数设置一个默认值,以防止出现类似的问题。
static变量
静态变量
可以自动注入系统属性值不?
我们一起看看,假如将上面的userName定义成static
的:
@Value("${nieyp.test.userName}")
private static String userName;程序可以正常启动,但是获取到userName的值却是null。由此可见,被
static
修饰的变量通过@Value会注入失败。
正确方法:
@Service
public class UserService {
private static String userName;
@Value("${nieyp.test.userName}")
public void setUserName(String userName) {
UserService.userName = userName;
}
public String test() {
return userName;
}
}提供一个静态参数的
setter
方法,在该方法上使用@Value注入属性值,并且同时在该方法中给静态变量赋值。@Value注解在这里竟然使用在setUserName方法上了,也就是对应的setter方法,而不是在变量上。
变量类型
基本数据类型
-
整型:byte、short、int、long
-
浮点型:float、double
-
布尔型:boolean
-
字符型:char
包装类型
-
整型:Byte、Short、Integer、Long
-
浮点型:Float、Double
-
布尔型:Boolean
-
字符型:Character
@Value注解对这8中基本类型和相应的包装类,有非常良好的支持,例如:
@Value("${nieyp.test.a:1}")
private byte a;
@Value("${nieyp.test.b:100}")
private short b;
@Value("${nieyp.test.c:3000}")
private int c;
@Value("${nieyp.test.d:4000000}")
private long d;
@Value("${nieyp.test.e:5.2}")
private float e;
@Value("${nieyp.test.f:6.1}")
private double f;
@Value("${nieyp.test.g:false}")
private boolean g;
@Value("${nieyp.test.h:h}")
private char h;
@Value("${nieyp.test.a:1}")
private byte a1;
@Value("${nieyp.test.b:100}")
private Short b1;
@Value("${nieyp.test.c:3000}")
private Integer c1;
@Value("${nieyp.test.d:4000000}")
private Long d1;
@Value("${nieyp.test.e:5.2}")
private Float e1;
@Value("${nieyp.test.f:6.1}")
private Double f1;
@Value("${nieyp.test.g:false}")
private Boolean g1;
@Value("${nieyp.test.h:h}")
private Character h1;
数组
定义数组时可以这样写:
@Value("${susan.test.array:1,2,3,4,5}")
private int[] array;spring默认使用逗号分隔参数值。
如果用空格分隔,例如:
@Value("${susan.test.array:1 2 3 4 5}")
private int[] array;spring会自动把空格去掉,导致数据中只有一个值:12345,注意千万别搞错了。
定义数组时一定要注意属性值的类型,必须完全一致才可以
集合类
List
使用spring的EL表达式。
@Value("#{'${nieyp.test.list}'.split(',')}")
private List<String> list;
配置文件
nieyp.test.list=10,11,12,13
适用@ConfigurationProperties
配置文件:
nieyp.test.list[0]=10
nieyp.test.list[1]=11
nieyp.test.list[2]=12
nieyp.test.list[3]=13
配置类
@Configuration
@ConfigurationProperties(prefix = "susan.test")
@Data
public class MyConfig {
private List<String> list;
}调用:
@Service
public class UserService {
@Autowired
private MyConfig myConfig;
public String test() {
System.out.println(myConfig.getList());
return null;
}
}
Set
set用法和list相似不在介绍
如何给set和list添加默认值
这种是正确的用法
@Value("#{'${susan.test.set:}'.empty ? null : '${susan.test.set:}'.split(',')}")
private Set<String> set;以下说明两种错误的用法:
@Value("#{'${susan.test.set:}'.split(',')}")
private Set<String> set;set集合怎么不是空的,而是包含了一个空字符串的集合?
@Value("#{'${susan.test.set: null}'.split(',')}")
private Set<String> set;Set集合也不是空的,而是包含了一个"null"字符串的集合。
Map
java代码:
@Value("#{${susan.test.map}}")
private Map<String, String> map;配置文件
susan.test.map={"name":"苏三", "age":"18"}
设置默认值
@Value("#{'${susan.test.map:}'.empty ? null : '${susan.test.map:}'}")
private Map<String, String> map;
EL高端玩法
注入bean
@Value("#{roleService}")
private RoleService roleService;通过这种方式,可以注入id为roleService的bean。
bean的变量和方法
通过EL表达式,@Value注解已经可以注入bean了。既然能够拿到bean实例,接下来,可以再进一步。
在RoleService类中定义了:成员变量、常量、方法、静态方法。
@Service
public class RoleService {
public static final int DEFAULT_AGE = 18;
public int id = 1000;
public String getRoleName() {
return "管理员";
}
public static int getParentId() {
return 2000;
}
}
在调用的地方这样写:
@Service
public class UserService {
@Value("#{roleService.DEFAULT_AGE}")
private int myAge;
@Value("#{roleService.id}")
private int id;
@Value("#{roleService.getRoleName()}")
private String myRoleName;
@Value("#{roleService.getParentId()}")
private String myParentId;
}
静态类
前面的内容都是基于bean的,但有时我们需要调用静态类,比如:Math、xxxUtil等静态工具类的方法,该怎么办呢?
答:用T加括号。
//可以注入系统的路径分隔符到path中。
@Value("#{T(java.io.File).separator}")
private String path;//可以注入一个随机数到randomValue中。
@Value("#{T(java.lang.Math).random()}")
private double randomValue;
逻辑运算
通过上面介绍的内容,我们可以获取到绝大多数类的变量和方法的值了。但有了这些值,还不够,我们能不能在EL表达式中加点逻辑?
//拼接字符串
@Value("#{roleService.roleName + '' + roleService.DEFAULT_AGE}")
private String value;//逻辑判断
@Value("#{roleService.DEFAULT_AGE > 16 and roleService.roleName.equals('苏三')}")
private String operation;
//三目运算
@Value("#{roleService.DEFAULT_AGE > 16 ? roleService.roleName: '苏三' }")
private String realRoleName;
${}和#{}的区别
${}
主要用于获取配置文件中的系统属性值。
@Value(value = "${susan.test.userName:susan}")
private String userName;可以设置默认值。如果在配置文件中找不到susan.test.userName的配置,则注入时用默认值。
如果在配置文件中找不到susan.test.userName的配置,也没有设置默认值,则启动项目时会报错
#{}
主要用于通过spring的EL表达式,获取bean的属性,或者调用bean的某个方法。还有调用类的静态常量和静态方法。
@Value("#{roleService.DEFAULT_AGE}")
private int myAge;
@Value("#{roleService.id}")
private int id;
@Value("#{roleService.getRoleName()}")
private String myRoleName;
如果是调用类的静态方法,则需要加T(包名 + 方法名称)。例如:T(java.lang.Math)。
@Value("#{T(java.lang.Math).random()}")
private double randomValue;