Spring Boot 自动配置原理及过程

Spring Boot 是一个基于 Spring 框架的快速应用开发框架,它极大地简化了开发流程,使得开发者能够更加快速地构建应用程序。Spring Boot 中的一个关键特性就是自动配置(Auto-Configuration),这使得开发者无需手动编写大量的配置代码就能得到一个功能完善的 Spring 应用程序。

1.基本原理

Spring Boot 的自动配置是基于 Spring 框架的核心功能------依赖注入(Dependency Injection)和自动装配(Bean Auto-Wiring)。

1.1.启动类和 @SpringBootApplication 注解

启动类 :Spring Boot 应用通常有一个主类,这个主类上会有一个 @SpringBootApplication 注解。

@SpringBootApplication 注解:该注解是一个组合注解

  • @SpringBootConfiguration:表示这是一个 Spring 配置类。
  • @EnableAutoConfiguration:启用自动配置功能,告诉 Spring Boot 启动自动配置。
  • @ComponentScan :扫描指定包下的组件,以便于发现并装配带有 @Component@Service@Repository@Controller 等注解的类。

1.2.@EnableAutoConfiguration 注解

@EnableAutoConfiguration注解:该注解本身也是一个组合注解

  • @AutoConfigurationPackage :这个注解会告诉 Spring Boot 扫描当前包以及子包中的 @Component 相关的注解。
  • @Import({AutoConfigurationImportSelector.class})
    • AutoConfigurationImportSelector:通过这个类,Spring Boot 会在启动时选择并导入一组自动配置类。

1.3.自动配置类的发现

  • AutoConfigurationImportSelector :在 Spring 容器启动过程中,这个类会从 META-INF/spring.factories 文件中读取所有候选的自动配置类。

  • spring.factories 文件 :位于每个自动配置模块的 META-INF 目录下,包含了一系列的自动配置类和它们对应的条件,每个类都是一个配置项。

  • org.springframework.boot.autoconfigure.AutoConfiguration.imports

    src/main/resources/META-INF/spring 文件夹下的org.springframework.boot.autoconfigure.AutoConfiguration.imports 文件功能与 spring.factories一样。都是用来加载自动装配的类。

    两者目的都是为引入外部的jar,把外部bean纳入到Spring容器,实现外部组件与Spring的集成, 主要区别当前方式通过配置的信息创建内部是具体的要导入到Spring环境的中的配置类, 而spring.factories这种方式,内部是key-value的形式。

    注意:从spring boot2.7开始,慢慢不支持META-INF/spring.factories文件了需要导入的自动配置类可以放在
    /META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports文件中。

1.4.条件匹配

  • @Conditional 注解 :自动配置类中的每个 Bean 都可能带有 @Conditional 注解,它用来指定配置类生效的条件。

  • 条件注解 :例如 @ConditionalOnClass@ConditionalOnMissingClass@ConditionalOnBean@ConditionalOnMissingBean 等,这些注解可以帮助决定哪些自动配置类会被激活。

    @ConditionalOnClass: 当指定的类位于类路径上时,才会启用被注解的组件或配置。这可用于根据类的可用性来决定是否启用某个特定功能。
    @ConditionalOnMissingClass: 当指定的类不在类路径上时,才会启用被注解的组件或配置。这可用于在某些类不可用时应用备用实现。
    @ConditionalOnBean: 当指定的 Bean 在应用程序上下文中存在时,才会启用被注解的组件或配置。这可以用于基于其他 Bean 的存在与否来决定是否启用特定功能。
    @ConditionalOnMissingBean : 当指定的 Bean 在应用程序上下文中不存在时,才会启用被注解的组件或配置。这可用于提供默认实现或避免重复创建 Bean。
    @ConditionalOnProperty: 当指定的属性满足条件时,才会启用被注解的组件或配置。这可用于基于配置属性的值来决定是否启用特定功能。
    @ConditionalOnExpression: 当指定的 SpEL 表达式计算结果为 true 时,才会启用被注解的组件或配置。这可用于更复杂的条件判断。

1.5.自动配置类

  • 自动配置类:每个自动配置类通常会针对一个特定的框架或技术栈(如 Tomcat、JPA、Redis 等)。
  • 配置Bean :自动配置类内部会通过 @Bean 方法来注册 Bean 到 Spring 容器中。
  • 属性绑定 :自动配置类还可以通过 @ConfigurationProperties 注解来绑定配置文件中的属性到特定的 Java 对象上。

1.6.配置文件

  • application.propertiesapplication.yml:这些文件包含了 Spring Boot 应用程序的配置信息,用于调整自动配置的行为。

1.7.Starter 依赖

Spring Boot 提供了一组"starter"依赖,这些依赖简化了项目的依赖管理。每个 starter 包含了构建典型应用所需的依赖项,而无需编写复杂的 XML 配置文件。例如,spring-boot-starter-web 包含了 Web 应用所需的所有依赖,如 Spring MVC、Tomcat(默认的嵌入式容器)等。

2.自动装配的过程

2.1 启动 Spring 应用

