Yang's blog Yang's blog
首页
后端开发
密码学
机器学习
命令手册
关于
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

xiaoyang

尽人事,听天命
首页
后端开发
密码学
机器学习
命令手册
关于
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • SpringCloud

    • 微服务架构介绍
    • SpringCloud介绍
    • Spring Cloud:生产者与消费者
    • Spring Cloud Eureka:构建可靠的服务注册与发现
    • Spring Cloud Ribbon:负载均衡
    • Spring Cloud Fegin:服务调用
    • Spring Cloud Hystrix:熔断器
    • Spring Cloud Zuul:统一网关路由
    • Spring Cloud Config:配置中心
  • Java后端框架

    • LangChain4j

      • 介绍
      • 快速开始
      • Chat and Language Models
      • Chat Memory
      • Model Parameters
      • Response Streaming
      • AI Services
      • Agent
      • Tools (Function Calling)
      • RAG
      • Structured Outputs
      • Classification
      • Embedding (Vector) Stores
      • Image Models
      • Quarkus Integration
      • Spring Boot Integration
      • Kotlin Support
      • Logging
      • Observability
      • Testing and Evaluation
      • Model Context Protocol
    • SpringBoot

      • SpringBoot-核心介绍
  • 八股文

    • 操作系统
    • JVM介绍
    • Java多线程
    • Java集合框架
    • Java反射
    • JavaIO
    • Mybatis介绍
    • Spring介绍
    • SpringBoot介绍
      • Spring Boot 是什么?
      • Spring 和 Spring Boot 的区别
      • Spring Boot 启动流程
      • SPI机制
        • spi和api有什么区别
        • JDBC例子
        • 1. Java 定义接口(SPI 接口)
        • 2. 数据库厂商实现接口
        • 3. 在 META-INF/services 中声明实现类
        • 4. Java 通过 ServiceLoader 自动加载实现
        • 这样 JDBC 就实现了完全解耦
      • SpringBoot自动装配
        • 1. 自动装配出发点
        • 2. 核心执行者
        • 3. 加载逻辑
        • 4. 条件筛选机制
        • 5. 加载与注册
      • Spring Boot 适合用在哪些场景?
      • 总结
    • Mysql
    • Redis
    • 数据结构
    • 云计算
    • 设计模式
    • 计算机网络
    • 锁核心类AQS
    • Nginx
    • 面试场景题
  • 前端技术

    • 初识Vue3
    • Vue3数据双向绑定
    • Vue3生命周期
    • Vue-Router 组件
    • Pinia 集中式状态存储
  • 中间件

    • RocketMQ
  • 源码分析

    • 线程池源码解析
    • Redisson源码分析
  • 开发知识

    • 请求参数注解
    • 时间复杂度和空间复杂度
    • JSON序列化与反序列化
    • Timestamp vs Datetime
    • Java开发中必备能力单元测试
    • 正向代理和反向代理
    • 什么是VPN
    • 后端服务端主动推送消息的常见方式
    • 正则表达式
    • SseEmitter vs Flux 的本质区别与底层原理解析
    • Function Calling与MCP区别
    • 分布式事务
  • 后端开发
  • 八股文
xiaoyang
2025-02-18
目录

SpringBoot介绍

# SpringBoot介绍

# Spring Boot 是什么?

Spring Boot 是 Spring 框架的一个子项目,它主要用于简化 Spring 应用的开发,提供了一整套开箱即用的功能,比如:

  • 内嵌 Web 服务器(如 Tomcat、Jetty、Undertow)
  • 自动配置(AutoConfiguration)
  • 约定优于配置(Convention over Configuration,框架默认帮你做好合理选择,你只要按它建议的方式写代码,就不用写额外配置。)
  • 无 XML 配置(几乎不需要 applicationContext.xml)
  • Starter 依赖管理(简化 pom.xml)

一句话总结:Spring Boot 让 Spring 开发更简单、更快速,避免大量的 XML 配置,开箱即用!


# Spring 和 Spring Boot 的区别

特性 Spring Spring Boot
需要的配置 需要手动配置(XML/Java) 约定优于配置,自动装配
Web 服务器 需要手动配置 Tomcat、Jetty 内嵌 Tomcat,开箱即用
依赖管理 依赖版本需要手动维护 Starter 依赖自动管理
开发效率 配置复杂,开发慢 简单易用,开发快
微服务支持 需要自己搭建 天然支持微服务

# Spring Boot 启动流程

当调用 SpringApplication.run(...) 时,Spring Boot 会执行一系列自动配置:

  1. 创建 SpringApplication 对象
  2. 自动推断应用类型(Servlet / Reactive / None)
  3. 加载 ApplicationContext
  4. 执行 @SpringBootApplication 扫描并加载 Bean
  5. 加载 spring.factories 进行自动配置
  6. 启动 Web 服务器(Tomcat/Jetty)
  7. 初始化 CommandLineRunner / ApplicationRunner

