【SpringBoot】自动配置原理

1. 第一个 SpringBoot 程序

  1. 选择要创建的项目类型及 JDK 版本

    在这里插入图片描述

  2. 填写项目基本信息

    在这里插入图片描述

  3. 选择依赖

    在这里插入图片描述

  4. 选择项目位置

    在这里插入图片描述

  5. 创建完项目结构如图所示

    在这里插入图片描述

  6. 创建 HelloController

    package com.ice.demo.controller;
    
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    @RestController
    public class HelloController {
        @RequestMapping("/hello")
        public String hello(){
            return "Hello SpringBoot!";
        }
    }
    
  7. 启动主类 DemoApplication

    在这里插入图片描述

  8. 浏览器访问:127.0.0.1:8080/hello

    在这里插入图片描述

2. 依赖管理特性

初始化项目的 pom.xml 文件长这样:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.4.3</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.ice</groupId>
    <artifactId>demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>demo</name>
    <description>第一个SpringBoot程序</description>
    <properties>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

可以发现,里面有 <parent> 标签,说明该工程是一个子工程,其父工程的 pom.xml 文件为:

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.4.3</version>
    <relativePath/> <!-- lookup parent from repository -->
</parent>

然后我们进入 spring-boot-starter-parent.pom 查看,主要包括如下设置:

  • 项目信息(包括该父工程的开发者信息)

  • JDK 版本(JDK 8)

  • 字符编码(UTF-8)

  • 开源协议(Apache License)

  • 静态资源过滤

    <resources>
        <resource>
            <directory>${basedir}/src/main/resources</directory>
            <filtering>true</filtering>
            <includes>
                <include>**/application*.yml</include>
                <include>**/application*.yaml</include>
                <include>**/application*.properties</include>
            </includes>
        </resource>
        <resource>
            <directory>${basedir}/src/main/resources</directory>
            <excludes>
                <exclude>**/application*.yml</exclude>
                <exclude>**/application*.yaml</exclude>
                <exclude>**/application*.properties</exclude>
            </excludes>
        </resource>
    </resources>
    
  • 编译打包插件

    这里简要说下这个打包插件:

    <executions>
        <execution>
            <phase>package</phase>
            <goals>
                <goal>shade</goal>
            </goals>
            <configuration>
                <transformers>
                    <transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
                        <resource>META-INF/spring.handlers</resource>
                    </transformer>
                    <transformer implementation="org.springframework.boot.maven.PropertiesMergingResourceTransformer">
                        <resource>META-INF/spring.factories</resource>
                    </transformer>
                    <transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
                        <resource>META-INF/spring.schemas</resource>
                    </transformer>
                    <transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/>
                    <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                        <mainClass>${start-class}</mainClass>
                    </transformer>
                </transformers>
            </configuration>
        </execution>
    </executions>
    

    其实就是使用 maven-shade-plugin 插件打包,如果项目中用到了 Spring Framework,将依赖打到一个 jar 包中,运行时会出现读取 XML schema 文件出错. 原因是Spring Framework 的多个 jar 包中包含相同的文件 spring.handlers 和 spring.schemas,如果生成一个 jar 包会互相覆盖. 为了避免互相影响,可以使用 AppendingTransformer 来对文件内容追加合并.

并且,该文件也有一个父文件:

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-dependencies</artifactId>
    <version>2.4.3</version>
</parent>

进入 spring-boot-dependencies.pom 查看,可以发现包括两部分内容:

  • 各种经常使用的工具包及其默认版本号
  • 工具包相对应的 maven 依赖

可以在创建的项目的目录下的 pom.xml 中修改版本号来达到使用特定版本的目的

接下来再谈谈启动器,SpringBoot 已经内置了许多场景的启动器,其命名方式为 spring-boot-starters-*,引入该场景的依赖后,自动会导入一系列相关依赖,无需像以前一样逐个导入.

以 web 场景为例:

