Skip to content

Spring Boot 从零到生产级学习总览

Spring Boot 不是一个替代 Spring 的新容器,也不是“加一个注解就会自动写业务代码”的魔法框架。它仍以 Spring IoC 容器为核心,只是在 Spring 之上补齐了依赖版本管理、约定式配置、条件化自动配置、可执行应用、内嵌 Web 容器、生产监控等工程能力。

学完本专栏后,你不应只会创建 Controller,而应能从 main 方法一直解释到端口开始监听,并能回答下面这些问题:

  1. SpringApplication.run() 为什么能启动一个完整 Web 服务?
  2. @SpringBootApplication 展开后包含什么,分别在哪个阶段生效?
  3. 引入一个 Starter 后,Bean 为什么会自动出现在容器中?
  4. 自动配置候选类从哪里来,条件注解何时判断,用户 Bean 为什么能让默认 Bean 退让?
  5. application.yml、环境变量和命令行参数冲突时,最终值从哪里来?
  6. 内嵌 Tomcat 在什么时候创建,HTTP 请求怎样进入 Controller?
  7. 应用启动慢、自动配置不生效、端口未监听、配置未绑定时,从哪里开始排查?
  8. Boot 2.7/JDK 8 和 Boot 3/Java 17 的边界是什么,老项目为什么不能照抄新项目代码?

一、学习目标与验收标准

层次你需要做到什么只会表面时的典型表现
入门能创建 Boot 2.7/JDK 8 项目并写出一个接口只会复制脚手架,不知道注解作用
原理能讲清启动、配置、自动配置、Starter 和容器刷新链路只会背“约定优于配置”
工程能正确分层、校验参数、处理异常、管理配置与日志业务逻辑全部堆在 Controller
生产能接入健康检查、指标、优雅停机和启动诊断线上出错只会重启服务
扩展能根据生命周期阶段选择正确扩展点所有初始化逻辑都放 @PostConstruct
兼容能区分 Boot 2/3、JDK 8/17、javax/jakarta复制代码后大量包名或字节码错误

完成全部学习后,用从零到精通验收清单逐项验收,而不是用“页面看完了”代替“真正掌握了”。

二、正确学习路线

mermaid
flowchart TD
    A["Java 与 Maven 基础"] --> B["Spring IoC 和 Bean 生命周期"]
    B --> C["Spring Boot 基础应用"]
    C --> D["SpringApplication 启动流程"]
    D --> E["Environment 与配置绑定"]
    E --> F["自动配置与条件注解"]
    F --> G["Starter 与扩展点"]
    G --> H["Web 请求与工程分层"]
    H --> I["Actuator 与生产排查"]
    I --> J["商业场景和面试验收"]

建议按下面顺序阅读:

  1. 基础入门:认识启动类、Bean、Controller 和基本注解。
  2. 启动流程全过程:从 SpringApplicationApplicationReadyEvent
  3. 配置体系全过程:从配置源到 EnvironmentBinder 和属性对象。
  4. 自动配置原理:候选类发现、条件判断、BeanDefinition 注册和失败诊断。
  5. Starter 全过程:依赖聚合、autoconfigure 模块和商业公共能力封装。
  6. 扩展点:按启动阶段选择 Environment、容器、Bean、Web 和监控扩展点。
  7. Web 项目工程实践:请求链路、分层、校验、异常和统一响应。
  8. Actuator 监控:健康检查、指标、启动分析、线程栈和安全边界。
  9. 生产监控与线上问题排查:日志、指标、Trace、告警、JVM、容器和典型故障 Runbook。
  10. Spring Boot Admin:集中展示多个实例的 Actuator 信息、接入方式与安全边界。
  11. 商业场景训练营:将知识组合到订单、采集和客户端 Starter 场景。
  12. 面试题:标准回答、追问和对应原理锚点。

短页面用于第一次建立概念,带“全过程”的页面负责深入原理。不要在浅页面背完一句定义后就跳去面试页。

三、Spring、Spring MVC 与 Spring Boot 到底是什么关系

技术主要职责Spring Boot 是否替代它
Spring FrameworkIoC、依赖注入、AOP、事务、事件、资源与扩展点不替代,Boot 内部仍使用它
Spring MVCServlet Web 请求分发、参数解析、Controller 调用、响应转换不替代,starter-web 默认装配它
Spring Boot依赖管理、自动配置、启动封装、内嵌服务器、生产运维在前两者之上做工程化整合
Spring Cloud注册发现、配置中心、网关、调用和容错等分布式能力不属于 Boot 核心,通常基于 Boot 构建

