Spring Boot從配置獲取隨機值
Spring Boot從配置獲取隨機值
application.properties 或 application.yml)中設置一個隨機值,應該怎么辦呢?這個Spring Boot已經有了解決方案。下面就通過示例詳細說明。通過配置獲取隨機值
?application.properties
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]}"
?application.yml
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]}"
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;@Componentpublic 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;@Autowiredprivate 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"));}}
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-4261b75274614032da51f1edd76256abee1683c6ca96-354560558-632597375314852670004e686db-4a1a-42af-8d59-1d17501166ae835928========================258a9bb9-f6fc-4d5b-bcea-8a4528a60c6d04e44548ea9a5c5b2c0bee1a4f2c1658-722507177-313282001081326805509dba0b-caf2-4477-8970-de648baa388e8511412021-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 這個類來實現(xiàn)。這個類的源碼如下(關鍵部分):
public class RandomValuePropertySource extends PropertySource<Random> {/*** Name of the random {@link PropertySource}.*/public static final String RANDOM_PROPERTY_SOURCE_NAME = "random";private static final String PREFIX = "random.";public RandomValuePropertySource(String name) {super(name, new Random());}@Overridepublic 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) 這個函數(shù)來獲取的,這個函數(shù)是繼承了父類的重寫方法。Object getRandomValue(String type) 可以很清楚的看到每種隨機值的獲取方式。源碼很簡單我就不展開說明了。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 而已。
最后
PropertySource 入手,屬性的初始化在 Application.run 函數(shù)中的如下三個關鍵函數(shù)調用中賦值:?prepareContext?refreshContext?afterRefresh
*.properties 和 *.yml 。如果您的項目中同時存在這兩個配置文件,并且配置文件中的屬性有同樣的key,最終 *.yml 中的配置會覆蓋 *.properties 中的配置。歡迎關注我的公眾號“須彌零一”,原創(chuàng)技術文章第一時間推送。
評論
圖片
表情