在这里插入图片描述

  • 没有的依赖可以在创建的项目目录下的 pom 文件中添加
  • 已有的依赖允许替换版本
  • 不建议替换 Spring 系列依赖的版本,他们一般与 SpringBoot 版本绑定

3. 项目结构

当一个类不包含包声明时,它被认为是在默认包中. 通常不鼓励使用默认包,应该避免使用. 对于 SpringBoot 应用程序来说,它可能会导致一些特殊的问题. 建议遵循 Java
推荐的包命名约定并使用反向的域名,例如:com.example.project.

每个 SpringBoot 程序应当有一个主启动类,通常建议将主应用程序类放在根包中,置于其他类之上.

@SpringBootApplication 注解经常放在主类上,它隐式地为某些项定义了一个基本的“搜索包”,主程序所在包及其下面的所有子包里面的组件都会被默认扫描进来

典型的项目结构如下:

com
  +- example
    +- myapplication
      +- Application.java
      |
      +- customer
      |         +- Customer.java
      |         +- CustomerController.java
      |         +- CustomerService.java
      |         +- CustomerRepository.java
      |
      +- order
            +- Order.java
            +- OrderController.java
            +- OrderService.java
            +- OrderRepository.java

更改默认扫描包可以在 @SpringBootApplication 注解中传递参数:@SpringBootApplication(scanBasePackages="com.xxx.xxx")

@SpringBootApplication(scanBasePackages="com.ice.work")
等同于
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan("com.ice.work")

SpringBootApplication 注解其实是由下面三个注解封装的

4. 自动配置

SpringBoot 已经为我们配置好了许多功能:

  • 自动配好Tomcat

    • 引入 Tomcat 依赖

    • 配置 Tomcat

      <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-tomcat</artifactId>
          <version>2.3.4.RELEASE</version>
          <scope>compile</scope>
      </dependency>
      
  • 自动配好 SpringMVC

    • 引入 SpringMVC 全套组件
    • 自动配好 SpringMVC 常用组件(功能),如:视图解析器,文件上传解析器
  • 自动配好 Web 常见功能,如:字符编码问题

    • SpringBoot 帮我们配置好了所有 web 开发的常见场景
  • 各种配置拥有默认值

    • 默认配置最终都是映射到某个类上,如:MultipartProperties
    • 配置文件的值最终会绑定某个类上,这个类会在容器中创建对象
  • 按需加载所有自动配置项

    • 非常多的 starter
    • 引入了哪些场景,这个场景的自动配置才会开启
    • SpringBoot 所有的自动配置功能都在 spring-boot-autoconfigure 包里面

5. 容器功能

5.1 组件添加

首先创建两个实体类:

@Data
@ToString
@NoArgsConstructor
@AllArgsConstructor
public class User {
    private String name;
    private Integer age;
}
@Data
@ToString
@NoArgsConstructor
@AllArgsConstructor
public class Pet {
    private String name;
}

注意,学习的时候用 lombok 加快效率,实际开发别用.

传统的方法就是创建 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="user01" class="com.ice.demo.bean.User">
        <property name="name" value="zhangsan"></property>
        <property name="age" value="18"></property>
    </bean>

    <bean id="cat" class="com.ice.demo.bean.Pet">
        <property name="name" value="tomcat"></property>
    </bean>
</beans>

下面看看新的基于注解的配置方法.

5.1.1 使用 @Configuration 注解

package com.ice.demo.config;

import com.ice.demo.bean.Pet;
import com.ice.demo.bean.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * 1. 配置类里面使用 @Bean 标准在方法上给容器注册组件,默认是单实例的
 * 2. 配置类本身也是组件
 * 3. proxyBeanMethods:代理 bean 的方法,默认为 true
 */
@Configuration(proxyBeanMethods = true) // 告诉 SpringBoot 这是一个配置类,等于一个配置类
public class MyConfig {

    @Bean
    // 给容器中添加组件,以方法名作为组件的 id
    // 返回类型就是组件类型
    // 返回的值就是组件在容器中的实例
    public User user01() {
        return new User("zhangsan", 18);
    }

