1 配置文件

●SpringBoot 使用一个全局配置文件:

○application.yml

○application.properties

●配置文件放在 src/main/resources 目录或者 类路径/config 下。

●.yml 是 YAML 语言的文件,以数据为中心,比 JSON 、XML 等更适合做配置文件。

●全局配置文件可以对一些默认配置值进行修改。

●YAML 配置示例:

server:
  port: 8081

●XML 配置示例:

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

●properties 配置示例:

server.port=8081

2 YAML 语法

2.1 YAML 基本语法

●使用缩进表示层级关系。

●缩进时不允许使用 tab 键,只允许使用空格。

●缩进的空格数目不重要,只要相同层级的元素左侧对齐即可。

●大小写敏感。

●示例:

server:
  port: 8081
  context-path: helloworld

2.2 YAML支持的三种数据结构

●对象、Map :

○键值对的集合。

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

○例如:

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

●数组、List 、Set :

○一组按次序排列的值。

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

○例如:

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

●字面量(数字、字符串、布尔):

○单个的、不可再分的值。

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

○例如:

server:
  port: 8080

3 YAML 配置文件值注入

●配置文件:

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

●对应的 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 +
                '}';
    }
}

●可以导入配置文件注册器,以后编写配置就有提示了:

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

3.1@ConfigurationProperties 获取值和 @Value 获取值的比较

@ConfigurationProperties

@Value

功能

批量注入配置文件中的属性

一个一个指定配置文件中的属性

松散绑定(松散语法)

支持

不支持

SPEL

不支持

支持

JSR303数据校验

支持

不支持

复杂类型封装

支持

不支持

注意:

●如果我们只是在某个业务逻辑中需要获取一个配置文件中的某项值,我们就使用 @Value 注解。

●如果我们专门编写了一个 JavaBean 来和配置文件进行映射,我们就使用 @ConfigurationProperties 注解。

3.2 @PropertySource 和 @ImportSource

●@ConfigurationProperties 注解默认是从全局配置文件(application.yml 或 application.properties)中读取配置。

●@PropertySource 注解可以加载指定的配置文件,并且 @PropertySource 注解只能加载 properties 文件。

@ImportSource 注解可以导入 Spring 的配置文件,让配置文件里面的内容生效,但是现在都是纯注解开发,无需使用此注解。

●示例:@PropertySource 注解

●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 +
                '}';
    }
}

●测试:

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);
    }

}

●示例:@ImportSource 注解

●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的启动类:

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);
    }

}

●测试:

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 配置文件占位符

4.1 随机数

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

4.2 配置文件占位符

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

●可以在配置文件中引用前面配置过的属性,如果找不到就使用默认值。

#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 多环境配置

●profile 是Spring 对不同环境提供不同配置功能的支持,可以通过激活、指定参数等方法快速切换环境。

●①多 profile 文件形式:

○格式:application-{profile}.properties。

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

●②多 profile 文档块:

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

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

server:
  port: 8081

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

server:
  port: 8082

●③激活方式:

○命令行:--spring.profiles.active=dev

○配置文件:spring.profiles.active=dev

○JVM参数:-Dspring.profiles.active=dev

○Junit单元测试:@ActiveProfiles(value = "dev")

6 配置文件加载位置

●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

若有收获,就点个赞吧

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