spring 配置项 随机_SpringBoot2.x基础篇:探索配置文件中随机数的实现方式

本文介绍了SpringBoot2.x中如何在配置文件里使用${random}语法生成随机数,包括int、int范围、long、long范围以及uuid等,并解析了其底层的RandomValuePropertySource实现原理。
摘要由CSDN通过智能技术生成

随机数的使用你是不是经常用到?我们在进行运行SpringBoot单元测试时一般不会指定应用程序启动时的端口号,可以在application.properties文件内配置server.port的值为${random.int(10000)},代表了随机使用0~10000的端口号。

既然这种方式使用这么方便,那你知道${random.int}是通过什么方式实现的吗?

推荐阅读

概述

24778acd2e62c583c50136d668ccfa8d.png

配置文件方式

在我们分析源码之前,我们先来看看${random.xxx}具体提供了哪几种的随机配置。

int随机数

使用${random.int}方式配置,结果从int的最大值、最小值中间产生,int的最小值为-2147483648,最大值为2147483647,配置如下所示:

1

2server:

port: ${random.int}

int范围随机数

使用${random.int(10000)}方式配置,这种方式我们可以指定随机数的最大值,当然不能超过2147483647,配置如下所示:

1

2server:

port: ${random.int(10000)}

注意事项:${random.int(10000)}随机数的值将会在0~10000之间产生,配置的最大值必须为正整数,

如果需要指定随机数的最小值,可以使用${random.int[100,200]}方式配置,这样只会从100~200之间产生随机数(包括最小值,不包括最大值)。

long随机数

使用${random.long}方式配置,结果会从long的最大值、最小值中间产生,long的最小值为-9223372036854775808,最大值为9223372036854775807,配置方式如下所示:

1

2config:

longValue: ${random.long}

long范围随机数

使用${random.long(10000)}方式配置,我们可以指定0~9223372036854775807之间的任意数值作为随机的最大上限,配置方式如下所示:

1

2config:

maxLongValue: ${random.long(102400)}

如果需要指定最小值,可以使用${random.long[1024,2048]}方式配置,这样只会从1024~2048中产生随机数(包括最小值,不包括最大值)。

uuid随机数

uuid因为它的唯一性,应该是我们平时开发中比较常用到的。

SpringBoot也为我们考虑到了这一点,我们只需要使用${random.uuid}就可以获得一个随机的uuid字符串,配置方式如下所示:

1

2config:

uuid: ${random.uuid}

@Value方式

如果在我们在编码中需要用到随机数的生成,${random}是支持注入使用的,主要还是因为它的实现继承自PropertySource。

我们可以在Spring IOC所管理的类内直接使用@Value注解进行注入使用,如下所示:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15/**

* 随机生成uuid字符串

*/

@Value("${random.uuid}")

private String uuid;

/**

* 随机生成0~1000的正整数

*/

@Value("${random.int(1000)}")

private int maxInt;

/**

* 随机生成0~102400的long类型数值

*/

@Value("${random.long(102400)}")

private long maxLong;

源码解析

我们之所以可以这么方便的使用随机数,都归功于SpringBoot为我们提供了一个名为RandomValuePropertySource的PropertySource实现类,该实现类位于org.springframework.boot.env包内,该类部分源码如下所示:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84/**

* {@link PropertySource} that returns a random value for any property that starts with

* {@literal "random."}. Where the "unqualified property name" is the portion of the

* requested property name beyond the "random." prefix, this {@link PropertySource}

* ...

*/

public class RandomValuePropertySource extends PropertySource{

private static final String PREFIX = "random.";

private static final Log logger = LogFactory.getLog(RandomValuePropertySource.class);

@Override

public Object getProperty(String name){

// 仅处理random.开头的配置

if (!name.startsWith(PREFIX)) {

return null;

}

if (logger.isTraceEnabled()) {

logger.trace("Generating random property for '" + name + "'");

}

// 获取数据数,将random.后的内容作为类型参数传递到getRandomValue方法

return getRandomValue(name.substring(PREFIX.length()));

}

private Object getRandomValue(String type){

// 处理random.int类型的随机数

if (type.equals("int")) {

return getSource().nextInt();

}

// 处理random.long类型的随机数

if (type.equals("long")) {

return getSource().nextLong();

}

// 处理random.int(100)类型的随机数

String range = getRange(type, "int");

if (range != null) {

// 生成有范围的int类型随机数

return getNextIntInRange(range);

}

// 处理random.long(1024)类型的随机数

range = getRange(type, "long");

if (range != null) {

// 生成有范围的long类型随机数

return getNextLongInRange(range);

}

// 处理random.uuid类型的随机数

if (type.equals("uuid")) {

// 生成随机的uuid返回

return UUID.randomUUID().toString();

}

// 默认返回随机字节

return getRandomBytes();

}

private String getRange(String type, String prefix){

if (type.startsWith(prefix)) {

int startIndex = prefix.length() + 1;

if (type.length() > startIndex) {

return type.substring(startIndex, type.length() - 1);

}

}

return null;

}

private int getNextIntInRange(String range){

String[] tokens = StringUtils.commaDelimitedListToStringArray(range);

int start = Integer.parseInt(tokens[0]);

if (tokens.length == 1) {

return getSource().nextInt(start);

}

return start + getSource().nextInt(Integer.parseInt(tokens[1]) - start);

}

private long getNextLongInRange(String range){

String[] tokens = StringUtils.commaDelimitedListToStringArray(range);

if (tokens.length == 1) {

return Math.abs(getSource().nextLong() % Long.parseLong(tokens[0]));

}

long lowerBound = Long.parseLong(tokens[0]);

long upperBound = Long.parseLong(tokens[1]) - lowerBound;

return lowerBound + Math.abs(getSource().nextLong() % upperBound);

}

}

当我们使用${random.xxx}这种方式获取随机数时,无论是配置文件方式还是@Value方式都会通过org.springframework.boot.env.RandomValuePropertySource#getProperty方法来获取对应类型的随机数。

注意事项:RandomValuePropertySource在继承PropertySource时泛型类型为Random,java.util.Random类内包含了全部的随机生成逻辑,该类由java提供,有兴趣可以研究下源码。

总结

SpringBoot内的配置都是通过ConfigurablePropertyResolver属性配置解析器来获取的,而该类的实例化在AbstractEnvironment内,我们通过AbstractEnvironment#getProperty(java.lang.String)方法可以获取由多个PropertySource实现类提供的属性配置。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值