十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

SpringBoot入门:自动配置、Starter与启动原理

SpringBoot入门:自动配置、Starter与启动原理 我第一次用 IDEA 创建 SpringBoot 项目时心里冒出一个很直接的问题项目刚创建出来一行业务代码都没写为什么点击启动后控制台马上出现“Tomcat started on port(s): 8080”浏览器访问 localhost:8080 甚至能出现响应是谁提前启动了 Tomcat是谁配置好了 Spring MVC 的核心组件如果这一切都要自己完成到底要写多少配置和代码后来我才理解SpringBoot 真正做的事不是帮你“省掉几行配置”而是把“把一个 Java Web 项目从零启动到可访问”这件事从一堆依赖经验、依赖手工决策的重复劳动压缩成了默认约定加按需覆盖。第一节最该建立的不是注解清单不是面试题答案而是一个心智模型SpringBoot 到底是谁、它替你做了什么、它为什么值得用。这个心智模型一旦建立后面无论是看自动配置源码、处理事务失效、排查循环依赖还是把项目打包成镜像部署都有了方向感。1. SpringBoot 是什么先搞清楚它不是替代品而是一个“启动器 约定”很多第一次接触 SpringBoot 的人会把它理解成“一个新的 Web 框架”。这个理解不算全错但会干扰后续学习。SpringBoot 没有重新发明一套 Web 开发模型也没有替代 Spring Framework它更像是给 Spring 生态装了一个“一键启动器”。1.1 从“空项目为什么会响应 HTTP 请求”说起当你创建一个 SpringBoot 项目引入一个spring-boot-starter-web依赖写完一个带SpringBootApplication的启动类点击运行后一个内嵌的 Tomcat 就被启动起来了。你甚至不需要去下载 Tomcat 解压包不需要把它装到 IDE 里不需要在 web.xml 里配置DispatcherServlet。对一个刚从 SSM 学习阶段过来的人来说这几乎像变魔术。但魔术的真相是SpringBoot 不是没有做这些配置而是在你看不到的地方用“自动配置”帮你做了。它读到了类路径下有spring-webmvc相关类于是判定“这是一个 Spring MVC 项目”自动创建了DispatcherServlet它发现有内嵌 Tomcat 的存在于是自动启动了 Web 容器。这些动作不是通过你写代码完成的而是通过一堆条件判断自动装配出来的。1.2 SpringBoot 与 Spring Framework 的边界这里需要先把边界说清楚Spring Framework 是核心它提供 IoC 容器、AOP、事务抽象、Spring MVC 等基础能力。SpringBoot 不是要替换这些而是在 Spring Framework 之上提供一套更快的组装方式。可以这样理解Spring Framework 就像一套积木它提供了零件和接口SpringBoot 则是预制好的模块组合说明书外加一个自动装配机器人。你依然是在用积木但不再需要每次从零决定“这个功能需要哪几个零件”“它们怎么拼”。所以面试里如果问“SpringBoot 和 Spring 是什么关系”重点不是背定义而是说清楚SpringBoot 基于 Spring Framework它通过自动配置和 starter 依赖降低了 Spring 项目的搭建成本但运行时底层仍然是 Spring 容器在发挥作用。1.3 它真正降低的是决策成本很多人以为 SpringBoot 的价值是“快”。其实快只是结果真正被改变的是决策成本。以前搭一个 Spring MVC 项目你要决定用哪个版本的 Spring用哪个版本的 Tomcat用哪个 JSON 库用哪个连接池各种库之间的版本是否兼容配置写在 XML 还是注解里这些决策每个都不难但组合起来就是经验门槛。SpringBoot 通过 starter 和默认配置把这些决策变成了“大多数场景下一个合理解即可”。这带来的价值不只是省了几分钟而是让一个新人也能在短时间内把项目跑起来让一个团队可以用相对统一的方式管理项目基线。2. 没有 SpringBoot 之前“启动一个 Web 项目”需要做哪些事如果想要真正理解 SpringBoot 做了什么最好的办法是回到没有它的年代看看那时启动一个 Web 项目有多麻烦。2.1 从 web.xml 到 Spring MVC 的“标准动作清单”以传统的 Servlet 项目为例当时要写的东西包括创建 Maven 工程手动引入servlet-api、spring-webmvc、jackson-databind、logback等依赖而且要自己处理版本冲突。编写web.xml在里面配置ContextLoaderListener让 Spring 容器随 Web 应用启动。配置DispatcherServlet指定它拦截哪些请求路径。配置 Spring 的 XML 文件applicationContext.xml、spring-mvc.xml以及后来的WebMvcConfigurer实现类。如果需要数据库要引入连接池驱动、配置数据源、配置事务管理器。如果接 MyBatis要写SqlSessionFactoryBean扫描 Mapper 接口和 XML。最后把项目打包成 war 包扔进外部 Tomcat 的 webapps 目录里再重启 Tomcat。这个过程不是说不能完成而是每一步都要亲手确认。任何一个第三方库接入都意味着你要重新理解一遍“它在 Spring 里应该怎么被管理”。这也是为什么以前一个 Web 项目从零到能正常开发往往要先搭一两天环境。2.2 每接一个中间件都要写一层“胶水代码”如果只做一个简单接口手工配置还勉强可以接受。一旦加入 Redis、消息队列、定时任务、权限框架事情就开始失控。每个中间件都要先找到它的 Spring 整合包再写一个配置类或者 XML 配置把它的客户端、连接工厂、模板类注册进 Spring 容器。这些代码本身难度不高但属于典型的“没有增量价值的工作”——你把它们写一百遍也不会提升业务能力只会在第两百遍时感到厌倦。SpringBoot 的starter就是针对这个问题出现的。它把“接入一个组件”的依赖组合、默认配置、自动装配类打包成一个坐标。你只需要引入一个依赖SpringBoot 在启动时会检查类路径里的条件决定要不要装配对应的组件。2.3 SpringBoot 在动手之前先替你做完了哪些事用一个类比来理解自动配置你搬进一间新办公室里面已经装好了桌椅、空调、照明和网口。你不需要知道电是怎么接进来的、网线是从哪个交换机拉过来的你只需要插上电脑就能办公。等你有了更高要求比如想加一个工位再去找管理员申请。SpringBoot 做的事情就是装修公司和管理员的结合体它预先铺好了水电同时也允许你提出改动需求。所以你会发现很多配置不写也能跑。不是因为配置不存在而是在你还没有写之前SpringBoot 已经用默认值把它准备好了。等你写了自定义配置它又会通过条件判断优先采用你的配置。3. SpringBoot 真正替你做的三件事依赖、装配、配置把 SpringBoot 的能力拆开看核心就是三件事依赖管理、自动装配、集中配置。理解了这三件事第一节的目标就完成一半了。3.1 starter把“依赖组合”变成“声明式坐标”starter是 SpringBoot 提供的一种依赖聚合方式。你不需要一个个去挑选具体依赖版本只需要引入一个starter它会帮你把一组相关依赖带进来。常见 starter核心作用典型场景spring-boot-starter-web引入 Spring MVC、内嵌 Tomcat、Jackson 等Web API 项目spring-boot-starter-data-redis引入 Redis 客户端和 Spring Data Redis缓存、分布式锁spring-boot-starter-test引入 JUnit、Spring Test、AssertJ 等单元测试、集成测试mybatis-spring-boot-starter引入 MyBatis 与 Spring Boot 整合使用 MyBatis 访问数据库spring-boot-starter-security引入 Spring Security认证与授权需要注意的是引入starter不等于所有功能都可用。它只是把“依赖和默认装配”带进来了具体行为还要看类路径和配置。如果某个功能的自动配置和你预期的行为不一致优先去查对应xxxAutoConfiguration类而不是怀疑项目坏了。3.2 自动配置核心机制是条件装配自动配置听起来玄实际底层就是条件判断。SpringBoot 在启动时会扫描spring-boot-autoconfigure包里的配置类。这些配置类不是无条件执行的。它们上面通常会有一堆条件注解比如ConditionalOnClass只有当类路径里存在某个类时才装配ConditionalOnMissingBean只有当容器里还没有某个 Bean 时才装配。这种方式带来一个关键好处你可以用自己的 Bean 覆盖默认行为。比如 SpringBoot 自动配置了一个数据源但你在自己的配置类里定义了一个更符合项目需求的数据源自动配置的ConditionalOnMissingBean就会放弃执行。SpringBoot 2.7 之前的自动配置描述文件通常叫spring.factories之后的版本使用META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports。不同版本路径有差异但不影响理解基本原理SpringBoot 扫描到这些描述文件加载里面声明的自动配置类再通过条件注解决定哪些生效。很多人背了“自动装配原理”面试题却不知道它对自己的意义。实际开发里你完全不用把所有自动配置类都记住。但当你遇到“我明明没写这个 Bean为什么它存在”“为什么我自定义配置不生效”这类问题时知道去自动配置类里找条件注解才是这个知识点的最大价值。3.3 集中配置从 web.xml 散落各处到 application.yml传统项目里配置是分散的web.xml 里配置 ServletSpring XML 里配置数据源和事务日志配置单独一个文件端口配置可能还要改 Tomcat 的 server.xml。SpringBoot 把这些集中到了一个位置application.yml或application.properties。常见的配置内容包括server: port: 8080 servlet: context-path: /demo spring: application: name: example-service datasource: url: jdbc:mysql://localhost:3306/demo username: root password: 123456 redis: host: localhost port: 6379配置项很多但启动日志里也能看到最终生效的配置组合。遇到“为什么我改了端口没生效”“为什么配置没起作用”时先去确认配置文件的加载顺序、是否有context-path影响路径、是否命中了正确前缀。另外提一个有趣的点SpringBoot 启动时那个 ASCII 字符画叫 banner它是可以自定义的。把自定义内容放到 resources 目录下然后在配置里指定spring.banner.location即可。网上有生成器可以做这种小彩蛋但不建议在上面花太多时间。4. 第一节的实操跑通第一个 SpringBoot 项目知道了理论还是要亲手跑一次。第一节的实操目标很简单创建一个最小的 SpringBoot 项目写一个接口成功访问。4.1 环境准备与版本选择常见开发环境组合是 JDK、Maven、IDE。在创建项目前先确认本机环境。从版本兼容角度看SpringBoot 2.7.x 对应 Java 8 是比较稳妥的组合如果你的项目基线是 Java 17那么 SpringBoot 3.x 更合适。SpringBoot 3.x 之后的包名从javax迁移到了jakarta这会导致很多旧代码在新版本中报编译错误。所以“SpringBoot 版本太高”不是错觉。它通常意味着项目使用了旧 JDK、旧依赖、旧 API却强行选择了新版本框架。注意如果本机是 JDK 1.8不建议因为追新而创建 SpringBoot 3.x 项目。先选能稳定运行的版本组合比选最新版本重要得多。4.2 创建最小项目并理解目录创建项目时可以用 IDEA 的 Spring Initializr也可以直接访问 Spring Initializr 网站生成压缩包。选择 Java 版本、Maven 构建、SpringBoot 版本依赖里先只勾选Spring Web。生成后的项目核心结构src/main/java/com/example/demo/ DemoApplication.java src/main/resources/ application.properties 或 application.yml static/ templates/ src/test/java/com/example/demo/ DemoApplicationTests.javaDemoApplication.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); } }SpringBootApplication相当于开启了自动配置和组件扫描。启动类的包位置很重要它决定了组件扫描的根路径。自定义的 Controller、Service 要放在这个包或其子包下否则扫不到。4.3 写第一个接口并观察启动日志在启动类同级或子包下创建 Controllerpackage com.example.demo.controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; RestController public class HelloController { GetMapping(/hello) public String hello() { return Hello SpringBoot; } }然后启动项目。启动成功后日志里会有关键信息Tomcat started on port(s): 8080 (http) Started DemoApplication in 1.234 seconds (process running for 1.345)浏览器访问http://localhost:8080/hello能看到Hello SpringBoot说明最小项目跑通了。注意这里的“跑通”只是第一步。它能启动只代表流程没有断真正理解它还得知道为什么这个请求能到达hello()方法。这背后是 Spring MVC 的前端控制器、HandlerMapping、参数解析、响应转换等一系列机制在协作。5. 新手最容易踩的坑以及一套排查顺序SpringBoot 降低了入门门槛但也带来一个副作用有些人只学会了“能跑”没有建立起“出了问题怎么排查”的思路。下面几个坑是新手阶段最常见的。5.1 版本问题不是越新越好“SpringBoot 版本太高导致 AOP 失效”“找不到javax包里的类”“MyBatis 整合不了”这类问题网上经常出现。这里面大部分不是 SpringBoot 缺陷而是版本基线不匹配。SpringBoot 3.x 要求 JDK 17 及以上如果你的项目仍然使用 JDK 8则适合 SpringBoot 2.7.x。另外SpringBoot 4.0 如果出现在新版本里对旧项目来说往往意味着更大的 API 变动。遇到找不到类、切面不生效、依赖爆红时第一反应不应该是怀疑某个包有问题而是检查 JDK、SpringBoot、第三方 starter 三者的兼容矩阵。处理方式建议是先确定一个稳定的基线版本再按这个基线去找配套依赖。不要只升级 SpringBoot 而不同步检查第三方 starter 版本。5.2 IDEA 中 application.yml 不提示通常不是配置问题很多新手遇到「IDEA 里写server.port没有提示」的情况第一反应是配置文件有问题。其实大概率是以下原因Maven 依赖还没导入完整导致 IDEA 没有识别到 Spring Boot 的配置元数据。IDEA 缓存异常导致提示失效。项目里根本没有引入 SpringBoot 相关依赖。处理顺序检查 Maven 依赖是否报红。mvn clean compile或者让 IDEA 重新刷新 Maven 项目。确认spring-boot-configuration-processor是否被引入。它不是必需但能提升 IDE 的配置提示能力。如果还是不提示尝试 IDEA 的 Invalidate Caches 并重启。最后再检查项目结构是否是标准 Maven 项目。这不属于复杂问题但经常会消耗大量时间。先按这个顺序排查比反复重装配置有效。5.3 启动成功但访问 404 / 连不上按这个顺序排查这是 Web 开发里出现频率最高的场景。项目日志显示启动成功但浏览器就是访问不到。不要一上来就怀疑自动配置有问题按下面这个顺序排查看启动日志里到底有没有Tomcat started on port(s)如果没有说明项目可能不是以 Web 应用方式启动或者在启动过程中切换成了非 Web 模式。看端口确认访问的端口是不是启动日志里显示的端口。如果配置了server.port要看application.yml是否真的生效。看路径如果设置了context-path访问路径必须加上对应前缀。看 Controller 有没有被扫描到Controller 是否在启动类所在包的子包下类上是否有RestController或Controller方法映射是否写对了看静态资源或页面目录如果访问的是页面而不是接口检查文件是否放在resources/static下。看异常日志有些 Bean 初始化失败但应用仍然继续运行。要往日志下方找Error creating bean with name或APPLICATION FAILED TO START这类关键信息。排查顺序不要反过来。很多人直接跳到“自动配置是不是有问题”结果折腾半天最后发现只是 context-path 没算上。6. 第一节之后按什么顺序继续学SpringBoot 的知识面很广从starter、自动配置到单元测试、事务、缓存、消息队列、部署再到微服务。如果第一节学完就急着背注解大全很容易变成“看的时候都懂做项目时全都忘”。更合适的方式是分阶段推进。6.1 三阶段路径跑通、理解、工程化第一阶段目标是跑通最小项目。会创建项目、理解启动类、写一个接口、修改端口、打包运行。这个阶段不需要深挖自动配置源码能稳定运行即可。第二阶段目标是理解机制。重点看 starter 和自动配置怎么生效配置文件的优先级如何用自定义 Bean 覆盖默认行为。这个阶段适合看 SpringBoot 官方文档里关于“Auto-configuration”的部分。第三阶段目标是工程化。开始关注单元测试、日志体系、异常处理、事务边界、过滤器与拦截器、接口鉴权、部署方式。到这个阶段你自然会遇到SpringBoot 事务失效场景、循环依赖、资源映射、大文件上传下载这些更具体的问题再针对性地逐个解决。需要说明的是第三阶段没有终点。技术会遇到业务业务会遇到边界。SpringBoot 本身只是个启动器工程化能力要靠项目实践来打磨。6.2 什么时候值得深入“自动装配源码”不是所有人一开始都需要读自动装配的源码。读源码的前提是你已经无法通过配置解决问题或者你很好奇一个具体行为是怎么发生的。常见的信号包括你配置了一个数据源但系统启动后还是用了自动配置的那个。你想排除某个自动配置类不知道该看哪个条件注解。你引入了自定义组件但容器里没有出现预期的 Bean。你想写一个自己的 starter 给团队内部复用。当这些问题出现时再去打开自动配置类的源码你会非常明确自己要找什么。否则只是把源码读一遍很快就会忘掉。6.3 SpringBoot 的适用边界它解决什么不解决什么最后也要把边界说清楚。SpringBoot 适合大多数常见的 Web 应用场景尤其在中小型项目和微服务基础架构里它让团队能够快速启动、统一维护、低成本接入常用组件。但它不解决一切问题如果项目对性能有极端要求需要自己控制 IO 线程模型和容器行为SpringBoot 的默认封装反而会成为瓶颈。如果团队已经有一套成熟的手工配置体系强行改成自动配置未必能带来直接收益反而会造成不必要的黑盒。当项目依赖大量第三方组件时starter 之间的版本兼容会成为一个持续的维护问题。自动配置的另外一面是“隐藏复杂性”。它让你不用关心细节但也意味着当细节出错时你需要花更多时间找到问题来源。所以使用 SpringBoot 的同时保持对底层 Spring 机制的持续理解并不是浪费。第一节结束之后建议你不要急着看更多花哨的进阶内容。先把你电脑上的项目重新创建一遍用排除法试一试去掉依赖会怎样改配置会怎样把 Controller 移到启动类包外面会怎样。这些尝试会让你更清楚地触摸到 SpringBoot 替你做的那些事。SpringBoot 的第一课不是背 API而是建立一种判断力知道哪些东西是框架替你默认做好的知道去哪里找突破口知道什么时候该相信默认配置什么时候该亲手改掉它。带着这个判断力继续往下学后面的路会顺很多。
返回列表