    @Bean("tom")
    public Pet tomcatPet() {
        return new Pet("tomcat");
    }
}

然后,启动主程序:

@SpringBootApplication
public class DemoApplication {

    public static void main(String[] args) {
        // 返回 IOC 容器
        ConfigurableApplicationContext run = SpringApplication.run(DemoApplication.class, args);

        // 2查看容器里的组件
        String[] names = run.getBeanDefinitionNames();
        for (String name : names) {
            System.out.println(name);
        }
    }
}

可以看到容器中已经有杂合两个组件了:

在这里插入图片描述

这种方式仍然保证容器中组件是单实例的特性:

@SpringBootApplication
public class DemoApplication {

    public static void main(String[] args) {
        // 返回 IOC 容器
        ConfigurableApplicationContext run = SpringApplication.run(DemoApplication.class, args);

        // 从容器中获取组件
        Pet tom01 = run.getBean("tom", Pet.class);
        Pet tom02 = run.getBean("tom", Pet.class);
        System.out.println(tom01 == tom02); // true
        
        // 配置类本身也是组件
        // 如果@Configuration(proxyBeanMethods = true),获取到的是代理对象
        // 此时获取组件时,如果容器中没有,则新创建一个,否则从从气质获取,保证组件单实例
        MyConfig bean = run.getBean(MyConfig.class);
        System.out.println(bean); // com.ice.demo.config.MyConfig$$EnhancerBySpringCGLIB$$bacdb0d@3561304b
        
        // 外部无论对配置类中的组件注册方法调用多少次,获取的都是之前容器中的单实例对象
        User user = bean.user01();
        User user1 = bean.user01();
        System.out.println(user == user1); // true
    }

}

输出结果:

true
com.ice.demo.config.MyConfig$$EnhancerBySpringCGLIB$$bacdb0d@3561304b
true

下面试验下 @Configuration(proxyBeanMethods = false) 的情况,其他代码不变,启动主类后输出的结果为:

true
com.ice.demo.config.MyConfig@248fb644
false

说明对于这段代码:

MyConfig bean = run.getBean(MyConfig.class);
System.out.println(bean); // com.ice.demo.config.MyConfig@248fb644,可以看到不是代理对象了

User user = bean.user01();
User user1 = bean.user01();
System.out.println(user == user1); // false,此时拿到的也就不是相等的值了

引出 SpringBoot 的两种配置:FullLite

  • Full:@Configuration(proxyBeanMethods = true)
  • Lite:@Configuration(proxyBeanMethods = false)

主要用来解决组件依赖场景

修改一下 User 类:

@Data
@ToString
@NoArgsConstructor
@AllArgsConstructor
public class User {
    private String name;
    private Integer age;
    private Pet pet;

    public User(String name, Integer age) {
        this.name = name;
        this.age = age;
    }
}

再修改一下配置类:

@Configuration(proxyBeanMethods = true)
public class MyConfig {

    @Bean
    public User user01() {
        User zhangsan = new User("zhangsan", 18);
        // User 组件依赖了 Pet 组件
        zhangsan.setPet(tomcatPet());
        return zhangsan;
    }

    @Bean("tom")
    public Pet tomcatPet() {
        return new Pet("tomcat");
    }
}

再次启动 SpringBoot:

@SpringBootApplication
public class DemoApplication {

    public static void main(String[] args) {
        // 返回 IOC 容器
        ConfigurableApplicationContext run = SpringApplication.run(DemoApplication.class, args);

        User user01 = run.getBean("user01", User.class);
        Pet tom = run.getBean("tom", Pet.class);
        System.out.println(user01.getPet() == tom); // true
    }
}

输出结果为:

true

但是,我们如果设置 @Configuration(proxyBeanMethods = false)

输出的结果为:

false

这就是 SpringBoot 2 的一个大的改变,Lite模式的优点是可以跳过一些检查,对于无依赖场景加载会比较快,但是有依赖情况下,还是设置为 Full 模式比较好.