当你运行带有 @SpringBootApplication 注解的主类时,Spring Boot 会开始初始化 Spring 应用上下文。

2.2 导入自动配置

  • @EnableAutoConfiguration :该注解触发了 AutoConfigurationImportSelector 的执行。
  • AutoConfigurationImportSelector:这个类会根据类路径上的可用资源来决定应该导入哪些自动配置类。
  • 选择自动配置类 :通过 getCandidateConfigurations() 方法,AutoConfigurationImportSelector 会读取 spring.factories 文件中的配置,从中挑选出所有以 org.springframework.boot.autoconfigure. 开头的配置类。

2.3 加载自动配置类

  • 加载配置类:Spring 会将这些自动配置类加载到应用上下文中。
  • 解析条件注解 :对于每个自动配置类,Spring 会检查 @Conditional 注解来确定是否应该激活该配置类。
  • 条件匹配 :如果条件匹配成功,则会创建配置类的实例,并执行其 @Bean 方法来注册 Bean。

2.4 注册 Bean

  • 注册 Bean :自动配置类中的 @Bean 方法会被执行,这些方法会创建并注册新的 Bean 到 Spring 容器中。
  • 属性绑定 :如果有 @ConfigurationProperties 注解,则会尝试从配置文件中读取相应的属性值并绑定到相应的 Java 对象上。

2.5 应用配置

  • 最终配置:所有的自动配置完成后,Spring Boot 会将所有注册的 Bean 进行依赖注入,从而完成整个应用的初始化过程。

3.示例 :MyBatis

当使用 MyBatis 作为持久层框架时,Spring Boot 会自动配置 MyBatis 相关的组件,以简化 MyBatis 的集成。

3.1. 添加依赖

pom.xml 文件中添加 MyBatis 和 Spring Boot Starter MyBatis 的Starter 依赖:

mybatis-spring-boot-starter,它会自动添加 MyBatis 和其他相关依赖,而不需要你显式声明每一个依赖。

xml 复制代码
<!-- Maven -->
<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>2.2.1</version>
</dependency>

3.2. 启动类

在启动类上 @SpringBootApplication 注解包含 @EnableAutoConfiguration 启动自动装配

3.3. 自动配置的发现

  • @EnableAutoConfiguration:这个注解告诉 Spring Boot 启动自动配置过程。

  • AutoConfigurationImportSelector :这个类负责从 spring.factories 文件中读取所有候选的自动配置类。该文件列出了所有候选的自动配置类。

    properties 复制代码
    # META-INF/spring.factories
    org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
        org.springframework.boot.autoconfigure.admin.SpringApplicationAdminAutoConfiguration,\ 
        org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\ 
        org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,\ 
        ...,
        org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration
  • spring.factories 文件 :位于 META-INF 目录下,包含了 MyBatis 相关的自动配置类,如 org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration

3.4. 自动配置类

  • MybatisAutoConfiguration:这个类是 Spring Boot 为 MyBatis 提供的自动配置类,它负责配置 MyBatis 的核心组件。

  • 条件注解 :该类中的 @Bean 方法通常带有 @Conditional 注解,用来控制自动配置的条件。类上的@ConditionalOnClass 来确认 MyBatis 类的存在,或者使用 @ConditionalOnMissingBean 来避免重复配置。

    java 复制代码
    @Configuration
    @ConditionalOnClass({ SqlSessionFactory.class })
    @EnableConfigurationProperties(MybatisProperties.class)
    @AutoConfigureBefore({ DataSourceAutoConfiguration.class, TransactionManagementAutoConfiguration.class })
    public class MybatisAutoConfiguration {
        // ...
    }

3.5.属性绑定

类上的@EnableConfigurationProperties(MybatisProperties.class)注解用来读取配置信息

java 复制代码
@ConfigurationProperties(
    prefix = "mybatis"
)
public class MybatisProperties {
    ...
}

通过 @ConfigurationProperties 从自 application.propertiesapplication.yml 的配置文件中读取 mybatis.mapper-locations配置信息

3.6.自动配置顺序@AutoConfigureAfter

@AutoConfigureAfter({DataSourceAutoConfiguration.class, MybatisLanguageDriverAutoConfiguration.class})

MybatisAutoConfiguration它依赖于 DataSourceAutoConfigurationMybatisLanguageDriverAutoConfiguration 两个功能, 通过这个注解确保 MybatisAutoConfiguration 在这两个自动配置类之后被加载,以确保 MyBatis 可以正确地使用数据源和语言驱动配置。

其中 DataSourceAutoConfiguration

java 复制代码
@AutoConfiguration(
    before = {SqlInitializationAutoConfiguration.class}
)
@ConditionalOnClass({DataSource.class, EmbeddedDatabaseType.class})
@ConditionalOnMissingBean(
    type = {"io.r2dbc.spi.ConnectionFactory"}
)
@EnableConfigurationProperties({DataSourceProperties.class})
@Import({DataSourcePoolMetadataProvidersConfiguration.class, DataSourceCheckpointRestoreConfiguration.class})
public class DataSourceAutoConfiguration {
	...
}

通过 DataSourceProperties

