如果您想在Spring Boot 项目的配置文件(application.properties
或 application.yml
)中设置一个随机值,应该怎么办呢?这个Spring Boot已经有了解决方案。下面就通过示例详细说明。
配置随机值
在Spring Boot项目中同构配置获取随机值可以参考如下配置示例:
1 2 3 4 5 6 7 my.id =${random.uuid} my.secret ="${random.value}" my.number ="${random.int}" my.bignumber ="${random.long}" my.uuid ="${random.uuid}" my.number-less-than-ten ="${random.int(10)}" my.number-in-range ="${random.int[1024,65536]}"
1 2 3 4 5 6 7 8 my: id: ${random.uuid} secret: "${random.value}" number: "${random.int}" bignumber: "${random.long}" uuid: "${random.uuid}" number-less-than-ten: "${random.int(10)}" number-in-range: "${random.int[1024,65536]}"
OK!有了上面的配置,我们来用如下代码测试一下:
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 import org.springframework.beans.factory.annotation.Autowired;import org.springframework.beans.factory.annotation.Value;import org.springframework.core.env.Environment;import org.springframework.stereotype.Component;@Component public class RandomValuesTester { @Value("${my.id}") private String id; @Value("${my.secret}") private String secret; @Value("${my.number}") private String number; @Value("${my.bignumber}") private String bigNumber; @Value("${my.uuid}") private String uuid; @Value("${my.number-less-than-ten}") private String numberLessThanTen; @Value("${my.number-in-range}") private String numberInRange; @Autowired private Environment environment; public void test () { placeholderTest(); System.out.println("========================" ); useEnvironmentTest(); } private void placeholderTest () { System.out.println(id); System.out.println(secret); System.out.println(number); System.out.println(bigNumber); System.out.println(uuid); System.out.println(numberLessThanTen); System.out.println(numberInRange); } private void useEnvironmentTest () { System.out.println(environment.getProperty("my.id" )); System.out.println(environment.getProperty("my.secret" )); System.out.println(environment.getProperty("my.number" )); System.out.println(environment.getProperty("my.bignumber" )); System.out.println(environment.getProperty("my.uuid" )); System.out.println(environment.getProperty("my.number-less-than-ten" )); System.out.println(environment.getProperty("my.number-in-range" )); } }
来运行一下上面的测试,看看结果如何:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 2021-03-31 19:45:57.632 INFO 25308 --- [ main] com.jeremy.tech.lab.LabApplication : Started LabApplication in 2.034 seconds (JVM running for 3.125) 43adc303-aa7b-4424-ac59-4261b7527461 4032da51f1edd76256abee1683c6ca96 -354560558 -6325973753148526700 04e686db-4a1a-42af-8d59-1d17501166ae 8 35928 ======================== 258a9bb9-f6fc-4d5b-bcea-8a4528a60c6d 04e44548ea9a5c5b2c0bee1a4f2c1658 -722507177 -313282001081326805 509dba0b-caf2-4477-8970-de648baa388e 8 51141 2021-03-31 19:45:58.158 INFO 25308 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Shutting down ExecutorService 'applicationTaskExecutor'
怎么样?你可以多运行几次(可以循环调用 environment.getProperty("xxx")
)看看是不是每次都是随机的值。下面介绍一下这些值是怎么获取的。
源码分析
其实这个的实现并不神秘,一切都靠 org.springframework.boot.env.RandomValuePropertySource
这个类来实现。
这个类的源码如下(关键部分):
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 public class RandomValuePropertySource extends PropertySource <Random > { public static final String RANDOM_PROPERTY_SOURCE_NAME = "random" ; private static final String PREFIX = "random." ; public RandomValuePropertySource (String name) { super (name, new Random()); } @Override public Object getProperty (String name) { if (!name.startsWith(PREFIX)) { return null ; } logger.trace(LogMessage.format("Generating random property for '%s'" , name)); return getRandomValue(name.substring(PREFIX.length())); } private Object getRandomValue (String type) { if (type.equals("int" )) { return getSource().nextInt(); } if (type.equals("long" )) { return getSource().nextLong(); } String range = getRange(type, "int" ); if (range != null ) { return getNextIntInRange(range); } range = getRange(type, "long" ); if (range != null ) { return getNextLongInRange(range); } if (type.equals("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); } private Object getRandomBytes () { byte [] bytes = new byte [32 ]; getSource().nextBytes(bytes); return DigestUtils.md5DigestAsHex(bytes); } }
分析
通过上面的源码,我们可以很容易的识别出来我们是如何获取这些随机值的。原来这些随机值都是通过 Object getProperty(String name)
这个函数来获取的,这个函数是继承了父类的重写方法。
通过函数调用 Object getRandomValue(String type)
可以很清楚的看到每种随机值的获取方式。源码很简单我就不展开说明了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 private Object getRandomValue (String type) { if (type.equals("int" )) { return getSource().nextInt(); } if (type.equals("long" )) { return getSource().nextLong(); } String range = getRange(type, "int" ); if (range != null ) { return getNextIntInRange(range); } range = getRange(type, "long" ); if (range != null ) { return getNextLongInRange(range); } if (type.equals("uuid" )) { return UUID.randomUUID().toString(); } return getRandomBytes(); }
结论
通过分析我们可以得出结论:
${random.value}
的值是一个随机的32位十六进制的MD5摘要值
${random.int}
的值是通过 new Random()
获取的一个随机的int值
${random.long}
的值是通过 new Random()
获取的一个随机的long值
${random.uuid}
的值是通过 UUID.randomUUID().toString()
获取的一个随机UUID值
${random.int(10)}
的值是一个不大于10的int值
${random.int[1024,65536]}
的值是一个包含1024,不包含65535的一个随机值
注:${random.int[min,max]}
中的 [min, max]
是一个包含min
不包含max
的范围,{random.long[min,max]}
也是一样的,只不过最大值是Long.MAX
而已。
最后
Spring Boot的属性配置也是一个比较大的知识点,这里仅仅列出了冰山一角。如果您想了解更多的关于配置的概念,可以从了解PropertySource
入手,属性的初始化在 Application.run
函数中的如下三个关键函数调用中赋值:
prepareContext
refreshContext
afterRefresh
另外,顺便提一句。上文一开始给出了两种配置文件 *.properties
和 *.yml
。 如果您的项目中同时存在这两个配置文件,并且配置文件中的属性有同样的key,最终 *.yml
中的配置会覆盖 *.properties
中的配置。
欢迎关注我的公众号 须弥零一 ,跟我一起学习IT知识。
如果您喜欢此博客或发现它对您有用,则欢迎对此发表评论。 也欢迎您共享此博客,以便更多人可以参与。 如果博客中使用的图像侵犯了您的版权,请与作者联系以将其删除。 谢谢 !