可以把关系理解成:

mermaid
flowchart TD
    A["业务代码"] --> B["Spring Boot 工程约定与自动配置"]
    B --> C["Spring MVC Web 请求体系"]
    B --> D["Spring IoC、AOP、事务与事件"]
    C --> D
    D --> E["JDK、Servlet 容器和第三方库"]

如果没有 Spring Boot,你仍可直接使用 Spring Framework,但需要自己选择依赖版本、创建 Web 容器、注册 DispatcherServlet、配置 JSON 转换器、数据源和监控。Boot 的价值不是改变这些原理,而是把成熟的默认组合编码成可覆盖的自动配置。

四、Spring Boot 解决了什么问题

4.1 依赖版本难以协调

传统项目可能分别声明 Spring、Jackson、Tomcat、日志组件版本。版本不兼容时会出现 NoSuchMethodErrorClassNotFoundException。Boot 的依赖管理提供一组经过兼容性验证的版本组合。

但要注意:Starter 负责“引入哪些依赖”,依赖管理负责“这些依赖默认用什么版本”,自动配置负责“类路径和配置满足条件后创建哪些 Bean”。这三件事不是同一个概念。

4.2 重复配置太多

绝大多数 Servlet 项目都需要 Web 容器、DispatcherServlet、消息转换器、异常处理基础设施。Boot 根据 classpath、配置属性、应用类型和已有 BeanDefinition 判断是否提供默认实现。

4.3 部署依赖外部容器

Boot 可以将应用打成可执行 Jar,并在同一个 JVM 中创建内嵌 Tomcat、Jetty 或 Undertow。Jar 并不是“自己实现了 HTTP”,而是把服务器依赖和应用一起打包,由启动流程创建 WebServer。

4.4 缺少统一生产入口

Actuator 为健康检查、指标、配置诊断、线程栈和日志级别提供统一端点。它不是完整监控平台:通常还要配合 Prometheus、Grafana、日志平台和链路追踪系统。

五、Spring Boot 不会替你做什么

  1. 不会自动设计领域模型、事务边界和幂等方案。
  2. 不会因为使用了 Starter 就消除慢 SQL、线程池耗尽和缓存一致性问题。
  3. 不会自动保证配置安全;密钥写进 Git 仍会泄露。
  4. 不会让所有依赖版本任意混搭;越过 Boot BOM 强行升级仍可能冲突。
  5. 不会让 Bean 天生线程安全;单例 Service 的可变字段仍可能发生并发问题。
  6. 不会让 @Transactional 在自调用、非代理对象或错误异常规则下必然生效。

“自动配置”只是在条件满足时注册一套默认 Bean,不等于自动完成业务设计。

六、版本边界:JDK 8存量线与Java 17+现代线并行学习

本知识库同时维护两条完整学习线:基础页以 JDK 8 + Boot 2.7 帮助读者理解大量企业存量系统;现代版本专题系统讲解 Java 17+ + Boot 3.x。二者都会说明原理和可运行 Demo,不会把现代技术只缩成一张差异表。

组合最低要求与定位代码差异重点
JDK 7 + 早期 Spring/Boot只能用于理解历史项目;Spring Boot 1.x 曾支持部分 JDK 7 场景无 Lambda、默认方法、java.time,现在不建议新建
JDK 8 + Boot 2.7.x重要存量基线;Boot 2.7 支持 Java 8javax.servletjavax.validationjavax.annotation
JDK 11/17 + Boot 2.7.x存量系统升级 JDK 的过渡组合仍使用 javax 生态,关注模块和反射限制
Java 17+ + Boot 3.x当前新项目主线之一Spring 6、Jakarta EE 9,包名迁移为 jakarta.*
Java 21 + 新版 Boot 3.x可使用虚拟线程等新能力不是所有旧中间件、Agent、驱动都天然兼容

最常见迁移错误:

java
// Boot 2.7 / Spring 5 常见写法
import javax.validation.constraints.NotBlank;
import javax.servlet.Filter;

// Boot 3 / Spring 6 对应写法
import jakarta.validation.constraints.NotBlank;
import jakarta.servlet.Filter;

这不是 IDE 自动导包的小问题,而是 Jakarta EE 命名空间迁移。只改一个 import 往往不够,Servlet 容器、验证器、JPA 和第三方依赖都必须使用相容版本。

