SpringBoot- the use of advanced configuration

I. 【SpringBoot- the use of advanced configuration】Introduction


Hello everyone, I'm Cabbage, a sophomore. This article is an introduction to the advanced use of SpringBoot configuration files. After reading this article, what can you guys gain?

Introduction of annotation @ConfigurationProperties
Use of loose binding and data validation
Understanding of data type conversion (note that)
Without further ado, let's start the study of this chapter.

2. 【SpringBoot- the use of advanced configuration】@ConfigurationProperties


The first thing I will introduce to you is the use of the annotation @ConfigurationProperties, which is used to bind properties to beans. Developers can add several properties in the object format in the yml configuration file. Here is an example:

@Component
@Data
@ConfigurationProperties(prefix = "servers")
public class ServerConfig {
private String ipAddress;
private int port;
private long timeout;
}

This entity class pays attention to providing the setter method corresponding to the attribute

servers:
ipAddress: 192.168.0.2
port: 1111
timeout: -1

Use the @ConfigurationProperties annotation to associate the property values in the configuration with the entity class. Next, write a test code to see if the result is correct:

@SpringBootTest
class Springboot05ConfigurationApplicationTests {
@Autowired
private ServerConfig serverConfig;
@Test
void test01() {
System.out.println(serverConfig);
}
}

The result is exactly right:

What I just talked about is to use this form to load attribute values for custom beans. What if it is a third-party bean? Is it possible to load attribute values in this form?

Why ask this question? The reason is that the current @ConfigurationProperties annotation is written above the class definition, and the bean source code developed by the third party is not written by us, and it is impossible for us to add the @ConfigurationProperties annotation to the source code. How to solve this problem? ?

First define a third-party bean using the @Bean annotation

@Bean
public DruidDataSource datasource(){
DruidDataSource ds = new DruidDataSource();
return ds;
}

Then define the properties to be bound in yml, note that the datasource is all lowercase at this time

datasource:
driverClassName: com.mysql.cj.jdbc.Driver

Finally, use the @ConfigurationProperties annotation to bind properties for third-party beans. Note that the prefix is all lowercase datasource

@Bean
@ConfigurationProperties(prefix = "datasource")
public DruidDataSource datasource(){
DruidDataSource ds = new DruidDataSource();
return ds;
}

The operation method is the same as before, the difference is that the @ConfigurationProperties annotation can be added not only to the class, but also to the method. Adding it to the class is the object binding property of the current class managed by the spring container, and adding it to the method is to The return value object binding properties of the current method managed by the spring container are essentially the same.

But at present, we define beans either through class annotation definitions or @Bean definitions. Using the @ConfigurationProperties annotation can bind properties for beans. In practice, which beans are bound to properties through the @ConfigurationProperties annotation? Because this annotation can be written not only on the class, but also on the method, it is more troublesome to find.

In order to solve this problem, spring provides us with a new annotation, which specifically marks which beans are bound to properties using the @ConfigurationProperties annotation. This annotation is called @EnableConfigurationProperties

First, enable the @EnableConfigurationProperties annotation on the configuration class, and mark the class that will use the @ConfigurationProperties annotation to bind properties

@SpringBootApplication
@EnableConfigurationProperties(ServerConfig.class)
public class Springboot13ConfigurationApplication {
}

Then use @ConfigurationProperties directly on the corresponding class for property binding

@Data
@ConfigurationProperties(prefix = "servers")
public class ServerConfig {
private String ipAddress;
private int port;
private long timeout;
}

Maybe the friends will say, it makes no difference? Carefully observe, the ServerConfig class that now binds the property does not declare the @Component annotation. When using the @EnableConfigurationProperties annotation, spring will define its annotated class as a bean by default, so there is no need to declare the @Component annotation again.

Note that if you use the @ConfigurationProperties annotation, the following prompt will appear:

Just need to add a coordinate and it will be solved


org.springframework.boot
spring-boot-configuration-processor


【SpringBoot- the use of advanced configuration】Summarize

Use @ConfigurationProperties to bind properties for third-party beans declared with @Bean
When using @EnableConfigurationProperties to declare a bean for property binding, there is no need to use the @Component annotation to declare the bean again

3. loose binding
When performing attribute binding, in order to carry out standard naming, we will write the attribute name strictly according to the camel case nomenclature, and change the datasource to dataSource in the yml configuration file, as follows:

dataSource:
driverClassName: com.mysql.cj.jdbc.Driver

At this point, the program can run normally, and then the prefix datasource in the code is modified to dataSource, as follows:

@Bean
@ConfigurationProperties(prefix = "dataSource")
public DruidDataSource datasource(){
DruidDataSource ds = new DruidDataSource();
return ds;
}

At this point, the code will report an error, why does this problem occur? This is to talk about an important knowledge point when springboot performs attribute binding - loose binding

What is loose binding? It is a manifestation of the humanized design of springboot when programming, that is, the naming format in the configuration file and the naming format of the variable name can be maximized in format compatibility

ipAddress property name in ServerConfig

@Component
@Data
@ConfigurationProperties(prefix = "servers")
public class ServerConfig {
private String ipAddress;
}

It is fully compatible with the following configuration property name rules:

servers:
ipAddress: 192.168.0.2 # CamelCase
ip_address: 192.168.0.2 # underscore mode
ip-address: 192.168.0.2 # kebab mode
IP_ADDRESS: 192.168.0.2 # constant mode

