Previous articles review: The first Spring Boot, greet the world!!
preface
How to use Spring Boot to greet the world, presumably we all have a certain grasp of Spring Boot. If you haven’t seen it yet, you can click on the previous review link above to learn more.
Spring Boot configuration file Spring Boot configuration file When it comes to Spring Boot configuration files, it’s a love-hate relationship. , how a cool word get. Of course, at the same time, but also ushered in a lot of trouble, such as: we for Spring Boot is how to achieve only need to modify the configuration file can achieve a certain effect is also full of curiosity, this requires us to read Spring Boot source code – automatic assembly principle,. Here I will not repeat, after I will be specifically for the source analysis of the article, please look forward to it!!
Don't talk too much, just do it!!
Format of the Spring Boot configuration file
Spring Boot provides two common configuration file formats: Properties and YML. Compared to Properties, YML is younger and more hierarchical. The YML format is highly recommended
Spring Boot configuration file priority loading mechanism
The Spring Boot project will scan application.properties or application.yml in the following location as the default configuration file.
file:./config/
file:./config/*/
file:./
classpath:/config/
classpath:/
All files are loaded from top to bottom in priority order. The content with higher priority overwrites the content with lower priority to form a complementary configuration
Tear the source code by hand
We can go from ConfigFileApplicationListener found in this class, including DEFAULT_SEARCH_LOCATIONS attribute is set to the directory to load:
public class ConfigFileApplicationListener implements EnvironmentPostProcessor.SmartApplicationListener.Ordered {
private static final String DEFAULT_SEARCH_LOCATIONS = "classpath:/,classpath:/config/,file:./,file:./config/*/,file:./config/";
private static final String DEFAULT_NAMES = "application";
private static final Set<String> NO_SEARCH_NAMES = Collections.singleton((Object)null);
private static final Bindable<String[]> STRING_ARRAY = Bindable.of(String[].class);
private static final Bindable<List<String>> STRING_LIST = Bindable.listOf(String.class);
private static final Set<String> LOAD_FILTERED_PROPERTY;
public static final String ACTIVE_PROFILES_PROPERTY = "spring.profiles.active";
public static final String INCLUDE_PROFILES_PROPERTY = "spring.profiles.include";
public static final String CONFIG_NAME_PROPERTY = "spring.config.name";
public static final String CONFIG_LOCATION_PROPERTY = "spring.config.location";
public static final String CONFIG_ADDITIONAL_LOCATION_PROPERTY = "spring.config.additional-location"; . . . }Copy the code
Then in method of getSearchLocations ConfigFileApplicationListener classes to comma parsed into the Set, including the inner class Loader is responsible for this configuration file loading process, including the load profile specified environment configuration, Load as application+ ‘-‘ +name concatenation.
Load method of the inner class Loader
private void load(ConfigFileApplicationListener.Profile profile, ConfigFileApplicationListener.DocumentFilterFactory filterFactory, ConfigFileApplicationListener.DocumentConsumer consumer) {
this.getSearchLocations().forEach((location) -> {
String nonOptionalLocation = ConfigDataLocation.of(location).getValue();
boolean isDirectory = location.endsWith("/");
Set<String> names = isDirectory ? this.getSearchNames() : ConfigFileApplicationListener.NO_SEARCH_NAMES;
names.forEach((name) -> {
this.load(nonOptionalLocation, name, profile, filterFactory, consumer);
});
});
}
Copy the code
GetSearchLocations () method
private Set<String> getSearchLocations(a) {
Set<String> locations = this.getSearchLocations("spring.config.additional-location");
if (this.environment.containsProperty("spring.config.location")) {
locations.addAll(this.getSearchLocations("spring.config.location"));
} else {
locations.addAll(this.asResolvedSet(ConfigFileApplicationListener.this.searchLocations, "classpath:/,classpath:/config/,file:./,file:./config/*/,file:./config/"));
}
return locations;
}
Copy the code
asResolvedSet()
private Set<String> asResolvedSet(String value, String fallback) { List<String> list = Arrays.asList(StringUtils.trimArrayElements(StringUtils.commaDelimitedListToStringArray(value ! =null ? this.environment.resolvePlaceholders(value) : fallback)));
Collections.reverse(list);
return new LinkedHashSet(list);
}
Copy the code
In fact, you can see the source code given in the configuration file order with the load order is the opposite. Instead, the collections.reverse (list) method was used
- We can also specify the configuration
spring.config.location
To change the default configuration, usually after the project has been packaged, we can use the following commandLoad the external configuration
.
Java jar - XXX - 0.0.1 - the SNAPSHOT. Jar -- spring. Config. Location = F: / application. YmlCopy the code
- It can also pass
Cli parameters are configured
All configurations can be specified on the command line. Multiple configurations are separated by Spaces. — Configuration item = value
Jar --server.port=8888 --server.context-path=/ QLHCopy the code
The following configuration files are listed in order of priority from highest to lowest:
- Command line arguments
- JNDI properties from Java :comp/env
- Java System Properties(system.getProperties ())
- Operating system environment variables
- RandomValuePropertySource configuration of the random. * attribute values
Note: Search from the jar package outside the JAR package inside the JAR package, load the file with profile first, and then load the file without profile
- Application -{profile}. Properties or application.yml(with spring.profile) outside the JAR package with the -file
- Application -{profile}.properties or application. Yml (with spring.profile) configuration file inside the JAR package
- Properties or application.yml(without spring.profile) configuration file outside the JAR package
- Properties or application.yml(without spring.profile) configuration file inside the JAR package
- @Configuration Annotation @propertysource on the class
- Through SpringApplication. SetDefaultProperties specify default properties
Properties, YAML configures the priority loading mechanism
Spring Boot uses a configuration file named Application as the default global configuration file. Configuration files ending with the properties suffix or yamL file configuration ending with the yML /yaml suffix are supported.
This section uses setting an application port as an example to experience the Spring Boot configuration file for the first time
Properties suffix end (application.properties)
server.port=80
Copy the code
Yml/yaml end suffixes (application. Yml/application. Yaml)
server:
prot: 8088
Copy the code
Note: In the same directory, choose Properties configuration file priority > YML/YAML configuration file priority. Therefore, the configuration can be overwritten with the properties script when the JAR package starts.
The yamL/YML configuration file is written with Spaces after colons
Properties configuration file
The syntax is key=value
Value type:
Numbers, strings, booleans, dates
person.name=tinygrey
person.age=18
person.status=true
person.birthday=2020/11/23
Copy the code
Object, the Map
Phone = iPhone 12 Person.assets. Car = Jaguar # object person.dog.name= milk dog person.dog.age=3Copy the code
An array of
Person.hobby [0]= play basketball Person.Hobby [1]= sleep Person.Hobby [2]= play gamesCopy the code
Yml/YAML configuration file
Control the hierarchy by indentation of Spaces. The number of Spaces is not important, as long as the left space is aligned, it is considered the same level. Note that you cannot use tabs instead of Spaces. And case sensitive. Support literal value, object, array three kinds of data structure, also support composite structure.
Literals: string, Boolean, value, date. Strings are not quoted by default. Single quotes escape special characters. Date format YYYY /MM/ DD HH: MM: SS Object: Consists of key and value pairs, such as key (space)value. Spaces after colons are mandatory. Each pair of keys and values occupies a line with the same degree of indentation. You can also use inline notation: {k1: v1,…. Kn: vn} array: consists of data of the form -(space)value. Each group of data occupies one line with the same degree of indentation. You can also use the inline notation: [1,2…n] compound structure: any combination of the above three data structures
Value type:
Numbers, strings, booleans, dates
person:
name: tinygrey
age: 18
status: true
birthday: 2002/04/02
Copy the code
Object, the Map
Person: #Map Assets: Phone: iPhone 12 Car: Jaguar # object Dog: name: Milk dog Age: 3Copy the code
Person: #Map assets: {phone: iPhone 12,car: Jaguar} # object dog: {name: milk dog,age: 3}Copy the code
An array of
Person: Hobby: - Play basketball - sleep - play games - studyCopy the code
Person: hobby: [Play basketball, sleep, play games, study]Copy the code
Note: YML is a new format with distinct hierarchies and is highly recommended.
Note the following: String can be unquoted. If double quotation marks are used, special characters are output. If single quotation marks are not used, special character array types are escaped. Yaml/YML controls hierarchy by the degree of space indentation. However, the TAB key cannot be used instead of the space, which is case-sensitive
All configuration files mentioned in this article refer to the entity class below
@Data
@AllArgsConstructor
@NoArgsConstructor
@Slf4j
@Component
@PropertySource(value = "classpath:config/custom-profile.properties", encoding = "utf-8")
@ConfigurationProperties(prefix = "person")
public class Person {
@Value("${person.name}")
private String name;
@Value("${person.age}")
private int age;
private boolean status;
@Value("${person.birthday}")
private Date birthday;
private List<String> hobby;
private Map<String, Object> assets;
private Dog dog;
}
@Data
@AllArgsConstructor
@NoArgsConstructor
@Slf4j
@Component
@PropertySource(value = "classpath:config/custom-profile.properties", encoding = "utf-8")
@ConfigurationProperties(prefix = "dog")
class Dog {
private String name;
private Integer age;
}
Copy the code
How do configuration files bind to entity classes
Spring Boot Everything is configured for values. Spring Boot provides several ways to value values. Let’s take a look.
ConfigurationProperties(prefix = “person”
Note: This annotation is used to value values from configuration files and supports complex data types, but does not support SPEL expressions.
Prefix attribute: Specifies the prefix to be configured. After all, there are many attributes in the configuration file with the same name, you must use a prefix to distinguish them. This annotation can be annotated on a class or a method, and you can see that it has two ways of getting values.
Labeled on the class
@Data
@AllArgsConstructor
@NoArgsConstructor
@Slf4j
@Component // Inject into the IOC container
@ConfigurationProperties(prefix = "person")// Read files from configuration files
public class Person {
@Value("${person.name}")
private String name;
@Value("${person.age}")
private int age;
@Value("${person.birthday}")
private Date birthday;
private List<String> hobby;
private Map<String, Object> assets;
private Dog dog;
}
Copy the code
Mark the method
/ * * *@BeanInject the returned result into the IOC container *@ConfigurationPropertiesThe value is * in the configuration file@return* /
@ConfigurationProperties(prefix = "person")
@Bean
public Person person(a){
return new Person();
}
Copy the code
In summary, the @ConfigurationProperties annotation makes it easy to bind configuration files to entity classes.
Has the following advantages:
- Injection properties support batch, specifying only one
The prefix prefix
Can be- Data types support complex data such as
The List, Map,
- Attribute name matching rule –
Loosely bound
, such asa-b
.a_b
.aB
.A_B
I can take values- Supports JAVA JSR303 data verification
Of concern: The @configurationProperties annotation only supports values from the default Configuration files of Spring Boot, i.e. Application. properties, Application. yml, application.yaml, So how do we value from a custom configuration file? Don’t worry, the solution is to add another annotation: @propertysource (value = “classpath:custom-profile.properties”). There is a description of the @propertysource annotation below. Please bear with me and look down.
Spring supports SPEL expressions and does not support complex data types, such as Map and List. You can refer to the code in the entity class above.
User-defined configuration files and values
Spring Boot will automatically load application. XXX upon startup. However, in order to avoid the oversize of the application. XXX configuration file, we need to customize the configuration file. This is where the @propertysource annotation comes in.
Annotate with @propertysource
Annotate @propertysource on the configuration class and specify your custom configuration file. Refer to the code below
@Data
@AllArgsConstructor
@NoArgsConstructor
@Slf4j
@Component
@PropertySource(value = {"classpath:config/custom-profile.properties"}, encoding = "utf-8")
@ConfigurationProperties(prefix = "person")
public class Person {
@Value("${person.name}")
private String name;
@Value("${person.age}")
private int age;
@Value("${person.birthday}")
private Date birthday;
private List<String> hobby;
private Map<String, Object> assets;
private Dog dog;
}
Copy the code
Configuration file
Person.name = tinyGrey person.age=18 person.birthday=2020/11/23 Person.Hobby [0]= play basketball Person.Hobby [1]= sleep Person.Hobby [2]= play games Hobby [3]= Learn Person.assets. Phone = iPhone 12 Person.assets. Car = Jaguar Person.dog. name= milk dog person.dog.age=3Copy the code
@propertysource Annotation property
Value: is an array that can specify multiple configuration files to be imported at the same time. Value is an array then the question arises: If multiple profiles are loaded at the same time, and different profiles have different values for the same property, which one will Spring recognize?
Create two configuration files, custom profile.yml and custom profile1.yml, as introduced below.
@PropertySource(value = {"classpath:config/custom-profile.yml","classpath:config/custom-profile1.yml"})
public class Person {... }Copy the code
We can test it by controlling variables, but I won’t go into the details here. Spring is loaded from left to right, and the last one overrides the first one.
Another note: @propertysource loads a configuration file of type xxx.properties by default and cannot load a configuration file in YML format. How to solve it? Let’s solve this problem
Load a customized YML configuration file
@ PropertySource annotation has an attribute factory, the default value is PropertySourceFactory. Class, this is used for loading the properties configuration file format, then we customize a configuration file to load YML format is not ok? In the code
/ * * *@PropertySourceOnly properties files can be loaded, but not yML or YAML. * /
public class YmlPropertySourceFactory extends DefaultPropertySourceFactory {
@Override
publicPropertySource<? > createPropertySource(String name, EncodedResource resource)throwsIOException { String sourceName = name ! =null ? name : resource.getResource().getFilename();
if(! resource.getResource().exists()) {assertsourceName ! =null;
return new PropertiesPropertySource(sourceName, new Properties());
} else if (Objects.requireNonNull(sourceName).endsWith(".yml") || sourceName.endsWith(".yaml")) {
Properties propertiesFromYaml = loadYamlProperties(resource);
return new PropertiesPropertySource(sourceName, propertiesFromYaml);
} else {
return super.createPropertySource(name, resource); }}private Properties loadYamlProperties(EncodedResource resource){
YamlPropertiesFactoryBean factory = new YamlPropertiesFactoryBean();
factory.setResources(resource.getResource());
factory.afterPropertiesSet();
returnfactory.getObject(); }}Copy the code
Once we have written the above code, all we need to do is add the factory property to the @propertysource annotation as YmlPropertySourceFactory:
@Data
@AllArgsConstructor
@NoArgsConstructor
@Slf4j
@Component
@PropertySource(value = {"classpath:config/custom-profile.yml"}, encoding = "utf-8", factory = YmlPropertySourceFactory.class)
@ConfigurationProperties(prefix = "person")
public class Person {
@Value("${person.name}")
private String name;
@Value("${person.age}")
private int age;
@Value("${person.birthday}")
private Date birthday;
private List<String> hobby;
private Map<String, Object> assets;
private Dog dog;
}
Copy the code
Configuration file:
Person: Name: QLH age: 22 Birthday: 2012/04/02 Hobby: -Play-learn Assets: Phone: iPhone Car: Ford Mustang Dog: Name: Age: 1Copy the code
@propertysource specifies to load a custom configuration file. By default, only properties can be loaded, but you can specify the Factory property to load a YML configuration file. Load multiple configurations simultaneously.
Test success
Write PropertiesController
@RestController
@RequestMapping("properties")
@Slf4j
public class PropertiesController {
final
Person person;
public PropertiesController(Person person) {
this.person = person;
}
@GetMapping("getProperties")
public Dict getProperties(a){
log.info(person.toString());
return Dict.create().set("person", person); }}Copy the code
Browser input: http://localhost:8081/springboot-properties/properties/getProperties validation results. If the displayed class information is displayed, the customized YML configuration file is successfully loaded.
Extend the functionality
SpringBoot also provides the @importResource annotation to load external configuration files, although @ImportResource is typically used to load Spring’s XML configuration files
@ ImportResource use
Spring Boot has a zero XML configuration, so by default Spring Boot does not actively recognize Spring’s XML configuration files in a project. To enable loading of XML configuration files, Spring Boot provides the @importResource annotation, which loads Spring’s XML configuration files, usually on the Boot class. Here is not to repeat, code reference below.
//value: The Spring XML configuration file.
@ImportResource(value = {"classpath:config/beans.xml"})
@SpringBootApplication
public class SpringbootPropertiesApplication {
public static void main(String[] args) { SpringApplication.run(SpringbootPropertiesApplication.class, args); }}Copy the code
Spring Boot Multi-environment configuration
What are the benefits of multi-environment configuration?? You can configure different parameters for different environments to facilitate deployment, improve efficiency, and reduce errors
Yml multi-environment configuration
Application. Yml Master configuration file
Server: port: 8081 servlet: context-path: /springboot-properties # Configure activation options spring: profiles: active: devCopy the code
Application-dev. yml Develop the configuration file
Spring: profiles: -devCopy the code
Application-prod. yml Production configuration file
Spring: Profiles: -propCopy the code
Application-test. yml Tests the configuration file
Spring: Profiles: -testCopy the code
Properties Multi-environment configuration
(1) Master profile: Configures activation options
spring.profiles.active=dev
Copy the code
(2) other configuration files: specify which environment belongs to (same as yML, but the expression is key=value, three configuration files are respectively: Application – dev. Properties, application – prod. Properties, application – test. The properties)
Comparison of YML multi-environment configuration and Properties multi-environment configuration
Yml Configure multiple environments: You can add multiple configuration files, but do not add them. Separate them (for example, the following code). (This method is not recommended because the configuration files are bloated.
server:
port: 8081
servlet:
context-path: /springboot-properties
spring:
profiles:
active: dev
---
spring:
profiles:
- test
---
spring:
profiles:
- prod
---
spring:
profiles:
- dev
Copy the code
Application-dev. Yml: this is the main configuration file, which contains some common configuration for the project. Application-dev. Application-prod. yml: stores the configuration of the production environment, such as the connection address and account password of the database. Application-test. yml: stores the parameters required by the test environment
Activate a specified profile
Activate with spring.profiles. Active
Either by using the multi-document block approach described above or by creating a new application-test.yml file, you can activate the specified profile by specifying spring.profiles.active=test in the configuration file.
Jar package run time using the command line activation
Java jar XXXX - 0.0.1 - the SNAPSHOT. Jar -- spring. Profiles. The active = testCopy the code
Activate using VM parameters
-Dspring.profiles.active=test
Copy the code
Activated in Java code
@SpringBootApplication
public class SpringbootPropertiesApplication {
public static void main(String[] args) {
System.setProperty("spring.profiles.active"."test"); SpringApplication.run(SpringbootPropertiesApplication.class, args); }}Copy the code
conclusion
Thanks for reading this article. I wish you all an early day of unparalleled wealth and freedom. Writing is not easy, must point praise, comment, collection oh, thank thank thank thank!!
Any questions can be searched in wechat public number: Madison Longshao for consultation or wechat scan the following TWO-DIMENSIONAL code for consultation