springboot basics - SpringBoot configuration

1 configuration file

●SpringBoot uses a global configuration file:

○application.yml

○application.properties

●Configuration files are placed in the src/main/resources directory or under the classpath/config.

●.yml is a file in YAML language, centered on data, and more suitable for configuration files than JSON and XML.

●The global configuration file can modify some default configuration values.

●YAML configuration example:

server:
  port: 8081

●XML configuration example:

<server>
    <port>8081</port>
</server>

●properties configuration example:

server.port=8081

2 YAML syntax

2.1 Basic syntax of YAML

● Use indentation to indicate hierarchical relationships.

● Tab keys are not allowed for indentation, only spaces are allowed.

●The number of spaces for indentation is not important, as long as elements of the same level are left-aligned.

●Case sensitive.

●Example:

server:
  port: 8081
  context-path: helloworld

2.2 Three data structures supported by YAML

●Object, Map:

○ A collection of key-value pairs.

# 在下有一行写对象的属性和值的关系,注意缩进
k: v

○Example:

friends:
    lastName: zhangsan
    age: 20
# 行内写法
friends: {lastName: zhangsan,age: 10}

●Array, List, Set:

○ A sequenced set of values.

# 用-值表示数组中的一个元素
k:
 - v1
 - v2
 - v3

○Example:

pets:
  - dog
  - cat
# 行内写法
pets: [dog,cat]

● Literals (numbers, strings, Booleans):

o A single, indivisible value.

# 字面量值直接写
# 默认情况下,字符串不用加引号
k: v

○Example:

server:
  port: 8080

3 YAML configuration file value injection

●Configuration file:

person:
  lastName: zhangsan
  age: 25
  boss: true
  birth: 1992/11/11
#  maps: {k1: v1,k2: v2}
  maps:
    k1: v1
    k2: v2
#  lists: [list1,list2]
  lists:
    - lists1
    - lists2
  dog:
    name: 小花
    age: 5
person.last-name=zhansan
person.age=15
person.birth=1991/11/11
person.boss=true
person.lists=a,b,c
person.maps.k1=v1
person.maps.k2=v2
person.dog.name=dog
person.dog.age=5

●Corresponding JavaBean:

package com.sunxiaping.springboot.domain;

import java.io.Serializable;

public class Dog implements Serializable {

    private String name;