完整版本边界、Spring Framework 6、Jakarta 二进制不兼容、Security 6、Observability、AOT、Cloud 版本矩阵和迁移 Runbook,请阅读 Java 17+ 与 Spring Boot 3.x

七、第一个可运行 Demo:JDK 8 + Spring Boot 2.7

7.1 Maven 配置

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.7.18</version>
        <relativePath/>
    </parent>

    <groupId>com.example</groupId>
    <artifactId>boot-first-demo</artifactId>
    <version>1.0.0</version>

    <properties>
        <java.version>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>

7.2 启动类

java
package com.example.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

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

启动类应放在业务根包,例如 com.example.demo。默认组件扫描从启动类所在包向下进行;如果启动类放在 com.example.demo.bootstrap,位于 com.example.demo.order 的组件可能扫描不到。

7.3 Controller

java
package com.example.demo.web;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class GreetingController {

    @GetMapping("/api/greeting")
    public Greeting greeting(@RequestParam(defaultValue = "beginner") String name) {
        return new Greeting("hello, " + name);
    }

    public static class Greeting {
        private final String message;

        public Greeting(String message) {
            this.message = message;
        }

        public String getMessage() {
            return message;
        }
    }
}

运行:

bash
mvn spring-boot:run

访问:

text
GET http://localhost:8080/api/greeting?name=Java8

预期响应:

json
{"message":"hello, Java8"}

这里发生的事情远不止“调用一个 Java 方法”:Tomcat 读取 HTTP 字节,Filter 链放行请求,DispatcherServlet 选择处理器,参数解析器读取 name,Controller 返回对象,Jackson 消息转换器将对象序列化为 JSON。

八、SpringApplication.run() 总体过程

mermaid
flowchart TD
    A["main 调用 SpringApplication.run"] --> B["创建 SpringApplication"]
    B --> C["推断 WebApplicationType"]
    C --> D["准备监听器、Environment 和 Profile"]
    D --> E["创建 ApplicationContext"]
    E --> F["加载启动类并解析自动配置"]
    F --> G["refresh 刷新 Spring 容器"]
    G --> H["创建单例 Bean 和代理"]
    H --> I["创建并启动内嵌 WebServer"]
    I --> J["执行 Runner 并发布就绪事件"]

每一步都解决不同问题:

阶段输入核心输出失败时常见现象
创建 SpringApplication主启动类、classpath应用类型、初始化器和监听器Web 类型判断与预期不同
准备 Environment文件、环境变量、命令行最终配置视图和激活 Profile端口、数据源或开关值错误
创建 ApplicationContextWeb 应用类型对应的 Spring 容器实现容器类型或 Web 栈不匹配
加载 BeanDefinition扫描、导入、自动配置Bean 的定义,不一定已有实例Bean 未注册、条件不匹配
refresh()BeanDefinitionBean、代理、事件系统、WebServer循环依赖、创建异常、端口冲突
Runner 与就绪事件已刷新容器初始化结果和可接流量状态启动很慢或就绪过早

完整源码链和断点位置见启动流程全过程

九、自动配置为什么不是“扫描到什么就配什么”

以 Boot 2.7 为例,核心链路可以简化为:

mermaid
flowchart TD
    A["@SpringBootApplication"] --> B["@EnableAutoConfiguration"]
    B --> C["AutoConfigurationImportSelector"]
    C --> D["读取自动配置候选名单"]
    D --> E["处理 exclude、去重和排序"]
    E --> F["条件注解判断 classpath、属性和 Bean"]
    F --> G{"条件是否满足"}
    G -- "否" --> H["记录未匹配原因并跳过"]
    G -- "是" --> I["注册配置类和 BeanDefinition"]
    I --> J["refresh 阶段创建真正 Bean"]

必须分清三个时间点:

  1. 找到候选自动配置类,不代表它一定生效。
  2. 条件满足并注册 BeanDefinition,不代表对象已经实例化。
  3. Bean 在 refresh() 中创建成功,才代表能力真正可用。

例如 DataSourceAutoConfiguration 在 classpath 缺 JDBC 类、配置缺失、已有用户 Bean 或被显式排除时,结果都可能不同。使用 debug=true/actuator/conditions 可以看到匹配原因,而不是靠猜。

详细条件判断时机、Boot 2/3 声明文件与自定义自动配置 Demo 见自动配置原理

十、Starter、自动配置和 Bean 的关系