5.1.2 传统注解

@Bean@Component@Controller@Service@Repository

这个不用多说了,包扫描到就能加载注册组件(@ComponentScan

5.1.3 @Import

这个在之前注解驱动开发有过笔记,见 Chapter 1.7

5.1.4 @Conditional

条件注册,满足 Condition 条件,则进行组件注册,该注解源码为:

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Conditional {
    Class<? extends Condition>[] value();
}

其继承树为:

在这里插入图片描述

  • ConditionalOnBean:当容器中存在某些 bean 的时候才执行
  • ConditionalOnMissingBean:当容器中没有某些 bean 的时候才执行
  • ConditionalOnClass:当容器中有某个类的时候才执行
  • ConditionalOnMissingClass:当容器中没有某个类的时候才执行
  • ConditionalOnResource:当存在某些资源文件的时候才执行
  • ConditionalOnJava:在指定的 Java 版本号下才执行
  • ConditionalOnWebApplication:当项目是一个 web 应用的时候才执行
  • ConditionalOnNotWebApplication:当项目不是一个 web 应用的时候才执行
  • ConditionalOnProperty:当容器中存在某些属性的时候才执行
  • ConditionalOnSingleCandidate:当某些 bean 是单实例或者多实例但是存在 @Primary 注解标注的 bean 的时候才执行

【例】配置类中值注册了 User 组件,但是没有注册 Pet 组件

@Configuration(proxyBeanMethods = true) // 告诉 SpringBoot 这是一个配置类,等于一个配置类
public class MyConfig {

    @Bean
    public User user01() {
        User zhangsan = new User("zhangsan", 18);
        zhangsan.setPet(tomcatPet());
        return zhangsan;
    }
    
    // @Bean("tom")
    // 此时只是常规方法,不是注册组件
    public Pet tomcatPet() {
        return new Pet("tomcat");
    }
}

此时执行主类:

@SpringBootApplication
public class DemoApplication {

    public static void main(String[] args) {
        // 返回 IOC 容器
        ConfigurableApplicationContext run = SpringApplication.run(DemoApplication.class, args);

        boolean tom = run.containsBean("tom");
        System.out.println(tom);      // false
        boolean user01 = run.containsBean("user01");
        System.out.println(user01);   // true
    }
}

现在希望容器中没有 Pet 组件时,也不要注册 User 组件,可以使用条件注解:

@Configuration(proxyBeanMethods = true) // 告诉 SpringBoot 这是一个配置类,等于一个配置类
public class MyConfig {

    @Bean
    @ConditionalOnBean(name = "tom")
    public User user01() {
        User zhangsan = new User("zhangsan", 18);
        // User 组件依赖了 Pet 组件
        zhangsan.setPet(tomcatPet());
        return zhangsan;
    }

    // @Bean("tom")
    public Pet tomcatPet() {
        return new Pet("tomcat");
    }
}

此时再执行主类方法:

false
false

5.2 原生配置文件引入

有些老的第三方包也许不支持注解形式,只能使用配置文件的方式,此时可以使用 @ImportResource 注解引入该配置文件

例如:

<?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="haha" class="com.ice.demo.bean.User">
        <property name="name" value="zhangsan"></property>
        <property name="age" value="18"></property>
    </bean>

    <bean id="hehe" class="com.ice.demo.bean.Pet">
        <property name="name" value="tomcat"></property>
    </bean>
</beans>

在配置类中如何引入呢?

@Configuration
@ImportResource("classpath:beans.xml")
public class MyConfig {

}

此时执行:

@SpringBootApplication
public class DemoApplication {

    public static void main(String[] args) {
        // 返回 IOC 容器
        ConfigurableApplicationContext run = SpringApplication.run(DemoApplication.class, args);

        boolean haha = run.containsBean("haha");
        boolean hehe = run.containsBean("hehe");
        System.out.println(haha);  // true
        System.out.println(hehe);  // true
    }
}

5.3 配置绑定

5.3.1 @Component + @ConfigurationProperties

我们写一个 Car

@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
@Component  // 只有在容器中的组件,才会拥有 SpringBoot 容器提供的强大功能
@ConfigurationProperties(prefix = "mycar")
public class Car {
    private String brand;
    private Integer price;
}

配置文件这样写:

mycar.brand=BYD
mycar.price=100000

上面的含义是,将 Car 类注册到容器中,并且通过注解 @ConfigurationProperties 绑定配置文件中前缀为 mycar 的属性值到该组件的属性中.

注意,配置文件中的前缀之后的属性名必须和类中的属性名一致!

我们编写一个 Controller 来测试一下:

@RestController
public class CarController {
    @Autowired
    Car car;  // 因为上面已经通过注解将该组件注册到容器中了,所以可以直接取

    @RequestMapping("/car")
    public Car car() {
        return car;
    }
}

网页显示:

在这里插入图片描述

5.3.2 @EnableConfigurationProperties + @ConfigurationProperties

此时 Car 类这样写:

@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
@ConfigurationProperties(prefix = "mycar")
public class Car {
    private String brand;
    private Integer price;
}

配置文件需要加一个注解,来指定哪个类开启配置绑定功能:

@Configuration
// 1. 开启 Car 配置绑定功能
// 2. 把 Car 组件注册到容器中
@EnableConfigurationProperties(Car.class)
public class MyConfig {

}

6. 自动配置原理入门

SpringBoot 的主程序类被 @SpringBootApplication 注解,其实核心等价于下面三个注解:

  • @SpringBootConfiguration
  • @EnableAutoConfigration
  • @ComponentScan

6.1 @SpringBootConfiguration

该注解源码为:

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
public @interface SpringBootConfiguration {
    @AliasFor(
        annotation = Configuration.class
    )
    boolean proxyBeanMethods() default true;
}

它其实就是一个 @Configuration,代表当前类是一个配置类,具体的见之前的博客,注解驱动开发

6.2 @ComponentScan

就是指定要扫描的包,排除的包,过滤的包

6.3 @EnableAutoConfigration

// 省略元注解
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {}

6.3.1 @AutoConfigurationPackage

// 省略元注解
@Import(AutoConfigurationPackages.Registrar.class)  // 给容器中导入一个组件
public @interface AutoConfigurationPackage {

	String[] basePackages() default {};

	Class<?>[] basePackageClasses() default {};

}

进入 AutoConfigurationPackages.Registrar 类:

static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {

    @Override
    public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
        register(registry, new PackageImports(metadata).getPackageNames().toArray(new String[0]));
    }

    @Override
    public Set<Object> determineImports(AnnotationMetadata metadata) {
        return Collections.singleton(new PackageImports(metadata));
    }

}