    private Integer age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Dog{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
package com.sunxiaping.springboot.domain;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

import java.io.Serializable;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * 将配置文件中配置的每一个属性的值,映射到这个组件中
 *
 * @ConfigurationProperties 告诉 SpringBoot 将本类中的所有属性和属性文件中相关属性进行绑定
 * prefix = "person":配置文件中那个下面的所有属性进行一一映射
 *
 * 只有这个组件是容器中的组件,才能使用容器提供的 @ConfigurationProperties 功能。
 */
@ConfigurationProperties(prefix = "person")
@Component
public class Person implements Serializable {

    private String lastName;

    private Integer age;

    private Boolean boss;

    private Date birth;

    private Map<String, Object> maps;

    private List<Object> lists;

    private Dog dog;

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public Boolean getBoss() {
        return boss;
    }

    public void setBoss(Boolean boss) {
        this.boss = boss;
    }

    public Date getBirth() {
        return birth;
    }

    public void setBirth(Date birth) {
        this.birth = birth;
    }

    public Map<String, Object> getMaps() {
        return maps;
    }

    public void setMaps(Map<String, Object> maps) {
        this.maps = maps;
    }

    public List<Object> getLists() {
        return lists;
    }

    public void setLists(List<Object> lists) {
        this.lists = lists;
    }

    public Dog getDog() {
        return dog;
    }

    public void setDog(Dog dog) {
        this.dog = dog;
    }

    @Override
    public String toString() {
        return "Person{" +
                "lastName='" + lastName + '\'' +
                ", age=" + age +
                ", boss=" + boss +
                ", birth=" + birth +
                ", maps=" + maps +
                ", lists=" + lists +
                ", dog=" + dog +
                '}';
    }
}

●You can import the configuration file register, and you will be prompted when you write the configuration later:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-configuration-processor</artifactId>
    <optional>true</optional>
</dependency>

3.1 Comparison of @ConfigurationProperties acquisition value and @Value acquisition value

@ConfigurationProperties

@Value

Function

Batch injection of attributes in configuration files

Specify the properties in the configuration file one by one

loose binding (loose syntax)

support

not support

GAME

not support

support

JSR303 data validation

support

not support

complex type encapsulation

support

not support

Notice:

●If we only need to get a certain value in a configuration file in a certain business logic, we use the @Value annotation.

● If we specially write a JavaBean to map with the configuration file, we use the @ConfigurationProperties annotation.

3.2 @PropertySource and @ImportSource

●The @ConfigurationProperties annotation reads the configuration from the global configuration file (application.yml or application.properties) by default.

●The @PropertySource annotation can load the specified configuration file, and the @PropertySource annotation can only load the properties file.

The @ImportSource annotation can import Spring configuration files to make the content in the configuration files take effect, but now it is purely annotation development, so there is no need to use this annotation.

●Example: @PropertySource annotation

●person.properties

person.last-name=zhansan
person.age=15
person.birth=1991/11/11
person.boss=true
person.lists=a,b,c
person.maps.k1=v1
person.maps.k2=v2
person.dog.name=dog
person.dog.age=5

●Dog.java

package com.sunxiaping.springboot.domain;

import java.io.Serializable;

public class Dog implements Serializable {

    private String name;

    private Integer age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Dog{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

●Person.java

package com.sunxiaping.springboot.domain;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;

import java.io.Serializable;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * 将配置文件中配置的每一个属性的值,映射到这个组件中
 *
 * @ConfigurationProperties 告诉SpringBoot将本类中的所有属性和属性文件中相关属性进行绑定
 * prefix = "person":配置文件中那个下面的所有属性进行一一映射
 *
 * 只有这个组件是容器中的组件,才能使用容器提供的@ConfigurationProperties功能。
 */
@PropertySource(value = {"classpath:person.properties"})
@ConfigurationProperties(prefix = "person")
@Component
public class Person implements Serializable {

    private String lastName;

    private Integer age;

    private Boolean boss;

    private Date birth;

    private Map<String, Object> maps;

    private List<Object> lists;

    private Dog dog;

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public Boolean getBoss() {
        return boss;
    }

    public void setBoss(Boolean boss) {
        this.boss = boss;
    }

    public Date getBirth() {
        return birth;
    }

    public void setBirth(Date birth) {
        this.birth = birth;
    }

    public Map<String, Object> getMaps() {
        return maps;
    }

    public void setMaps(Map<String, Object> maps) {
        this.maps = maps;
    }

    public List<Object> getLists() {
        return lists;
    }

    public void setLists(List<Object> lists) {
        this.lists = lists;
    }

    public Dog getDog() {
        return dog;
    }

    public void setDog(Dog dog) {
        this.dog = dog;
    }

    @Override
    public String toString() {
        return "Person{" +
                "lastName='" + lastName + '\'' +
                ", age=" + age +
                ", boss=" + boss +
                ", birth=" + birth +
                ", maps=" + maps +
                ", lists=" + lists +
                ", dog=" + dog +
                '}';
    }
}

●Test:

package com.sunxiaping.springboot;

import com.sunxiaping.springboot.domain.Person;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@SpringBootTest
public class SpringbootApplicationTests {

    @Autowired
    private Person person;

    @Test
    public void test() {
        System.out.println("person = " + person);
    }

}

●Example: @ImportSource annotation

●Dog.java

package com.sunxiaping.springboot.domain;

import java.io.Serializable;

public class Dog implements Serializable {

    private String name;

    private Integer age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Dog{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

●beans.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="dog" class="com.sunxiaping.springboot.domain.Dog"></bean>

</beans>

●SpringBoot startup class:

package com.sunxiaping.springboot;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.ImportResource;

/**
 * 主程序,用来启动SpringBoot应用
 */
@SpringBootApplication
// @ImportResource 将Spring的配置文件导入进来
@ImportResource(value = {"classpath:beans.xml"})
public class HelloWorldApplication {

    public static void main(String[] args) {
        SpringApplication.run(HelloWorldApplication.class, args);
    }

}

●Test:

package com.sunxiaping.springboot;

import com.sunxiaping.springboot.domain.Dog;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@SpringBootTest
public class SpringbootApplicationTests {
    
    @Autowired
    private Dog dog;

    @Test
    public void test() {
        System.out.println("dog = " + dog);
    }
}

4 Configuration file placeholders

4.1 Random numbers

${random.value}
${random.int}
${random.long}
${random.uuid}
...

4.2 Configuration file placeholders

app.name=SpringBoot
app.description=${app.name:Spring牛逼}是个牛逼的框架

●You can refer to the previously configured properties in the configuration file, and use the default value if it cannot be found.

#person.last-name=zhangsan${random.uuid}
person.age=15
person.birth=1991/11/11
person.boss=true
person.lists=a,b,c
person.maps.k1=v1
person.maps.k2=v2
person.dog.name=${person.last-name:小花}
person.dog.age=5

5 profile multi-environment configuration

●profile is Spring's support for different configuration functions for different environments, and you can quickly switch environments by activating, specifying parameters, and other methods.

●①Multi-profile file format:

o Format: application-{profile}.properties.

○例如:application-dev.properites、application-test.properties。

●②Multi-profile document block:

spring:
  profiles:
    active: prod #指定激活的配置

---
# 开发环境的profile
spring:
  profiles: dev

server:
  port: 8081

---
# 部署的profile
spring:
  profiles: prod

server:
  port: 8082

●③Activation method:

○Command line: --spring.profiles.active=dev

○Configuration file: spring.profiles.active=dev

○JVM parameters: -Dspring.profiles.active=dev

○Junit unit test: @ActiveProfiles(value = "dev")

6 Configuration file loading location

●SpringBoot 启动会扫描以下位置的 application.yml 或 application.properties 文件作为 SpringBoot 的默认配置文件。

○file:/config/

○file:/

○classpath:/config/

○classpath:

●以上是按照 优先级从高到低 的顺序,所有的配置文件都会被加载, 高优先级的配置内容会覆盖低优先级配置的内容 ,形成 互补配置

●在项目打包好以后,我们可以使用命令行:--spring.config.location=新配置文件的位置 ,这样启动项目的时候 Spring 将会加载从指定的位置加载配置文件,执行的配置文件和默认加载的这些配置文件共同起作用形成互补配置。

7 外部配置加载顺序

●SpringBoot 支持多种外部配置方式:

○① 命令行参数。

○② 来自 java:comp/env 的 JNDI 属性。

○③ Java系统属性(System.getProperties())。

○④ 操作系统环境变量。

○⑤ RandomValuePropertySource 配置的 random.* 属性值。

○⑥ jar 包外部的 application-{profile}.properties 或 application-{profile}.yml 配置文件。

○⑦ jar 包内部的 application-{profile}.properties 或 application-{profile}.yml 配置文件。

○⑧ jar 包外部的 application.properties 或 application.yml 配置文件。

○⑨ jar 包内部的 application.properties 或 application.yml 配置文件。

○⑩ @Configuration注解类上的 @PropertySource 。

○⑪ 通过 SpringApplication.setDefaultProperties 指定的默认属性。

8 自动配置原理

8.1 配置文件能配置的属性参照

配置文件能配置的属性参照

8.2 自动配置原理

●① SpringBoot 启动的时候加载主配置类,开启了自动配置功能 @EnableAutoConfiguration 。

●② @EnableAutoConfiguration 的作用:

○利用 EnableAutoConfigurationImportSelector 给容器中导入一些组件,可以查看 selectImports 方法的内容。

public class AutoConfigurationImportSelector
        implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware,
        BeanFactoryAware, EnvironmentAware, Ordered {

    private static final String[] NO_IMPORTS = {};

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

    private ConfigurableListableBeanFactory beanFactory;

    private Environment environment;

    private ClassLoader beanClassLoader;

    private ResourceLoader resourceLoader;

    @Override
    public String[] selectImports(AnnotationMetadata annotationMetadata) {
        if (!isEnabled(annotationMetadata)) {
            return NO_IMPORTS;
        }
        try {
            AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
                    .loadMetadata(this.beanClassLoader);
             //获取候选的配置
            AnnotationAttributes attributes = getAttributes(annotationMetadata);
            List<String> configurations = getCandidateConfigurations(annotationMetadata,
                    attributes);
            configurations = removeDuplicates(configurations);
            configurations = sort(configurations, autoConfigurationMetadata);
            Set<String> exclusions = getExclusions(annotationMetadata, attributes);
            checkExcludedClasses(configurations, exclusions);
            configurations.removeAll(exclusions);
            configurations = filter(configurations, autoConfigurationMetadata);
            fireAutoConfigurationImportEvents(configurations, exclusions);
            return configurations.toArray(new String[configurations.size()]);
        }
        catch (IOException ex) {
            throw new IllegalStateException(ex);
        }
    }
    //获取候选的配置
    protected List<String> getCandidateConfigurations(AnnotationMetadata metadata,
            AnnotationAttributes attributes) {
         //扫描所有jar包类路径下的META-INF/spring.factories,把扫描到的这些文件的内容包装成Properties对象,
         //从Properties中获取到EnableAutoConfiguration.class类名对应的值,然后把它们添加到容器中
        List<String> configurations = SpringFactoriesLoader.loadFactoryNames(
                getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader());
        Assert.notEmpty(configurations,
                "No auto configuration classes found in META-INF/spring.factories. If you "
                        + "are using a custom packaging, make sure that file is correct.");
        return configurations;
    }    
     //略
}

○将类路径下 META-INF/spring.factories 里面配置的所有 EnableAutoConfiguration 的值加入到容器中。

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.cloud.CloudAutoConfiguration,\
org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration,\
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.CassandraRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.couchbase.CouchbaseDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.couchbase.CouchbaseRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchAutoConfiguration,\
org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.ldap.LdapDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.ldap.LdapRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.mongo.MongoRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.neo4j.Neo4jDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.neo4j.Neo4jRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.solr.SolrRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration,\
org.springframework.boot.autoconfigure.data.redis.RedisRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.rest.RepositoryRestMvcAutoConfiguration,\
org.springframework.boot.autoconfigure.data.web.SpringDataWebAutoConfiguration,\
org.springframework.boot.autoconfigure.elasticsearch.jest.JestAutoConfiguration,\
org.springframework.boot.autoconfigure.freemarker.FreeMarkerAutoConfiguration,\
org.springframework.boot.autoconfigure.gson.GsonAutoConfiguration,\
org.springframework.boot.autoconfigure.h2.H2ConsoleAutoConfiguration,\
org.springframework.boot.autoconfigure.hateoas.HypermediaAutoConfiguration,\
org.springframework.boot.autoconfigure.hazelcast.HazelcastAutoConfiguration,\
org.springframework.boot.autoconfigure.hazelcast.HazelcastJpaDependencyAutoConfiguration,\
org.springframework.boot.autoconfigure.info.ProjectInfoAutoConfiguration,\
org.springframework.boot.autoconfigure.integration.IntegrationAutoConfiguration,\
org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.JndiDataSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.XADataSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration,\
org.springframework.boot.autoconfigure.jms.JmsAutoConfiguration,\
org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration,\
org.springframework.boot.autoconfigure.jms.JndiConnectionFactoryAutoConfiguration,\
org.springframework.boot.autoconfigure.jms.activemq.ActiveMQAutoConfiguration,\
org.springframework.boot.autoconfigure.jms.artemis.ArtemisAutoConfiguration,\
org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration,\
org.springframework.boot.autoconfigure.groovy.template.GroovyTemplateAutoConfiguration,\
org.springframework.boot.autoconfigure.jersey.JerseyAutoConfiguration,\
org.springframework.boot.autoconfigure.jooq.JooqAutoConfiguration,\
org.springframework.boot.autoconfigure.kafka.KafkaAutoConfiguration,\
org.springframework.boot.autoconfigure.ldap.embedded.EmbeddedLdapAutoConfiguration,\
org.springframework.boot.autoconfigure.ldap.LdapAutoConfiguration,\
org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration,\
org.springframework.boot.autoconfigure.mail.MailSenderAutoConfiguration,\
org.springframework.boot.autoconfigure.mail.MailSenderValidatorAutoConfiguration,\
org.springframework.boot.autoconfigure.mobile.DeviceResolverAutoConfiguration,\
org.springframework.boot.autoconfigure.mobile.DeviceDelegatingViewResolverAutoConfiguration,\
org.springframework.boot.autoconfigure.mobile.SitePreferenceAutoConfiguration,\
org.springframework.boot.autoconfigure.mongo.embedded.EmbeddedMongoAutoConfiguration,\
org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration,\
org.springframework.boot.autoconfigure.mustache.MustacheAutoConfiguration,\
org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration,\
org.springframework.boot.autoconfigure.reactor.ReactorAutoConfiguration,\
org.springframework.boot.autoconfigure.security.SecurityAutoConfiguration,\
org.springframework.boot.autoconfigure.security.SecurityFilterAutoConfiguration,\
org.springframework.boot.autoconfigure.security.FallbackWebSecurityAutoConfiguration,\
org.springframework.boot.autoconfigure.security.oauth2.OAuth2AutoConfiguration,\
org.springframework.boot.autoconfigure.sendgrid.SendGridAutoConfiguration,\
org.springframework.boot.autoconfigure.session.SessionAutoConfiguration,\
org.springframework.boot.autoconfigure.social.SocialWebAutoConfiguration,\
org.springframework.boot.autoconfigure.social.FacebookAutoConfiguration,\
org.springframework.boot.autoconfigure.social.LinkedInAutoConfiguration,\
org.springframework.boot.autoconfigure.social.TwitterAutoConfiguration,\
org.springframework.boot.autoconfigure.solr.SolrAutoConfiguration,\
org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration,\
org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration,\
org.springframework.boot.autoconfigure.transaction.jta.JtaAutoConfiguration,\
org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration,\
org.springframework.boot.autoconfigure.web.DispatcherServletAutoConfiguration,\
org.springframework.boot.autoconfigure.web.EmbeddedServletContainerAutoConfiguration,\
org.springframework.boot.autoconfigure.web.ErrorMvcAutoConfiguration,\
org.springframework.boot.autoconfigure.web.HttpEncodingAutoConfiguration,\
org.springframework.boot.autoconfigure.web.HttpMessageConvertersAutoConfiguration,\
org.springframework.boot.autoconfigure.web.MultipartAutoConfiguration,\
org.springframework.boot.autoconfigure.web.ServerPropertiesAutoConfiguration,\
org.springframework.boot.autoconfigure.web.WebClientAutoConfiguration,\
org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration,\
org.springframework.boot.autoconfigure.websocket.WebSocketAutoConfiguration,\
org.springframework.boot.autoconfigure.websocket.WebSocketMessagingAutoConfiguration,\
org.springframework.boot.autoconfigure.webservices.WebServicesAutoConfiguration

○每一个这样的 xxxAutoConfiguration 类都是容器中的一个组件,都加入到容器中。然后用它们做自动配置。

●③ 每一个自动配置类进行自动配置功能。

●④ 以 HttpEncodingAutoConfiguration( Http 编码自动配置)为例解释自动配置原理:

○其部分源码如下:

@Configuration //这是一个配置类,类似于xml时代的application.xml,可以给容器中添加组件
@EnableConfigurationProperties(HttpEncodingProperties.class) //启用指定类的ConfigurationProperties功能,将配置文件中对应的值和HttpEncodingProperties绑定起来,并把HttpEncodingProperties加入到IOC容器中
@ConditionalOnWebApplication //Spring底层@Conditional注解,根据不同条件,如果满足指定的条件,整个配置类里面的配置就会生效。 @ConditionalOnWebApplication判断当前应用是否是web应用,如果是,当前配置类生效。
@ConditionalOnClass(CharacterEncodingFilter.class) //判断当前项目中有没有CharacterEncodingFilter这个类,CharacterEncodingFilter是SpringMVC中进行乱码解决的过滤器
@ConditionalOnProperty(prefix = "spring.http.encoding", value = "enabled", matchIfMissing = true) //判断配置文件中是否存在某个配置spring.http.encoding.enabled,如果不存在,判断也是成立的。
//即使我们配置文件中不配置spring.http.encoding.enabled=true,也是默认生效的
public class HttpEncodingAutoConfiguration {
    
    //properties已经和SpringBoot的配置文件映射了
    private final HttpEncodingProperties properties;
    
    //只有一个有参构造器的情况下,参数的值就会从容器中拿
    public HttpEncodingAutoConfiguration(HttpEncodingProperties properties) {
        this.properties = properties;
    }
    
    @Bean //给容器中添加一个组件,这个组件的某些值需要从properties中获取
    @ConditionalOnMissingBean(CharacterEncodingFilter.class)
    public CharacterEncodingFilter characterEncodingFilter() {
        CharacterEncodingFilter filter = new OrderedCharacterEncodingFilter();
        filter.setEncoding(this.properties.getCharset().name());
        filter.setForceRequestEncoding(this.properties.shouldForce(Type.REQUEST));
        filter.setForceResponseEncoding(this.properties.shouldForce(Type.RESPONSE));
        return filter;
    }
    //略
}

○根据当前不同的条件判断,决定这个配置类是否生效。一旦这个配置类生效,这个配置类就会给容器中添加各种组件,这些组件的属性是从对应的 properties 类中获取的,而这些 properties 类里面的每一个属性又是和配置文件绑定的。

●⑤ 所有在配置文件中能配置的属性都是在 xxxProperties 类中封装的着。配置文件能配置什么就可以参照某个功能对应的这个属性类。

○HttpEncodingProperties 的部分源码如下:

  @ConfigurationProperties(prefix = "spring.http.encoding") //从配置文件中获取指定的值和Bean的属性进行绑定
  public class HttpEncodingProperties {
  
      public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");
  
      /**
       * Charset of HTTP requests and responses. Added to the "Content-Type" header if not
       * set explicitly.
       */
      private Charset charset = DEFAULT_CHARSET;
  
      /**
       * Force the encoding to the configured charset on HTTP requests and responses.
       */
      private Boolean force;
  
      /**
       * Force the encoding to the configured charset on HTTP requests. Defaults to true
       * when "force" has not been specified.
       */
      private Boolean forceRequest;
      //略   
  }

总结:

●① SpringBoot 启动会加载大量的自动配置类。

●② 我们需要查看需要的功能有没有 SpringBoot 默认写好的配置类。

●③ 我们需要查看自动配置类中到底配置了那些组件(只要我们要用的组件有,我们就不需要再来配置了)。

●④ 给容器自动配置类添加组件的时候,会从 properties 类中获取某些属性,我们就可以在配置文件中指定这些属性的值。

8.3 @Conditional 注解及其衍生注解

●@Conditional 注解的作用:必须是 @Conditional 指定的条件成立,才给容器中添加组件,配置项里面的所有内容才生效。

@Conditional扩展注解

作用(判断是否满足当前指定条件)

@ConditionalOnJava

系统的java版本是否符合要求

@ConditionalOnBean

容器中存在指定Bean;

@ConditionalOnMissingBean

容器中不存在指定Bean;

@ConditionalOnExpression

满足SpEL表达式指定

@ConditionalOnClass

系统中有指定的类

@ConditionalOnMissingClass

系统中没有指定的类

@ConditionalOnSingleCandidate

容器中只有一个指定的Bean,或者这个Bean是首选Bean

@ConditionalOnProperty

系统中指定的属性是否有指定的值

@ConditionalOnResource

类路径下是否存在指定资源文件

@ConditionalOnWebApplication

当前是web环境

@ConditionalOnNotWebApplication

当前不是web环境

@ConditionalOnJndi

JNDI存在指定项

●自动配置类必须在一定的条件下才能生效,那么我们怎么知道哪些自动配置类生效?

●我们可以启用 debug=true 属性来让控制台打印自动配置报告,这样我们就可以很方便的知道哪些自动配置类生效。

#开启 SpringBoot 的 debug 模式
debug: true

若有收获,就点个赞吧

Guess you like

Origin blog.csdn.net/peterjava123/article/details/128824458