What is Spring Boot
Spring applications have been known as “configuration hell” for a long time because of the dizzying and error-prone XML and annotation configurations that require a lot of configuration. To simplify the process of building and developing Spring applications, the Pivotal team offers a new open source framework based on Spring, Spring Boot.
Spring Boot has all the excellent features of Spring. Spring Boot can do all the things Spring can do, and it is easier to use, more functional, more stable and robust performance. With the popularity of microservices technology in recent years, Spring Boot has become a hot technology.
Spring characteristics of the Boot
- Spring projects that run independently: Spring Boot can be run independently as a JAR package. Spring Boot projects can be run independently by using the command”
Java - jar xx. The jar
“Can run. - Embedded Servlet containers: Spring Boot uses an embedded Servlet container (such as Tomcat, Jetty, or Undertow) without the need for a WAR package.
- Starter simplified Maven configuration: Spring Boot provides a series of “Starter” project object models (POMS) to simplify Maven configuration.
- Lots of auto-configuration: Spring Boot provides a lot of default auto-configuration to simplify project development, and developers also modify the default configuration through configuration files.
- Built-in application monitoring: Spring Boot provides monitoring of running projects.
- No code generation and XML configuration: Spring Boot does all of Spring’s configuration without any XML configuration.
Spring Boot target
The primary goal of Spring Boot is to reduce development, unit testing, and integration testing time.
- Provide purposeful development methods;
- Avoid defining more annotation configurations;
- Avoid writing a lot of import statements;
- Avoid XML configuration;
Spring Boot Starter
Spring Boot extracts all kinds of scenarios in daily enterprise application development and makes them into one starter (starter). The starter integrates various possible dependencies in this scenario. Users only need to introduce the starter dependency in Maven. SpringBoot automatically scans for the information to load and launches the corresponding default configuration. Starter provides a lot of automatic configuration, freeing users from dealing with dependencies and configurations. All of these starters follow the convention default configuration and allow the user to adjust these configurations, following the “convention over configuration” principle.
spring-boot-starter-parent
Spring-boot-starter -parent is the parent dependency of all Spring Boot projects. It is called the version arbitration center of Spring Boot. It can centrally manage some common dependencies in a project.
Spring Boot projects can get some reasonable defaults by inheriting spring-boot-starter-parent, which provides the following features:
- Default JDK version (Java 8);
- Default character set (UTF-8);
- Dependency management function;
- Resource filtering;
- Default plug-in configuration;
- Identify configuration files of type application.properties and application.yml;
Spring Boot Configures the priority
The following are common Spring Boot configurations and their loading order (in descending order of priority) :
- Command line arguments;
- JNDI properties from Java :comp/env;
- Java System properties (system.getProperties ());
- Operating system environment variables;
- RandomValuePropertySource configuration of the random. * attribute value;
- Configuration files (YAML files, Properties files);
- @Configuration Annotates the Configuration file specified by @propertysource on the class;
- Through SpringApplication. SetDefaultProperties specified default attributes;
All the preceding configurations are loaded. If the same configuration exists, the configuration with a higher priority overwrites the configuration with a lower priority. If different configurations exist, the configurations with high and low priorities take effect together to form complementary configurations.
Spring Boot automatic configuration principle
Once a Spring Boot project is created, it runs smoothly without any configuration, thanks to Spring Boot’s automated configuration.
There are a large number of configuration attributes in Spring Boot. Only by understanding the principle of Spring Boot automatic configuration, can we configure Spirng Boot more easily and skillfully.
Spring mechanism of Factories
The automatic configuration of Spring Boot is based on the Spring Factories mechanism.
The Spring Factories mechanism is a service discovery mechanism in Spring Boot. The Spring Boot Starter automatically scans meta-INF/Spring. factories files in the classpath of all Jar packages, reads them, and instantiates them.
Spring.factories files are essentially similar to properties files in that they contain one or more sets of key-value pairs (key=vlaue), where key is the fully qualified name of the interface; Value indicates the fully qualified name of the interface implementation class. An interface can be configured with multiple implementation classes. Use commas (,) to separate different implementation classes, for example:
org.springframework.boot.autoconfigure.AutoConfigurationImportFilter=\
org.springframework.boot.autoconfigure.condition.OnBeanCondition,\
org.springframework.boot.autoconfigure.condition.OnClassCondition,\
org.springframework.boot.autoconfigure.condition.OnWebApplicationCondition
Copy the code
Note: The contents of the file are too long. If you need to wrap the file manually for easy reading, you can use “\” to prevent the contents from being lost.
Spring Factories implementation principle
The SpringFactoriesLoader class is defined in the spring-core package. This class scans the META-INF/ Spring. factories files in the classpath of all Jar packages and gets the configuration for the specified interface. Two external methods are defined in the SpringFactoriesLoader class, as shown in the following table.
The return value | methods | describe |
---|---|---|
List | loadFactories(Class factoryType, @Nullable ClassLoader classLoader) | Static method; Get an instance of its implementation class according to the interface; This method returns a list of implementation class objects. |
List | loadFactoryNames(Class<? > factoryType, @Nullable ClassLoader classLoader) | Public static methods; Gets the name of its implementation class based on the interface; This method returns a list of class names that implement the class. |
The key to both methods is to get the Spring. factories file from the specified ClassLoader and parse it to get the list of class names:
The loadFactories() method gets the implementation object of the specified interface as follows:
public static <T> List<T> loadFactories(Class<T> factoryType, @Nullable ClassLoader classLoader) {
Assert.notNull(factoryType, "'factoryType' must not be null");
ClassLoader classLoaderToUse = classLoader;
if (classLoader == null) {
classLoaderToUse = SpringFactoriesLoader.class.getClassLoader();
}
Call loadFactoryNames to get the implementation class of the interface
List<String> factoryImplementationNames = loadFactoryNames(factoryType, classLoaderToUse);
if (logger.isTraceEnabled()) {
logger.trace("Loaded [" + factoryType.getName() + "] names: " + factoryImplementationNames);
}
// Iterate through the factoryNames array to create an object that implements the class
List<T> result = new ArrayList(factoryImplementationNames.size());
Iterator var5 = factoryImplementationNames.iterator();
/ / sorting
while(var5.hasNext()) {
String factoryImplementationName = (String)var5.next();
result.add(instantiateFactory(factoryImplementationName, factoryType, classLoaderToUse));
}
AnnotationAwareOrderComparator.sort(result);
return result;
}
Copy the code
The loadFactoryNames() method gets a collection of implementation class names based on the interface as follows:
public static List<String> loadFactoryNames(Class<? > factoryType,@Nullable ClassLoader classLoader) {
ClassLoader classLoaderToUse = classLoader;
if (classLoader == null) {
classLoaderToUse = SpringFactoriesLoader.class.getClassLoader();
}
String factoryTypeName = factoryType.getName();
// Get the auto-configuration class
return (List)loadSpringFactories(classLoaderToUse).getOrDefault(factoryTypeName,
Collections.emptyList());
}
Copy the code
The loadSpringFactories() method reads the meta-INF/Spring.Factories () configuration from the classpath of all Jar packages in the project and returns it as a collection of maps.
private static Map<String, List<String>> loadSpringFactories(ClassLoader classLoader) {
Map<String, List<String>> result = (Map)cache.get(classLoader);
if(result ! =null) {
return result;
} else {
HashMap result = new HashMap();
try {
// Scan meta-INF /spring.factories in the classpath of all Jar packages
Enumeration urls = classLoader.getResources("META-INF/spring.factories");
while(urls.hasMoreElements()) {
URL url = (URL)urls.nextElement();
UrlResource resource = new UrlResource(url);
// Wrap the contents of the scanned meta-INF /spring.factories file as properties objects
Properties properties = PropertiesLoaderUtils.loadProperties(resource);
Iterator var6 = properties.entrySet().iterator();
while(var6.hasNext()) { Map.Entry<? ,? > entry = (Map.Entry)var6.next();// Extract the key value from the properties object
String factoryTypeName = ((String)entry.getKey()).trim();
// Extract the value of the proper object (the fully qualified names of multiple classes are comma-concatenated strings)
// Use the comma delimiter to convert to an array in which each element is the fully qualified name of the configuration class
String[] factoryImplementationNames = StringUtils.commaDelimitedListToStringArray((String)entry.getValue());
String[] var10 = factoryImplementationNames;
int var11 = factoryImplementationNames.length;
// Iterate through the configuration class array and convert the array to a list collection
for(int var12 = 0; var12 < var11; ++var12) {
String factoryImplementationName = var10[var12];
((List)result.computeIfAbsent(factoryTypeName, (key) -> {
return newArrayList(); })).add(factoryImplementationName.trim()); }}}// Store the key of the propertise object into a Map named result by mapping it to a List of configuration classes
result.replaceAll((factoryType, implementations) -> {
return (List)implementations.stream().distinct().collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList));
});
cache.put(classLoader, result);
/ / return the result
return result;
} catch (IOException var14) {
throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var14); }}}Copy the code
Automatic configuration loading
Spring Boot automatic configuration is also based on Spring Factories, < < spring-boot-autoconfigure-xxx.jar > < < META-INF/spring.factories >
# Auto Configure org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\ org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\ org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\ org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,\ org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,\ org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration,\ org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration,\ org.springframework.boot.autoconfigure.context.LifecycleAutoConfiguration,\ org.springframework.boot.autoconfigure.context.MessageSourceAutoConfiguration,\ org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration,\ org.springframework.boot.autoconfigure.couchbase.CouchbaseAutoConfiguration,\ org.springframework.boot.autoconfigure.dao.PersistenceExceptionTranslationAutoConfiguration,\ org.springframework.boot.autoconfigure.data.cassandra.CassandraDataAutoConfiguration,\ org.springframework.boot.autoconfigure.data.cassandra.CassandraReactiveDataAutoConfiguration,\ org.springframework.boot.autoconfigure.data.cassandra.CassandraReactiveRepositoriesAutoConfiguration,\ org.springframework.boot.autoconfigure.data.cassandra.CassandraRepositoriesAutoConfiguration,\ org.springframework.boot.autoconfigure.data.couchbase.CouchbaseDataAutoConfiguration,\ org.springframework.boot.autoconfigure.data.couchbase.CouchbaseReactiveDataAutoConfiguration,\ org.springframework.boot.autoconfigure.data.couchbase.CouchbaseReactiveRepositoriesAutoConfiguration,\ org.springframework.boot.autoconfigure.data.couchbase.CouchbaseRepositoriesAutoConfiguration,\ org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchDataAutoConfiguration,\ org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchRepositoriesAutoConfiguration,\ org.springframework.boot.autoconfigure.data.elasticsearch.ReactiveElasticsearchRepositoriesAutoConfiguration,\ org.springframework.boot.autoconfigure.data.elasticsearch.ReactiveElasticsearchRestClientAutoConfiguration,\ ... .Copy the code
In the preceding configuration, the value consists of multiple xxxAutoConfiguration (separated by commas). Each xxxAutoConfiguration is an automatic configuration class. When Spring Boot is started, the xxxAutoConfiguration is instantiated and added to the container as components using the Spring-Factories mechanism to enable automatic Spring Boot configuration.
@ SpringBootApplication annotations
SpringBoot projects use a @SpringBootApplication annotation on the main launcher class. This annotation is one of the most important annotations in SpringBoot and is key to SpringBoot’s automatic configuration.
@SpringBootApplication is a composite meta-annotation that contains two main annotations: @SpringBootConfiguration and @EnableAutoConfiguration, where the @EnableAutoConfiguration annotation is the core of automatic SpringBoot configuration.
@ EnableAutoConfiguration annotations
The @enableAutoConfiguration annotation is used to enable the automatic configuration of Spring Boot. It USES the Spring framework provides @ Import annotations by AutoConfigurationImportSelector class (selectors) for container Import automatic configuration module.
AutoConfigurationImportSelector class
AutoConfigurationImportSelector class implements the DeferredImportSelector interface, AutoConfigurationGroup AutoConfigurationImportSelector also contains a static inner class, It implements the internal interface Group of the DeferredImportSelector interface (new in Spring 5).
AutoConfigurationImportSelector classes contained in the three methods, the following table.
The return value | Method statement | describe | Inner class method | The inner class |
---|---|---|---|---|
Class<? extends Group> | getImportGroup() | This method takes the class that implements the Group interface and instantiates it | no | |
void | process(AnnotationMetadata annotationMetadata, DeferredImportSelector deferredImportSelector) | This method is used to introduce automatically configured collections | is | AutoConfigurationGroup |
可迭代 | selectImports() | Iterate through the collection of auto-configuration classes (a collection of types of Entry) and parse the configuration classes in the collection one by one | is | AutoConfigurationGroup |
Each method in the AutoConfigurationImportSelector execution sequence is as follows:
GetImportGroup () method
AutoConfigurationImportSelector class getImportGroup () method is mainly used to obtain implements DeferredImportSelector. The Group, the class of the interface, the code is as follows:
public Class<? extends Group> getImportGroup() {
/ / get realized DeferredImportSelector Gorup interface AutoConfigurationImportSelector. AutoConfigurationGroup class
return AutoConfigurationImportSelector.AutoConfigurationGroup.class;
}
Copy the code
The process () method
Core method is the process of the static inner class AutoConfigurationGroup (), the method by calling getAutoConfigurationEntry () method reads the spring. The factories the contents of the file, Get a collection of auto-configuration classes as follows:
public void process(AnnotationMetadata annotationMetadata, DeferredImportSelector deferredImportSelector) {
Assert.state(deferredImportSelector instanceof AutoConfigurationImportSelector, () -> {
return String.format("Only %s implementations are supported, got %s", AutoConfigurationImportSelector.class.getSimpleName(), deferredImportSelector.getClass().getName());
});
// Get the EnableAutoConfiguration in meta-INF/Spring. factories and filter it out
//AutoConfigurationEntry contains classes that need to be introduced and classes that need to be excluded. Finally, only the configuration classes that need to be configured are returned
AutoConfigurationImportSelector.AutoConfigurationEntry autoConfigurationEntry = ((AutoConfigurationImportSelector)deferredImportSelector).getAutoConfigurationEntry(annotationMetadata);
// Add to cache, of type List
this.autoConfigurationEntries.add(autoConfigurationEntry);
Iterator var4 = autoConfigurationEntry.getConfigurations().iterator();
while(var4.hasNext()) {
String importClassName = (String)var4.next();
// Add cache, Map
type
,>
this.entries.putIfAbsent(importClassName, annotationMetadata); }}Copy the code
GetAutoConfigurationEntry () method by calling getCandidateConfigurations () method to get automatic configuration fully qualified name of a class, and after exclusion, filtering and other processing, the cache to the member variables, specific code is as follows:
protected AutoConfigurationImportSelector.AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
if (!this.isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
} else {
// Get property Settings in the annotation metadata
AnnotationAttributes attributes = this.getAttributes(annotationMetadata);
// Get the auto-configuration class
List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
// Delete duplicate configuration classes from list
configurations = this.removeDuplicates(configurations);
// Get the configuration class to float out
Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);
// Check if there are any excluded configuration classes
this.checkExcludedClasses(configurations, exclusions);
// Delete the excluded configuration classes
configurations.removeAll(exclusions);
// Get filter, filter configuration class
configurations = this.getConfigurationClassFilter().filter(configurations);
// Start automatic configuration import events
this.fireAutoConfigurationImportEvents(configurations, exclusions);
return newAutoConfigurationImportSelector.AutoConfigurationEntry(configurations, exclusions); }}Copy the code
In getCandidateConfigurations () method, according to the Spring mechanism of Factories call SpringFactoriesLoader loadFactoryNames () method, According to EnableAutoConfiguration. Class (automatic configuration interface) to obtain the implementation class (automatic configuration class) the class name of the collection of the diagram below.
SelectImports () method
. All of the above methods, after the completion of execution AutoConfigurationImportSelector AutoConfigurationGroup# selectImports () will be the process () method after processing of automatic configuration class, filtering, elimination, Finally, add all the auto-configuration classes to the container as follows:
public Iterable<DeferredImportSelector.Group.Entry> selectImports() {
if (this.autoConfigurationEntries.isEmpty()) {
return Collections.emptyList();
} else {
// Get all configuration classes that need to be excluded
Set<String> allExclusions = (Set)this.autoConfigurationEntries.stream(). map(AutoConfigurationImportSelector.AutoConfigurationEntry::getExclusions).flatMap(Collection::stream).collect(Collector s.toSet());// Get all configuration classes that have been automated configuration filters
Set<String> processedConfigurations = (Set)this.autoConfigurationEntries.stream().map(AutoConfigurationImportSelector.
AutoConfigurationEntry::getConfigurations).flatMap(Collection::stream).collect(Collectors.toCollection(LinkedHashSet::new));
// Exclude the classes that need to be excluded from the filtered configuration class
processedConfigurations.removeAll(allExclusions);
return (Iterable)this.sortAutoConfigurations(processedConfigurations,
this.getAutoConfigurationMetadata()).stream().map((importClassName) -> {
return new DeferredImportSelector.Group.Entry((AnnotationMetadata)this.entries.get(importClassName), importClassName); }).collect(Collectors.toList()); }}Copy the code
Automatic configuration takes effect and changes
All the auto-configuration classes (xxxAutoConfiguration) in the spring.factories file must be added to the container under certain conditions for the configuration to take effect. These restrictions are expressed in Spring Boot in the form of @Conditional derived annotations, as shown in the following table.
annotations | Effective condition |
---|---|
@ConditionalOnJava | This takes effect when the application uses the specified Java version |
@ConditionalOnBean | This takes effect when the specified Bean exists in the container |
@ConditionalOnMissingBean | Takes effect when the specified Bean does not exist in the container |
@ConditionalOnExpression | Takes effect when the specified SpEL expression is met |
@ConditionalOnClass | Takes effect when the specified class exists |
@ConditionalOnMissingClass | Takes effect when no specified class exists |
@ConditionalOnSingleCandidate | This takes effect when only one specified Bean exists in the container or the Bean is the preferred Bean |
@ConditionalOnProperty | The specified attribute takes effect when the specified value exists in the system |
@ConditionalOnResource | This parameter takes effect when the specified resource file exists in the classpath |
@ConditionalOnWebApplication | This parameter takes effect only when the current application is a Web application |
@ConditionalOnNotWebApplication | The current application is not a Web application |
Below we ServletWebServerFactoryAutoConfiguration, for example, to introduce the Spring Boot automatically configure is how to take effect.
ServletWebServerFactoryAutoConfiguration
@configuration (// this is a Configuration class, equivalent to an XML Configuration file, which can also add components to the container proxyBeanMethods = false)
@AutoConfigureOrder(-2147483648)
@ConditionalOnClass({ServletRequest.class})// Check whether the current project has a ServletRequest class
@ ConditionalOnWebApplication (/ / to determine whether the current application of web applications, if it is, the current effective configuration class type = the SERVLET)
@EnableConfigurationProperties({ServerProperties.class})
// enable the ConfigurationProperties function for the specified class; Bind the corresponding values in the configuration file to ServerProperties; Add ServerProperties to the IOC container
@Import({ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar.class, EmbeddedTomcat.class, EmbeddedJetty.class, EmbeddedUndertow.class})
public class ServletWebServerFactoryAutoConfiguration {
public ServletWebServerFactoryAutoConfiguration(a) {}@Bean // Add a component to the container whose values need to be retrieved from properties
public ServletWebServerFactoryCustomizer servletWebServerFactoryCustomizer(ServerProperties serverProperties, ObjectProvider<WebListenerRegistrar> webListenerRegistrars) {
return new ServletWebServerFactoryCustomizer(serverProperties, (List) webListenerRegistrars.orderedStream().collect(Collectors.toList()));
}
@Bean
@ConditionalOnClass( name = {"org.apache.catalina.startup.Tomcat"} )
public TomcatServletWebServerFactoryCustomizer tomcatServletWebServerFactoryCustomizer(ServerProperties serverProperties) {
return new TomcatServletWebServerFactoryCustomizer(serverProperties);
}
@Bean
@ConditionalOnMissingFilterBean({ForwardedHeaderFilter.class})
@ConditionalOnProperty( value = {"server.forward-headers-strategy"}, havingValue = "framework" )
public FilterRegistrationBean<ForwardedHeaderFilter> forwardedHeaderFilter(a) {
ForwardedHeaderFilter filter = new ForwardedHeaderFilter();
FilterRegistrationBean<ForwardedHeaderFilter> registration = new FilterRegistrationBean(filter, new ServletRegistrationBean[0]);
registration.setDispatcherTypes(DispatcherType.REQUEST, new DispatcherType[]{DispatcherType.ASYNC, DispatcherType.ERROR});
registration.setOrder(-2147483648);
returnregistration; }... . }Copy the code
This class uses the following annotations:
- @Configuration: Defines a Configuration class that can be used to replace XML Configuration files in Spring.
- @Bean: An @Configuration annotated class can contain one or more @Bean-annotated methods for building a Bean and adding them to the Spring container; This annotation is equivalent to the Spring configuration file, the method name is equivalent to the ID or name attribute of, and the method return value is equivalent to the class attribute.
In addition to the @Configuration and @bean annotations, this class uses five @conditional derived annotations:
- ConditionalOnClass({servletrequest.class}) : ConditionalOnClass({servletrequest.class}) : ConditionalOnClass({ServletRequest.
- @ ConditionalOnWebApplication (type = the SERVLET) : to determine whether the current application of Web applications, and if so, the current class configuration to take effect.
- @ ConditionalOnClass (name = {” org. Apache. Catalina. Startup. Tomcat “}) : to determine whether there is a Tomcat class, if there is the effective method.
- @ ConditionalOnMissingFilterBean ({ForwardedHeaderFilter. Class}) : whether the container has ForwardedHeaderFilter this filter, if does not exist, the method is effective.
- ConditionalOnProperty(value = {“server. Forward-headers -strategy”},havingValue = “framework”) : ConditionalOnProperty(value = {“server
server.forward-headers-strategy = framework
If no, the method takes effect.
ServerProperties
ServletWebServerFactoryAutoConfiguration class also USES a @ EnableConfigurationProperties annotations, through the annotations to import a ServerProperties class, Part of the source code is as follows.
@ConfigurationProperties( prefix = "server", ignoreUnknownFields = true )
public class ServerProperties {
private Integer port;
private InetAddress address;
@NestedConfigurationProperty
private final ErrorProperties error = new ErrorProperties();
private ServerProperties.ForwardHeadersStrategy forwardHeadersStrategy;
private String serverHeader;
private DataSize maxHttpHeaderSize = DataSize.ofKilobytes(8L);
private Shutdown shutdown;
@NestedConfigurationProperty
private Ssl ssl;
@NestedConfigurationProperty
private final Compression compression;
@NestedConfigurationProperty
private final Http2 http2;
private final ServerProperties.Servlet servlet;
private final ServerProperties.Tomcat tomcat;
private final ServerProperties.Jetty jetty;
private final ServerProperties.Netty netty;
private final ServerProperties.Undertow undertow;
public ServerProperties(a) {
this.shutdown = Shutdown.IMMEDIATE;
this.compression = new Compression();
this.http2 = new Http2();
this.servlet = new ServerProperties.Servlet();
this.tomcat = new ServerProperties.Tomcat();
this.jetty = new ServerProperties.Jetty();
this.netty = new ServerProperties.Netty();
this.undertow = newServerProperties.Undertow(); }... . }Copy the code
ServletWebServerFactoryAutoConfiguration USES a @ EnableConfigurationProperties annotations, The ServerProperties class uses an @ConfigurationProperties annotation. This is actually a common usage in the Spring Boot auto-configuration mechanism.
The @ConfigurationProperties annotation binds all of the properties of the class to the relevant configuration in the configuration file so that the configuration can be obtained or modified. However, the @ConfigurationProperties function is provided by the container. The class it annotates must be a component in the container, or the feature won’t work. It is the role of the @ EnableConfigurationProperties annotations specified class in the form of components into the IOC container, and open its @ ConfigurationProperties function. Therefore, @ ConfigurationProperties + @ EnableConfigurationProperties combination, can configure binding function for the XxxProperties class implements.