可以发现,其实就 2 个方法,registerBeanDefinitions() 是用来给容器中批量注册一些列组件的,在第 5 行打上断点:

在这里插入图片描述

其中,new PackageImports(metadata).getPackageNames() 是为了得到注解注释的类(其实就是主启动类)所在的包的全限定包名:

在这里插入图片描述

然后,就将该包下的所有组件都注册到容器中来.

6.3.2 @Import(AutoConfigurationImportSelector.class)

这里导入组件 AutoConfigurationImportSelector 用的是 @Import 的第二种方式,导入实现了 ImportSelector 接口的类.

这里面重写了selectImports() 方法:

在这里插入图片描述

  • 该方法返回值就是要导入到容器中的全限定类名
  • AnnotationMetadata 包含了当前配置类的所有注解信息,不仅仅是 @Import

上面重写方法是调用 getAutoConfigurationEntry() 方法得到一个结果,然后转成 String 数组返回.

所以我们要重点看看 getAutoConfigurationEntry() 这个方法.

在这里插入图片描述

进入该方法后,打上断点,debug 执行.

可以看到,函数内的一系列操作都是基于 configurations 列表的,该列表长度为 133 个:

在这里插入图片描述

这 130 个组件都要被导入到容器中.

为啥是这 130 个呢?就是通过方法 getCandidateConfigurations() 获取所有需要导入到容器中的组件(配置类).