# SPI机制

SJava SPI(Service Provider Interface),字面意思就是:“服务提供者的接口”,我的理解是:专门提供给服务提供者或者扩展框架功能的开发者去使用的一个接口。它的核心思想是:

接口由框架或核心模块定义,实现由第三方提供,通过约定的配置文件完成解耦与加载。

博主讲的很好,原文链接:https://javaguide.cn/java/basis/spi.html

# spi和api有什么区别

SPI 和 API 的区别,本质是 调用方向(调用控制权)不同,从广义上来说它们都属于接口,而且很容易混淆。下面先用一张图说明一下:

image-20260303103329963

一般模块之间都是通过接口进行通讯,因此我们在服务调用方和服务实现方(也称服务提供者)之间引入一个“接口”。

  • 当实现方提供了接口和实现,我们可以通过调用实现方的接口从而拥有实现方给我们提供的能力,这就是 API。这种情况下,接口和实现都是放在实现方的包中。调用方通过接口调用实现方的功能,而不需要关心具体的实现细节。
  • 当接口存在于调用方这边时,这就是 SPI 。由接口调用方确定接口规则,然后由不同的厂商根据这个规则对这个接口进行实现,从而提供服务。

举个通俗易懂的例子:公司 H 是一家科技公司,新设计了一款芯片,然后现在需要量产了,而市面上有好几家芯片制造业公司,这个时候,只要 H 公司指定好了这芯片生产的标准(定义好了接口标准),那么这些合作的芯片公司(服务提供者)就按照标准交付自家特色的芯片(提供不同方案的实现,但是给出来的结果是一样的)。

# JDBC例子

在 Java Database Connectivity(JDBC) 中,Java 官方只定义了一套 数据库访问接口规范,例如:

  • java.sql.Driver
  • Connection
  • Statement
  • ResultSet

这些接口只是 标准规范,真正的实现由各个数据库厂商提供,比如:

  • MySQL Connector/J
  • PostgreSQL JDBC Driver
  • Oracle JDBC Driver

这些驱动就是 SPI 的实现者(Service Provider)。大致流程是这样的:

# 1. Java 定义接口(SPI 接口)

Java 在 java.sql 包中定义接口:

public interface Driver {
    Connection connect(String url, Properties info) throws SQLException;
}
1
2
3

这一步是 框架定义规范。


# 2. 数据库厂商实现接口

例如 MySQL 驱动实现:

public class com.mysql.cj.jdbc.Driver implements java.sql.Driver
1

这一步是 服务提供者实现接口。


# 3. 在 META-INF/services 中声明实现类

SPI 通过配置文件告诉 JVM 有哪些实现。

文件:

META-INF/services/java.sql.Driver
1

内容:

com.mysql.cj.jdbc.Driver
1

# 4. Java 通过 ServiceLoader 自动加载实现

JDK 使用 ServiceLoader 加载这些实现:

ServiceLoader<Driver> loadedDrivers = ServiceLoader.load(Driver.class);
1

JVM 会自动:

  1. 扫描 classpath
  2. 找到 META-INF/services/java.sql.Driver
  3. 加载对应实现类

# 这样 JDBC 就实现了完全解耦

调用代码:

Connection conn = DriverManager.getConnection(url, user, password);
1

你的代码只依赖:

  • JDBC 接口
  • 不依赖具体数据库

换数据库只需要:

  • 替换 JDBC driver jar

代码完全不用改。

# SpringBoot自动装配

自动装配的核心目标 自动装配的本质是:根据类路径下的依赖、自定义配置和默认规则,自动向 Spring 容器中注册所需的 Bean,并完成依赖注入。 例如,当引入 spring-boot-starter-web 依赖时,Spring Boot 会自动配置 Tomcat 容器、DispatcherServlet、WebMvc 相关组件等,无需手动编写 XML 或 @Bean 配置。

# 1. 自动装配出发点

首先我们的SpringBoot程序的启动类会有一个@SrpingBootApplication注解,该注解我等价于@SpringBootConfiguration、@ComponentScan、@EnableAutoConfiguration。

Spring Boot 的自动装配从这个@EnableAutoConfiguration注解正式启动。

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
}
1
2
3
4
5
6
7
8

可以看到:

  • 它通过 @Import(AutoConfigurationImportSelector.class) 把 AutoConfigurationImportSelector 这个核心类导入容器;
  • 从而触发自动配置类的加载逻辑。

# 2. 核心执行者

Spring Boot 启动时,会扫描 @EnableAutoConfiguration,从而加载并执行 AutoConfigurationImportSelector 的 selectImports() 方法,这里是真正决定哪些自动配置类会被加载的关键步骤。