mermaid
flowchart TD
    A["业务项目引入 starter"] --> B["Maven 带入 SDK 和 autoconfigure"]
    B --> C["Boot 发现自动配置声明"]
    C --> D["条件注解决定是否注册默认 Bean"]
    D --> E["业务代码注入并使用 Bean"]
模块推荐职责不应该做什么
SDK纯 Java 客户端、接口和模型依赖完整 Boot 应用上下文
autoconfigure属性类、条件、默认 Bean、健康检查和失败分析塞入具体业务订单规则
starter聚合依赖,提供一个清晰入口把所有实现代码堆在 starter 中
业务应用提供实际配置,必要时覆盖默认 Bean修改公共组件源码才能使用

如果业务方声明了自己的同类型 Bean,公共自动配置常借助 @ConditionalOnMissingBean 退让。这体现的是“合理默认值 + 用户可覆盖”,不是 Bean 被随机覆盖。

完整商业客户端 Starter Demo 见Starter 全过程

十一、一次 HTTP 请求怎样穿过 Spring Boot

mermaid
flowchart TD
    A["客户端发送 HTTP 请求"] --> B["Tomcat Connector 接收字节"]
    B --> C["Servlet Filter 链"]
    C --> D["DispatcherServlet"]
    D --> E["HandlerMapping 查找 Controller"]
    E --> F["HandlerAdapter 与参数解析器"]
    F --> G["Controller 参数校验和协议转换"]
    G --> H["Service 执行业务和事务"]
    H --> I["Mapper、Redis、MQ 或下游服务"]
    I --> J["返回值处理与 Jackson 序列化"]
    J --> K["Tomcat 写回 HTTP 响应"]

Controller 只负责协议层工作:接收参数、触发校验、调用 Service、转换响应。事务边界和业务编排应放在 Service;数据访问放在 Mapper/Repository。否则常见后果包括事务失效、代码无法复用、异常处理重复和测试困难。

完整工程分层和错误示例见Web 项目工程实践,MVC 内部细节见Spring MVC 请求执行链

十二、商业场景:医疗数据采集服务如何使用 Boot

假设服务需要定时从医院接口拉取数据、校验、落库并发送 MQ:

mermaid
flowchart TD
    A["Boot 加载医院连接配置"] --> B["自动配置创建采集客户端"]
    B --> C["健康检查验证必要依赖"]
    C --> D["调度器触发采集批次"]
    D --> E["Service 编排校验和事务"]
    E --> F["数据库保存批次与数据"]
    F --> G["提交后发送消息或写本地消息表"]
    G --> H["Actuator 暴露健康与业务指标"]

这里 Boot 适合承担:

  • 将医院地址、超时、重试和开关绑定到类型安全的配置对象;
  • 通过 Starter 为不同服务提供统一客户端、健康检查和指标;
  • 通过条件注解决定某个医院适配器是否启用;
  • 通过 Actuator 和 Micrometer暴露成功率、耗时和待处理批次数;
  • 通过优雅停机停止接收新任务并等待在途任务收口。

Boot 不负责替你决定“数据库事务与消息怎样保证一致”“重复数据如何幂等”“重试是否会压垮医院接口”。这些需要分布式事务、消息可靠性、限流和幂等知识共同完成。

十三、生产问题从哪里开始排查

13.1 应用启动失败

  1. 先找日志中最早的根异常,不要只看最后一层 Application run failed
  2. 判断失败发生在 Environment、BeanDefinition、Bean 创建、WebServer 还是 Runner 阶段。
  3. 配置绑定失败看属性名、最终配置源、类型转换和校验信息。
  4. Bean 创建失败沿 Caused by 找构造器、注入、初始化方法或代理异常。
  5. 端口问题检查 BindException、监听端口和容器网络映射。

13.2 自动配置没有生效

bash
java -jar app.jar --debug

按下面顺序检查:

  1. Starter 是否真正进入运行时 classpath。
  2. 自动配置声明文件路径和类名是否正确。
  3. 目标自动配置是否在条件报告中出现。
  4. 是否被 exclude 排除。
  5. @ConditionalOnClass@ConditionalOnProperty 等条件为何不满足。
  6. 是否因为已有用户 Bean,触发了 @ConditionalOnMissingBean 退让。
  7. BeanDefinition 已注册后,是否又在 Bean 创建或配置绑定阶段失败。

13.3 应用启动成功但接口不通

