Knowledge changes fate, stroke code makes me happy, 2020 continue to walk in the open source community click “like” to see, form a habit to give me a Star, click to understand the componentialized interface services based on SpringBoot landing solution

Do you use random numbers a lot? Server. port = ${random.int(10000)} in the application.properties file. Indicates a random port number ranging from 0 to 10000.

Do you know how ${random. Int} is implemented?

Recommended reading

  • Springboot2.x tutorial summary

An overview of the

Configuration file Mode

Before we analyze the source code, let’s take a look at what kind of random configuration ${random.xxx} provides.

Int random number

${random. Int}, the result is generated between the minimum value of int and the minimum value of int. The minimum value of int is -2147483648, and the maximum value is 2147483647.

server:
  port: ${random.int}
Copy the code

Int Range random number

${random.int(10000)} specifies the maximum value of a random number, which cannot exceed 2147483647.

server:
  port: ${random.int(10000)}
Copy the code

Note: ${random.int(10000)} random number will be generated between 0 and 10000, the maximum value must be a positive integer!!

If you need to specify the minimum value of a random number, you can use ${random.int[100,200]} to generate a random number from 100 to 200 (including the minimum value but not the maximum value).

Long random number

If ${random.long} is used, the result will be generated between the maximum value and minimum value of long. The minimum value of long is -9223372036854775808, and the maximum value is 9223372036854775807.

config:
  longValue: ${random.long}
Copy the code

Long Range random number

With ${random.long(10000)}, we can specify any value between 0 and 9223372036854775807 as the maximum value of randomization, as follows:

config:
  maxLongValue: ${random.long(102400)}
Copy the code

Uuid random number

Uuid, because of its uniqueness, should be more commonly used in our daily development.

SpringBoot takes this into account for us, and we can just use ${random.uuid} to get a random UUID string as follows:

config:
  uuid: ${random.uuid}
Copy the code

@ Value way

If we need to generate random numbers in our coding, ${random} supports injection, mainly because its implementation inherits from PropertySource.

We can use the @Value annotation directly within the Spring IOC managed class for injection, as follows:

/** * Randomly generates the UUID string */
@Value("${random.uuid}")
private String uuid;
/** * Randomly generates positive integers from 0 to 1000 */
@Value("${random.int(1000)}")
private int maxInt;
/** * Randomly generate long values from 0 to 102400 */
@Value("${random.long(102400)}")
private long maxLong;
Copy the code

The source code parsing

The reason we can use a random number so convenient, owe SpringBoot provides us with a named RandomValuePropertySource PropertySource implementation class, The implementation class is located in the org. Springframework. Boot. Env bags, this part of the source code is as follows:

/ * * * {@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 {@linkPropertySource} * ... * /
public class RandomValuePropertySource extends PropertySource<Random> {

  private static final String PREFIX = "random.";

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

  @Override
  public Object getProperty(String name) {
    // Only configurations starting with random
    if(! name.startsWith(PREFIX)) {return null;
    }
    if (logger.isTraceEnabled()) {
      logger.trace("Generating random property for '" + name + "'");
    }
    // Get the number of data and pass random. As a type parameter to the getRandomValue method
    return getRandomValue(name.substring(PREFIX.length()));
  }
  
  private Object getRandomValue(String type) {
    // Handle random numbers of type random. Int
    if (type.equals("int")) {
      return getSource().nextInt();
    }
    // Handle random numbers of type random.long
    if (type.equals("long")) {
      return getSource().nextLong();
    }
    // Handle random numbers of type random.int(100)
    String range = getRange(type, "int");
    if(range ! =null) {
      // Generate a range of random int numbers
      return getNextIntInRange(range);
    }
    // Handle random numbers of type random.long(1024)
    range = getRange(type, "long");
    if(range ! =null) {
      // Generate a range of long type random numbers
      return getNextLongInRange(range);
    }
    // Handle random numbers of type random. Uuid
    if (type.equals("uuid")) {
      // Generate random UUID returns
      return UUID.randomUUID().toString();
    }
    // Returns random bytes by default
    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;
    returnlowerBound + Math.abs(getSource().nextLong() % upperBound); }}Copy the code

When we use ${random. XXX} to fetch a random number, Whether the configuration file or by org. @ Value every way springframework. Boot. The env. RandomValuePropertySource# getProperty method to get the corresponding type of random Numbers.

Note: RandomValuePropertySource generic types for the Random, when inheriting PropertySource Java. Util. The Random class contains all the randomly generated within the logic, the class is provided by Java, are interested can study the source code.

conclusion

SpringBoot configuration by ConfigurablePropertyResolver attribute configuration within the parser to obtain, and the class instantiation within AbstractEnvironment, The property configuration provided by multiple PropertySource implementation classes can be obtained via the AbstractEnvironment#getProperty(java.lang.string) method.

Author’s personal blog uses the open source framework ApiBoot to help you become an Api service architect