核心方法如下(伪简化):

@Override
public String[] selectImports(AnnotationMetadata metadata) {
    // 1. 判断是否开启自动配置
    if (!isEnabled(metadata)) {
        return NO_IMPORTS;
    }

    // 2. 加载所有候选配置类(从 spring.factories 或 AutoConfiguration.imports)
    AutoConfigurationEntry autoConfigurationEntry =
        getAutoConfigurationEntry(metadata);

    // 3. 返回最终需要导入的类名数组
    return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14

继续看 getAutoConfigurationEntry():

protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata metadata) {
    // 1. 从 spring.factories 加载所有候选类
    List<String> configurations = getCandidateConfigurations(metadata, attributes);

    // 2. 去重
    configurations = removeDuplicates(configurations);

    // 3. 通过条件过滤掉不符合条件的自动配置类
    configurations = filter(configurations, autoConfigurationMetadata);

    // 4. 处理 @AutoConfigureBefore / @After 排序
    configurations = sort(configurations);

    // 5. 返回最终结果
    return new AutoConfigurationEntry(configurations);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

所以这个类做了三件事:

  1. 读取候选自动配置类;
  2. 条件过滤;
  3. 排序后返回。

# 3. 加载逻辑

Spring Boot 2.x 和 3.x 的机制略有差别:

版本 文件位置 示例
Spring Boot 2.x META-INF/spring.factories org.springframework.boot.autoconfigure.EnableAutoConfiguration=\``org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration,\``org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
Spring Boot 3.x META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports 每行一个类:org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration

源码

protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
    return SpringFactoriesLoader.loadFactoryNames(
        getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader());
}
1
2
3
4

SpringFactoriesLoader.loadFactoryNames() 方法会从 classpath 下读取所有的 spring.factories 文件,并返回 EnableAutoConfiguration 对应的所有类名。


# 4. 条件筛选机制

这部分由 ConfigurationClassPostProcessor 结合 ConditionEvaluator 来实现。

自动配置类在被加载之前,会根据 @Conditional 系列注解(如 @ConditionalOnClass, @ConditionalOnBean, @ConditionalOnProperty 等)进行过滤。

关键逻辑在 ConditionEvaluator#shouldSkip():

public boolean shouldSkip(AnnotatedTypeMetadata metadata) {
    if (metadata.isAnnotated(Conditional.class.getName())) {
        Condition[] conditions = getConditions(metadata);
        for (Condition condition : conditions) {
            if (!condition.matches(context, metadata)) {
                return true; // 不满足条件则跳过
            }
        }
    }
    return false;
}
1
2
3
4
5
6
7
8
9
10
11

比如:

  • @ConditionalOnClass → 检查 classpath 是否存在指定类;
  • @ConditionalOnMissingBean → 检查容器中是否已经注册了指定 Bean;
  • @ConditionalOnProperty → 检查 application.yml 中对应的 key/value 是否存在。

# 5. 加载与注册

经过筛选后的自动配置类,会在 BeanDefinition 阶段由 ConfigurationClassPostProcessor 解析并注册 Bean。

流程如下:

  1. ConfigurationClassPostProcessor 扫描 @Configuration 类;
  2. 对每个类执行:
    • 解析 @Import;
    • 解析 @Bean 方法;
    • 注册到 BeanDefinitionRegistry;
  3. Spring 容器在后续阶段实例化 Bean 并完成依赖注入。

# Spring Boot 适合用在哪些场景?

  1. Web 应用
    • 快速开发 RESTful API
    • 传统 Web MVC 应用
  2. 微服务架构
    • 天然支持 Spring Cloud
    • 简单搭建分布式服务
  3. 任务调度 / 定时任务
    • 支持 @Scheduled
  4. 数据处理
    • 与 Spring Data JPA、MyBatis 无缝集成
  5. 企业级应用
    • 快速搭建企业管理系统、后台管理系统

# 总结

  • Spring Boot = Spring + 简单易用
  • 自动配置,减少 XML 和 Java 配置代码
  • 内置 Web 服务器,直接运行,不需要部署
  • Starter 依赖,简化依赖管理
  • 微服务天然支持,和 Spring Cloud 结合强大
  • 统一配置,使用 application.yml 进行全局管理

一句话总结:Spring Boot 让 Spring 开发更简单、更高效! 🚀

编辑 (opens new window)
上次更新: 2026/03/09, 11:21:12

← Spring介绍 Mysql→

最近更新
01
SpringBoot-核心介绍
11-13
02
Redisson源码分析
11-13
03
线程池源码解析
10-31
更多文章>
Theme by Vdoing | Copyright © 2023-2026 xiaoyang | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式