依次确认:端口是否监听、容器端口是否映射、上下文路径是否正确、Controller 是否被扫描、请求方法和路径是否匹配、Filter/Security 是否拦截、网关和反向代理是否转发到正确实例。

13.4 应用启动慢

重点检查 Bean 构造器、@PostConstruct、初始化方法、数据源连接、配置中心、类扫描、Runner 和外部系统调用。不要在 Bean 创建阶段做没有超时的网络请求;否则一个外部系统不可用就可能让整个服务无法启动。

具体端点和指标见Actuator 监控,CPU、内存、线程池、连接池、数据库和容器等完整 Runbook 见生产监控与线上问题排查

十四、常见错误,以及为什么会错

错误为什么会出问题正确方向
启动类放在业务子包默认扫描范围变窄,部分 Bean 不会注册启动类放根包或显式配置扫描范围
在构造器中请求外部接口Bean 创建被网络阻塞,容器无法完成刷新使用可超时、可观测的启动后预热
在 Runner 中解密配置Runner 执行时配置绑定和自动配置已经结束使用更早的配置扩展机制或外部 Secret 系统
所有配置都用 @Value分散、无结构、类型与校验能力弱一组业务配置使用 @ConfigurationProperties
看到 Bean 不存在就立刻手写配置可能只是条件不满足或被用户 Bean 顶掉先看 conditions 报告和 Bean 创建异常
暴露全部 Actuator 端点可能泄露环境变量、配置、线程栈和堆数据最小暴露、内网访问、鉴权和脱敏
Boot 2 项目复制 Boot 3 importjavaxjakarta 类型不兼容先确认版本矩阵,再选择示例代码

十五、面试标准回答

问:Spring Boot 的核心原理是什么?

Spring Boot 仍然以 Spring IoC 容器为核心。SpringApplication.run() 先推断应用类型并准备 Environment,再创建 ApplicationContext;@SpringBootApplication 触发组件扫描和自动配置导入,Boot 从声明文件读取候选自动配置类,经过排除、排序和条件注解判断后注册 BeanDefinition;容器在 refresh() 阶段执行后置处理器、创建单例 Bean 和代理。Servlet Web 应用还会在刷新过程中通过 ServletWebServerFactory 创建内嵌 Tomcat。最后执行 Runner、发布就绪事件。Starter 负责带入依赖和自动配置模块,用户 Bean 可以通过 @ConditionalOnMissingBean 机制覆盖默认实现。

追问时应继续展开:

  • @SpringBootApplication 的三个核心组成;
  • Boot 2.6及更早、Boot 2.7过渡机制与 Boot 3 AutoConfiguration.imports
  • 条件判断与 Bean 创建不是同一阶段;
  • 自动配置排序不等于 Bean 实例化顺序;
  • Environment、配置绑定和最终属性来源;
  • refresh() 与内嵌 Tomcat 创建时机;
  • 自动配置未生效的 conditions 排查方法。

更多标准回答放在Spring Boot 面试题,每个回答应回到对应原理页理解,不能只背这一段。

十六、问题到知识点的快速跳转

你遇到的问题应阅读的页面
不知道JDK 8/17、Boot 2/3如何选择和迁移Java 17+与Spring Boot 3.x
不知道 run() 做了什么启动流程全过程
不知道某个配置最终取了哪个值配置体系全过程
Bean 没有被自动创建自动配置原理
想把公共客户端做成开箱即用组件Starter 全过程
不知道该选 Runner、BPP、Filter 还是 InterceptorSpring Boot 扩展点
Controller、Service、Mapper 职责混乱Web 项目工程实践
要做健康检查、指标或线程诊断Actuator 监控
线上接口慢、CPU高、OOM、连接池耗尽怎么处理生产监控与线上问题排查
想集中查看和管理多个Spring Boot实例Spring Boot Admin
要练完整商业组合场景商业场景训练营
要检查自己是否真正掌握从零到精通验收清单
要准备面试标准回答面试题

本章小结

Spring Boot 的本质可以归纳为一条完整链路:

依赖管理提供兼容版本,Starter 把场景依赖带入 classpath,启动流程准备配置和容器,自动配置根据条件注册默认 Bean,Spring refresh() 创建 Bean 与代理,WebServer 开始监听端口,Actuator 提供生产可观测入口;业务代码仍需自己设计分层、事务、一致性、并发和失败处理。

当你能解释这条链路中每一步的输入、输出、时机和失败现象时,才算真正理解 Spring Boot,而不只是会使用脚手架。