如果你 Maven 里写的包有其他的,可能数目不一致

现在重新在该方法上打断点,进入该方法后,可以看到:

protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
    // 利用工厂加载,最终调用SpringFactoriesLoader类中的 
    // Map<String, List<String>> loadSpringFactories(ClassLoader classLoader) 方法得到所有的组件
    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;
}

所以我们再进入到 loadSpringFactories() 方法中打断点:

在这里插入图片描述

可以看到之前几行都是空,然后进入到 try-catch 语句块,先调用 getResources() 方法加载一些资源文件:

在这里插入图片描述

我们看看资源文件的位置:

在这里插入图片描述

到这,可以理一下了,注册所有组件之前,要先从 META-INF/spring.factories 位置加载资源文件的,也就是默认扫描当前系统里所有 META-INF/spring.factories 位置的文件,例如 SpringBoot 的一些包,其中最重要的是下面这个 spring-boot-autoconfigure-2.4.4.jar

在这里插入图片描述

进入该资源文件,找到 org.springframework.boot.autoconfigure.EnableAutoConfiguration 配置项,可以看到写死了 SpringBoot 一启动要给容器中加载的所有配置类.

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,\
org.springframework.boot.autoconfigure.data.jdbc.JdbcRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.ldap.LdapRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.mongo.MongoReactiveDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.mongo.MongoReactiveRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.mongo.MongoRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.neo4j.Neo4jDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.neo4j.Neo4jReactiveDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.neo4j.Neo4jReactiveRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.neo4j.Neo4jRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.solr.SolrRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.r2dbc.R2dbcDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.r2dbc.R2dbcRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration,\
org.springframework.boot.autoconfigure.data.redis.RedisReactiveAutoConfiguration,\
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.ElasticsearchRestClientAutoConfiguration,\
org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration,\
org.springframework.boot.autoconfigure.freemarker.FreeMarkerAutoConfiguration,\
org.springframework.boot.autoconfigure.groovy.template.GroovyTemplateAutoConfiguration,\
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.http.HttpMessageConvertersAutoConfiguration,\
org.springframework.boot.autoconfigure.http.codec.CodecsAutoConfiguration,\
org.springframework.boot.autoconfigure.influx.InfluxDbAutoConfiguration,\
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.jersey.JerseyAutoConfiguration,\
org.springframework.boot.autoconfigure.jooq.JooqAutoConfiguration,\
org.springframework.boot.autoconfigure.jsonb.JsonbAutoConfiguration,\
org.springframework.boot.autoconfigure.kafka.KafkaAutoConfiguration,\
org.springframework.boot.autoconfigure.availability.ApplicationAvailabilityAutoConfiguration,\
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.mongo.embedded.EmbeddedMongoAutoConfiguration,\
org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration,\
org.springframework.boot.autoconfigure.mongo.MongoReactiveAutoConfiguration,\
org.springframework.boot.autoconfigure.mustache.MustacheAutoConfiguration,\
org.springframework.boot.autoconfigure.neo4j.Neo4jAutoConfiguration,\
org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration,\
org.springframework.boot.autoconfigure.quartz.QuartzAutoConfiguration,\
org.springframework.boot.autoconfigure.r2dbc.R2dbcAutoConfiguration,\
org.springframework.boot.autoconfigure.r2dbc.R2dbcTransactionManagerAutoConfiguration,\
org.springframework.boot.autoconfigure.rsocket.RSocketMessagingAutoConfiguration,\
org.springframework.boot.autoconfigure.rsocket.RSocketRequesterAutoConfiguration,\
org.springframework.boot.autoconfigure.rsocket.RSocketServerAutoConfiguration,\
org.springframework.boot.autoconfigure.rsocket.RSocketStrategiesAutoConfiguration,\
org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration,\
org.springframework.boot.autoconfigure.security.servlet.UserDetailsServiceAutoConfiguration,\
org.springframework.boot.autoconfigure.security.servlet.SecurityFilterAutoConfiguration,\
org.springframework.boot.autoconfigure.security.reactive.ReactiveSecurityAutoConfiguration,\
org.springframework.boot.autoconfigure.security.reactive.ReactiveUserDetailsServiceAutoConfiguration,\
org.springframework.boot.autoconfigure.security.rsocket.RSocketSecurityAutoConfiguration,\
org.springframework.boot.autoconfigure.security.saml2.Saml2RelyingPartyAutoConfiguration,\
org.springframework.boot.autoconfigure.sendgrid.SendGridAutoConfiguration,\
org.springframework.boot.autoconfigure.session.SessionAutoConfiguration,\
org.springframework.boot.autoconfigure.security.oauth2.client.servlet.OAuth2ClientAutoConfiguration,\
org.springframework.boot.autoconfigure.security.oauth2.client.reactive.ReactiveOAuth2ClientAutoConfiguration,\
org.springframework.boot.autoconfigure.security.oauth2.resource.servlet.OAuth2ResourceServerAutoConfiguration,\
org.springframework.boot.autoconfigure.security.oauth2.resource.reactive.ReactiveOAuth2ResourceServerAutoConfiguration,\
org.springframework.boot.autoconfigure.solr.SolrAutoConfiguration,\
org.springframework.boot.autoconfigure.task.TaskExecutionAutoConfiguration,\
org.springframework.boot.autoconfigure.task.TaskSchedulingAutoConfiguration,\
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.client.RestTemplateAutoConfiguration,\
org.springframework.boot.autoconfigure.web.embedded.EmbeddedWebServerFactoryCustomizerAutoConfiguration,\
org.springframework.boot.autoconfigure.web.reactive.HttpHandlerAutoConfiguration,\
org.springframework.boot.autoconfigure.web.reactive.ReactiveWebServerFactoryAutoConfiguration,\
org.springframework.boot.autoconfigure.web.reactive.WebFluxAutoConfiguration,\
org.springframework.boot.autoconfigure.web.reactive.error.ErrorWebFluxAutoConfiguration,\
org.springframework.boot.autoconfigure.web.reactive.function.client.ClientHttpConnectorAutoConfiguration,\
org.springframework.boot.autoconfigure.web.reactive.function.client.WebClientAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.HttpEncodingAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.MultipartAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration,\
org.springframework.boot.autoconfigure.websocket.reactive.WebSocketReactiveAutoConfiguration,\
org.springframework.boot.autoconfigure.websocket.servlet.WebSocketServletAutoConfiguration,\
org.springframework.boot.autoconfigure.websocket.servlet.WebSocketMessagingAutoConfiguration,\
org.springframework.boot.autoconfigure.webservices.WebServicesAutoConfiguration,\
org.springframework.boot.autoconfigure.webservices.client.WebServiceTemplateAutoConfiguration

虽然我们 130 个场景的所有自动配置名称,启动的时候默认全部加载,但是最终会按照条件装配规则,按需注册,用到的就是 @Conditional 一系列条件装配的注解.

6.4 总结

  • SpringBoot 先加载所有的配置类
  • 每个自动配置类按照条件生效
  • 生效的配置类就会给容器中装配很多组件
  • 只要容器中有这些组件,相当于这些功能就有了
  • 只要有用户自己配置的,以用户自定义的为先
  • 定制化配置
    • 用户直接自己写一个 @Bean 替换底层的组件
    • 配置文件设置自定义的属性值

6.5 注释处理器

IDEA 自定义类想要在配置文件中有代码提示的话需要导入一个 processor 包:

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

但是,这只是在开发时候有用,打包时我们不应该将该插件打包进项目中:

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <configuration>
                <excludes>
                    <exclude>
                        <groupId>org.springframework.boot</groupId>
                        <artifactId>spring-boot-configuration-processor</artifactId>
                    </exclude>
                </excludes>
            </configuration>
        </plugin>
    </plugins>
</build>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值