The above four modes can finally match the attribute name ipAddress. Why is this so? The reason is that when matching, the name in the configuration should remove the underscore and underscore, and then match the property name in the java code with the case-ignoring case. The line is a word ipaddress after ignoring case, and the property name in java code is also ipaddress after ignoring case, so that equal value matching can be performed, which is why these four formats can be successfully matched. However, springboot officially recommends the use of kebab mode, which is the underline mode.

Note: The above rules are only valid for property binding of @ConfigurationProperties annotation in springboot, and invalid for property mapping of @Value annotation.

Summarize

@ConfigurationProperties supports property name loose binding when binding properties. This looseness is reflected in the naming rules of property names
@Value annotation does not support loose binding rules
It is recommended to use the kebab naming rules for the binding prefix name, that is, use a dash as the separator
4. Binding of common measurement units
In the previous configuration, we wrote the following configuration values. The third item, timeout, describes the server operation timeout. The current value is -1, which means never timeout.

servers:
ipAddress: 192.168.0.2
port: 1111
timeout: -1

However, everyone's understanding of this value will be different. For example, when an online server completes a master-slave backup, configure a timeout of 240. If the unit of 240 is seconds, the timeout period is 4 minutes, and if the unit is minutes, the timeout period is 4 hours. In the face of a master-slave backup of an online server, set 4 minutes and so on. So the question is, how to solve this misunderstanding?

Springboot takes full advantage of the new data types provided in JDK8 to represent units of measurement to solve this problem. Two new classes in JDK8 are added to the ServerConfig class, namely Duration and DataSize

@Component
@Data
@ConfigurationProperties(prefix = "servers")
public class ServerConfig {
@DurationUnit(ChronoUnit.HOURS)
private Duration serverTimeOut;
@DataSizeUnit(DataUnit.MEGABYTES)
private DataSize dataSize;
}

Duration: Indicates the time interval. The time unit can be described by the @DurationUnit annotation. For example, the unit described in the above example is hours (ChronoUnit.HOURS)
DataSize: Represents storage space. The storage space unit can be described by the @DataSizeUnit annotation. For example, the unit described in the above example is MB (DataUnit.MEGABYTES)
The use of the above two units can effectively avoid the problem of information asymmetry caused by out-of-sync communication or incomplete documents, which fundamentally solves the problem and avoids misreading.

The common units of Druation are as follows:


The common units of DataSize are as follows:


5. Calibration
Since the data type in the model class cannot be sensed, there will be a type mismatch problem. For example, the int type is required in the code, and an illegal value is given in the configuration, such as writing an "a", this data must not be bound effectively. , also throws an error. SpringBoot provides a powerful data verification function, which can effectively avoid the occurrence of such problems.

First open the verification framework and introduce the required dependencies



javax.validation
validation-api



org.hibernate.validator
hibernate-validator


Then use the annotation @Validated on the class that needs to enable the verification function to enable the verification function

@Component
@Data
@ConfigurationProperties(prefix = "servers")
//Enable property injection verification for the current bean
@Validated
public class ServerConfig {
}

Finally, set the validation rules for specific fields

@Component
@Data
@ConfigurationProperties(prefix = "servers")
//Enable property injection verification for the current bean
@Validated
public class ServerConfig {
//set specific rules
@Max(value = 666, message = "The maximum value cannot exceed 666")
@Min(value = 28, message = "The minimum value cannot be lower than 28")
private int port;
}

Summarize

There are 3 steps to enable the Bean attribute verification function:

Import JSR303 and Hibernate to verify frame coordinates,
Use the @Validated annotation to enable validation
Use specific validation rules to standardize data validation formats

Six, data type conversion
If the configuration file we cooperate with the database is like this, the values of the username and password are correct. Note that I am talking about the values here.

spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/ssm_db?serverTimezone=UTC
username: root
password: 0123

The developer's birthday is January 23, so the password is 0123, which is where the problem lies.

Remember what my configuration file in SpringBoot was? How to use it? Knowledge points in this basic article?

The problem is in the support base, 0123 is a string "0123" in the eyes of developers, but in the eyes of springboot, this is a number, and it is an octal number. When the backend uses the String type to receive data, if an integer value is configured in the configuration file, he first installs the integer for processing, and then converts it into a string after reading. Coincidentally, 0123 hits the octal format, so it ends up being the result of the decimal number 83.

be careful:

String standard writing plus quotation marks to form a habit
Pay more attention to the data starting with 0

7. Summary
Le Mo Lexi is a new acquaintance, and I am very glad that you can keep reading this article. If it is helpful to you, you can give the blogger a like~~ Come on and make progress together!


Copyright statement: The content of this article is contributed by Alibaba Cloud real-name registered users. The copyright belongs to the original author. The Alibaba Cloud developer community does not own the copyright and does not assume the corresponding legal responsibility. For specific rules, please refer to the " Alibaba Cloud Developer Community User Service Agreement " and " Alibaba Cloud Developer Community Intellectual Property Protection Guidelines ". If you find any content suspected of plagiarism in this community, fill out the infringement complaint form to report it. Once verified, this community will delete the allegedly infringing content immediately.

Related Articles

Explore More Special Offers

  1. Short Message Service(SMS) & Mail Service

    50,000 email package starts as low as USD 1.99, 120 short messages start at only USD 1.00