java 复制代码
@ConfigurationProperties(
    prefix = "spring.datasource"
)
public class DataSourceProperties implements BeanClassLoaderAware, InitializingBean {
	
    ...
    
    private String driverClassName;
    private String url;
    private String username;
    private String password;
    ...
}

读取 spring.datasource.urlspring.datasource.usernamespring.datasource.password,绑定到 MybatisProperties 对象上 Spring Boot 就会自动创建一个数据库连接池。

3.7.注册 Bean

自动配置类通过 @Bean 方法来注册各种 Bean。例如,MybatisAutoConfiguration 会注册 SqlSessionFactorySqlSessionTemplateMapperScannerConfigurer 等 Bean。

  • DataSource :如果未显式配置 DataSource,Spring Boot 会自动创建一个 DataSource 实例。

  • SqlSessionFactoryMybatisAutoConfiguration 会创建 SqlSessionFactory,这是 MyBatis 的核心组件。

  • MapperScannerConfigurer :用于扫描带有 @Mapper 注解的接口,自动生成对应的 Mapper Bean。

  • TransactionManager :如果使用了 JTA 或 DataSource 事务管理器,MybatisAutoConfiguration 也会配置事务管理器。

java 复制代码
@Configuration(
    proxyBeanMethods = false
)
@ConditionalOnClass({SqlSessionFactory.class, SqlSessionFactoryBean.class})
@ConditionalOnSingleCandidate(DataSource.class)
@EnableConfigurationProperties({MybatisProperties.class})
@AutoConfigureAfter({DataSourceAutoConfiguration.class, MybatisLanguageDriverAutoConfiguration.class})
public class MybatisAutoConfiguration implements InitializingBean {

    private final MybatisProperties properties;
    private final DataSource dataSource;

    public MybatisAutoConfiguration(DataSource dataSource, MybatisProperties properties) {
        this.dataSource = dataSource;
        this.properties = properties;
    }

    @Bean
    @ConditionalOnMissingBean
    public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
        SqlSessionFactoryBean factory = new SqlSessionFactoryBean();
        factory.setDataSource(dataSource);
        factory.setTypeAliasesPackage(this.properties.getTypeAliasesPackage());
        // 更多配置...
        return factory.getObject();
    }

    @Bean
    @ConditionalOnMissingBean
    public SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {
        return new SqlSessionTemplate(sqlSessionFactory);
    }

    @Bean
    @ConditionalOnMissingBean
    @ConditionalOnClass({ MapperFactoryBean.class, MapperScannerConfigurer.class })
    public MapperScannerConfigurer mapperScannerConfigurer() {
        MapperScannerConfigurer mapperScannerConfigurer = new MapperScannerConfigurer();
        mapperScannerConfigurer.setSqlSessionFactoryBeanName("sqlSessionFactory");
        mapperScannerConfigurer.setBasePackage(this.properties.getMapperLocations());
        // 更多配置...
        return mapperScannerConfigurer;
    }
}

3.8.应用配置

最终配置:所有的自动配置完成后,Spring Boot 会将所有注册的 Bean 进行依赖注入,从而完成整个应用的初始化过程。

4.总结

Spring Boot 的自动配置过程主要包括以下几个步骤:

  • 通过 @SpringBootApplication 注解启动自动配置。
  • 通过 AutoConfigurationImportSelector 选择并导入自动配置类。
  • 根据条件注解来确定哪些配置类应该被激活。
  • 通过 @Bean 方法注册 Bean 到 Spring 容器中。
  • 通过 @ConfigurationProperties 绑定配置文件中的属性到 Java 对象上。

通过这种方式,Spring Boot 大大简化了设置和配置 Spring 应用的过程,让开发者能够专注于业务逻辑而不是基础设施配置。

相关推荐
尘浮生3 分钟前
Java项目实战II基于微信小程序的电影院买票选座系统(开发文档+数据库+源码)
java·开发语言·数据库·微信小程序·小程序·maven·intellij-idea
郑祎亦26 分钟前
Spring Boot 项目 myblog 整理
spring boot·后端·java-ee·maven·mybatis
不是二师兄的八戒26 分钟前
本地 PHP 和 Java 开发环境 Docker 化与配置开机自启
java·docker·php
爱编程的小生38 分钟前
Easyexcel(2-文件读取)
java·excel
本当迷ya39 分钟前
💖2025年不会Stream流被同事排挤了┭┮﹏┭┮(强烈建议实操)
后端·程序员
带多刺的玫瑰1 小时前
Leecode刷题C语言之统计不是特殊数字的数字数量
java·c语言·算法
计算机毕设指导62 小时前
基于 SpringBoot 的作业管理系统【附源码】
java·vue.js·spring boot·后端·mysql·spring·intellij-idea
Gu Gu Study2 小时前
枚举与lambda表达式,枚举实现单例模式为什么是安全的,lambda表达式与函数式接口的小九九~
java·开发语言
Chris _data2 小时前
二叉树oj题解析
java·数据结构
牙牙7052 小时前
Centos7安装Jenkins脚本一键部署
java·servlet·jenkins