ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

SpringBoot入门:自动装配、Starter与内嵌服务器核心机制

2026/8/29 9:45:55 拓冰建站 浏览量
SpringBoot入门:自动装配、Starter与内嵌服务器核心机制 SpringBoot 是什么一句话可以先这样理解它不是一个新框架而是把 Spring 应用从“配置很重、启动很麻烦、整合成本高”的状态改成“依赖一加、配置一写、直接跑起来”的工程化方案。这篇是入门的“第一节”我会先讲清楚它到底做了什么能解决什么实际问题再结合平时最容易踩的坑把启动类、自动装配、starter、内嵌服务器这些概念拆开讲。适合谁看刚准备学 SpringBoot 的初学者被 SSM 项目里各种 XML 配置折腾过的同学还有面试前想弄明白“自动装配原理”但不想一上来就啃源码的人。这节不写复杂源码重点是把第一层逻辑讲通让你能顺利建项目、读日志、排查最常见报错。1. 先搞清楚 SpringBoot 是什么它把 Spring 的“工程化成本”降下来了1.1 从 Spring 的痛点倒推配置多、依赖杂、启动慢Spring 本身是一个优秀的容器框架IoC 和 AOP 解决了对象管理和切面逻辑的问题。但在 SpringBoot 出现之前做 Web 项目是另一套体验。你不但要理解对象生命周期还要处理一堆集成配置。举个典型场景。早期用 SSM 搭建 Web 项目流程大概是引入 spring-webmvc、mybatis、数据库驱动一堆依赖然后写 web.xml写 spring 配置文件写 springmvc 配置文件写 mybatis 配置文件再把 controller、service、mapper 扫描路径配好。中间还要处理静态资源映射、拦截器注册、事务管理器、数据源连接池。这个过程不是做不到而是每个环节都需要你手动确认。换一个团队配置风格可能完全不一样。新人进来第一周往往不是在写业务而是在对着配置文件猜“这个 bean 到底从哪里扫描进来的”。SpringBoot 解决的核心问题就是把 Spring 生态里最常见的整合方式做成“默认约定”并且提供 starter 和自动配置让大部分场景不需要你手动写配置就能跑起来。你可以把它的目标理解成让项目从“我要配 Spring 环境”变成“我要写业务代码”。1.2 SpringBoot 到底做了哪些事情SpringBoot 的贡献可以拆成四个维度这也对应了后面所有章节的入口自动配置根据 classpath 下的依赖自动创建相关 bean。比如引入了 spring-boot-starter-data-redisSpringBoot 会帮你配置 RedisTemplate、连接工厂等基本组件。starter 依赖管理把一组功能相关的依赖打包在一起比如 Web 项目只需要引入一个 spring-boot-starter-web就能拿到 spring-webmvc、内嵌 Tomcat、Jackson 等。内嵌服务器把 Tomcat、Jetty 等嵌入到应用里项目直接通过 main 方法启动不需要单独部署 war 到外部 Tomcat。约定优于配置提供默认配置、默认扫描包路径、默认配置文件位置同时也允许用配置项覆盖。这四个能力互相配合。没有 starter自动配置很难做到“依赖一加就能用”没有内嵌服务器应用启动和部署就不会这么轻量。它们共同把 Spring 项目的开发体验从“先解决环境问题”变成了“先写业务代码”。1.3 Spring 和 SpringBoot 对比不是替代是套了一层工具皮很多人刚学时会把 SpringBoot 当成 Spring 的替代品这是理解偏差。SpringBoot 底层运行的核心容器仍然是 SpringIoC、AOP、事务管理这些机制完全是 Spring 自己的。SpringBoot 相当于在 Spring 外面包了一层“自动配置工具”让你更方便地使用 Spring。对比项SpringSpringBoot定位核心框架提供 IoC/AOP/事务等能力基于 Spring 的快速开发脚手架配置方式XML 或注解手动组装自动配置 外部配置属性Web 启动需要外部 Tomcat或额外配置内置服务器直接启动 main依赖管理需要自己维护版本由 parent 或 dependency-management 统一管理学习重点理解容器、Bean、AOP理解 starter、自动装配、配置覆盖所以正确路线不是“学完 Spring 后再学 SpringBoot 就完全抛弃 Spring”而是 SpringBoot 帮你承担了 Spring 环境搭建的重复劳动但你还是得懂 Bean、依赖注入、事务、AOP遇到问题才知道去查哪里。2. SpringBoot 项目到底由哪些东西组成目录、启动类、配置文件2.1 一个最简项目长得什么样新建一个 SpringBoot 项目不管是用 IDEA 还是 Spring Initializr生成出来的骨架都差不多。核心结构通常包含pom.xmlMaven 依赖管理文件SpringBoot 版本和 starter 都在这里声明。src/main/javaJava 源码目录。启动类一般放在包根目录类名带 Application 后缀标了 SpringBootApplication。src/main/resources资源目录里面常见 application.yml 或 application.properties。启动类下面的包结构一般按 controller、service、mapper、entity 分层。如果你用 IDEA 创建 SpringBoot 项目它会自动生成一个启动类。这个类第一眼看起来什么都没做但它实际上是整个应用的总入口。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 不是单个注解而是一个组合注解。后面会拆开看。2.2 启动类为什么要放在包根目录这是新手最容易忽略的点。SpringBoot 默认扫描范围是“启动类所在包及其子包”。如果启动类放在 com.example.demo那么 com.example.demo.controller、com.example.demo.service 都能被扫描到。但如果启动类放到了 com.example.demo.config而 controller 在 com.example.demo.controller默认扫描就会漏掉controller 不会被注册成 Bean。我一般会建议启动类放在项目的顶层包然后 controller、service、mapper 都放在它下面。这样不用写额外的 scanBasePackages 也能跑通。如果你非得把启动类放在其他位置可以通过设置扫描包来解决但没必要自己增加复杂度。SpringBootApplication(scanBasePackages com.example)这种写法在拆分模块时会有用但新手阶段不建议一上来就改扫描路径容易把包结构搞乱。2.3 application.yml 和 application.properties 到底在配什么配置文件是 SpringBoot 默认读取外部配置的地方。默认文件名是 application.properties 或 application.yml。同一个项目里可以二选一也可以同时存在但 YAML 格式更利于表达层级关系后面项目里也更常见。server: port: 8080 servlet: context-path: /api spring: datasource: url: jdbc:mysql://localhost:3306/demo username: root password: root driver-class-name: com.mysql.cj.jdbc.Driver配置项虽然多但不要死记。SpringBoot 有一个“配置属性绑定”机制你写的前缀通常对应某个自动配置类的属性比如 spring.datasource 对应 DataSourceProperties。判断配置是否生效有一个简单的办法启动日志里会出现对应的自动配置报告或者通过 Actuator 的配置端点查看。如果配了但没生效先看是不是前缀写错、依赖没引入、类路径下没有对应自动配置文件。2.4 配置文件的优先级为什么你改了配置没反应SpringBoot 读取配置有优先级顺序而且不是只读 application.yml。它会按顺序读取命令行参数、Java 系统属性、操作系统环境变量、当前目录下的 config 包、当前目录、classpath 下的 config 包、classpath 根目录。所以如果你的项目里已经引入了外部配置中心或启动了命令行参数那本地 application.yml 里的同名配置可能被覆盖。问题看起来像“SpringBoot 不读配置”实际上是被更高优先级的配置盖住了。遇到这种情况排查顺序是先看启动命令有没有传参数再看环境变量再看是否有 config 目录下的同名配置最后才怀疑语法问题。3. 自动装配是怎么发生的从 SpringBootApplication 到条件装配3.1 SpringBootApplication 组合注解拆开看SpringBootApplication 其实是由三个注解组合而成SpringBootConfiguration本质上是一个配置类标记当前类为 Spring Boot 的配置类。EnableAutoConfiguration开启自动配置机制这是 SpringBoot 最核心的一环。ComponentScan开启组件扫描默认扫描当前类所在包和子包。如果你看到别人在代码里直接写 Configuration EnableAutoConfiguration ComponentScan效果和 SpringBootApplication 基本一致。但既然有了组合注解直接用它更省事。3.2 EnableAutoConfiguration 是怎么找到自动配置类的自动配置的关键在于 SpringBoot 会从 classpath 里读取一份自动配置类列表。在早期版本中这份列表写在 META-INF/spring.factories 文件里key 是 EnableAutoConfiguration。后面版本改成了 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports 这样的独立文件。不管文件位置怎么变思路一致第三方 jar 或 SpringBoot 自身把需要自动配置的类名列出来SpringBoot 启动时读取并尝试加载。但注意“尝试”这个词。SpringBoot 不会把列表里所有类都无条件加载。每个自动配置类上都有条件注解比如 ConditionalOnClass、ConditionalOnMissingBean、ConditionalOnProperty。也就是说自动配置是“有条件地生效”。你引入了 Redis 相关的类RedisAutoConfiguration 才可能生效你没引入它就不会加载。这种机制保证了 SpringBoot 不会给你创建一大堆用不到的 Bean。3.3 条件注解为什么重要条件注解是自动装配的灵魂。现实中你加了某个 starter但某个 Bean 没有自动创建最常见的几个原因classpath 缺少对应的类导致 ConditionalOnClass 不成立。项目里已经存在同类型的 Bean触发 ConditionalOnMissingBean自动配置选择“让位”。配置条件不满足比如某个配置项没有设置。自动配置类被 exclude 了或者启动类上的 excludeName 排除掉了。解决这类问题不要靠猜。先在启动日志里看“Negative matches”和“Positive matches”部分这两段会明确告诉你自动配置类为什么生效、为什么不生效。Positive matches: RedisAutoConfiguration matched: - ConditionalOnClass found required classes org.springframework.data.redis.core.RedisOperations Negative matches: RedisAutoConfiguration: - ConditionalOnClass did not find required class org.springframework.data.redis.core.RedisOperations看到这种日志就能立刻判断是依赖没引入还是缺配置。这是排查自动装配问题最直接的方式。4. starter 机制为什么依赖会自己带一堆库4.1 starter 是什么starter 可以理解成一个“功能包”它把一组功能相关的依赖聚合成一个坐标。比如你用 spring-boot-starter-web它会自动带上spring-webmvcspring-boot-starter-tomcatjackson-databindspring-boot-starter以及其他 Web 场景需要的依赖好处是你不用自己逐个找 jar。坏处是如果你不熟悉 starter 内部依赖可能引入了一些你根本用不到的库增加构建体积和启动耗时。常见的 starter 大致有这些starter 名称场景spring-boot-starter-webWeb 项目包含 Spring MVC 和内嵌 Tomcatspring-boot-starter-data-redisRedis 客户端与连接池spring-boot-starter-aopAOP 切面编程spring-boot-starter-test单元测试和集成测试基础依赖spring-boot-starter-quartz定时任务 Quartz 集成spring-boot-starter-activemqActiveMQ 消息队列4.2 版本管理为什么 parent 里已经定好了版本SpringBoot 项目里通常会有 spring-boot-starter-parent 作为父工程。它负责两件事一是通过 dependencyManagement 管理核心依赖版本二是统一插件配置。所以你引入 spring-boot-starter-web 时通常不用写版本号。版本由父工程统一管理。这样能减少版本冲突尤其适合新手。但有两点要注意。第一不要看一眼“不用写版本号”就所有依赖都不写版本号。非 SpringBoot 管理的第三方库比如某些内部组件、特殊插件如果不声明版本Maven 可能会报缺少版本或者意外拉到不兼容的版本。第二SpringBoot 版本升级时依赖版本会跟着变但你的代码不一定兼容。热搜里经常有人问“springboot 版本太高”导致某些功能变化、注解找不到或者升级后原来的配置失效。最稳的做法是先看官方的版本升级文档再决定是否升级别在正式项目里盲目追新。注意用最新版本不代表最优。如果你的项目已经稳定运行了很久优先确认升级带来的依赖和配置变化再决定是否迁移。4.3 实际项目中怎么选 starter刚开始学习时加 starter 的原则是“用多少加多少”。比如你只想写接口先加 spring-boot-starter-web。等你要连数据库再加 spring-boot-starter-jdbc 或 spring-boot-starter-data-jpa。等你要做定时任务再加 spring-boot-starter-quartz。不要在一开始把 redis、mq、minio 这些全塞进 pom.xml。原因有两个一方面依赖多启动时自动配置判断也会变多启动速度会受影响另一方面一旦某个 Starter 版本和主版本不匹配排查起来要翻整个依赖树新手很容易慌乱。真正需要整合多项中间件时我会把每个中间件单独写一个配置类并且尽量用 ConfigurationProperties 配置类来收敛参数。这样即使自动配置出问题也能快速定位到具体模块。5. 内嵌 Tomcat 和独立运行SpringBoot 的部署方式变简单了5.1 为什么不用装 Tomcat传统 Web 项目需要把项目打包成 war然后放到外部 Tomcat 的 webapps 目录下启动 Tomcat 才能访问。这个过程本身不复杂但每个环境都要装服务器版本不一致还会出问题。SpringBoot 默认使用的 spring-boot-starter-web 里就包含了内嵌 Tomcat 依赖。通过启动类 main 方法运行 SpringApplication.run 时它会自动创建 Tomcat 实例并启动不需要你单独安装任何容器。想换服务器也容易。Jetty、Undertow 都可以替代 Tomcat只要替换 starter 内的依赖即可。不过对新手来说默认 Tomcat 通常够用。5.2 打包成可执行 jar再用 java -jar 启动SpringBoot 项目最终可以打成可执行 jar这个 jar 不仅包含编译后的 class还包含所有依赖 jar 和内嵌服务器。部署时只需要把 jar 传到服务器再执行命令启动。mvn clean package -DskipTests java -jar target/demo-0.0.1-SNAPSHOT.jar第一次打包时要注意SpringBoot 的可执行 jar 依赖 spring-boot-maven-plugin 的 repackage 功能。如果你手动换成了别的打包方式可能打出来的 jar 里面没有依赖启动时报 ClassNotFoundException。启动时常用参数java -jar demo.jar --server.port8081 java -jar demo.jar --spring.profiles.activeprod java -jar demo.jar -Xms512m -Xmx1024m命令行参数优先级比 application.yml 高所以临时改端口、激活环境时很有用。5.3 本地开发和线上部署有哪些差异本地开发时IDEA 直接运行 main 方法就行。线上部署时最常遇到的差异不是 SpringBoot 本身而是环境变量和路径。比如本地数据库和线上数据库不同通常通过 spring.profiles.active 切换环境配置。你可以在 resources 目录下准备 application-dev.yml、application-prod.yml再在 application.yml 里设置默认环境。再比如上传文件、日志、临时缓存这些需要磁盘路径的场景本地路径和服务器路径可能是两套。不要用硬编码路径建议配置成外部属性部署时通过环境变量覆盖。排查部署问题一般按这个顺序先看应用有没有启动成功再看端口是否被占用再看配置里有没有错误最后看日志文件。常见情况是“代码本地能跑服务器上起不来”多半是环境变量、数据库连接、文件路径或系统权限问题。6. 第一节应该掌握的实践经验和常见问题边界6.1 自动装配原理怎么答成一段话如果你是为了面试准备最好不要背一段源码参数而是用清晰的逻辑表达出来。可以这样说SpringBoot 通过 EnableAutoConfiguration 开启自动装配启动时会读取 classpath 下的自动配置类列表然后根据条件注解判断哪些配置类生效最终创建对应的 Bean。同时配置项可以通过 application.yml 或环境变量覆盖用户也可以通过 ConditionalOnMissingBean 相关的机制替换默认 Bean。这里的关键词是自动配置类列表、条件注解、Bean 创建、配置覆盖。把这些讲清楚面试官基本能判断你是真的理解而不是只会贴启动类。6.2 为什么面试会问循环依赖和事务失效很多 SpringBoot 面试题并不是 SpringBoot 独有的而是 Spring 基础问题在 SpringBoot 场景下的体现。循环依赖指的是多个 Bean 互相依赖Spring 在默认情况下对单例 Bean 的循环依赖有一定的处理能力但构造器注入、多例 Bean、某些代理场景下可能还是会有问题。SpringBoot 使用基于注解的依赖注入所以这些老问题依然存在。事务失效也是高频问题。常见场景包括同一类里的方法自调用导致事务切面不生效、方法不是 public、异常被 try-catch 吞掉、事务管理器没有配置好、数据库表引擎不支持事务。这些问题的根因都在 Spring AOP 和事务传播机制不在 SpringBoot 本身。我建议你在学第一节时不要只看“怎么启动项目”还要把 IoC、AOP、事务管理的概念串起来。SpringBoot 只是让你更容易启动但代码运行时的容器行为仍然是 Spring 在负责。6.3 常见的“看起来像框架问题实际是环境问题”结合日常排查和热搜里经常出现的提问很多问题都属于这一类现象优先排查项目启动不了报端口占用先看 8080 或自定义端口是否被占用依赖下载卡住检查 Maven 镜像仓库、网络、本地仓库controller 访问 404检查启动类扫描包路径、类上有没有 RestControllerRedis 连接失败检查配置前缀、密码、地址、序列化方式配置项不生效检查命令行参数、环境变量、config 目录打包后启动报错看 jar 内容里依赖是否完整、插件是否生效单元测试找不到上下文确认测试类有没有 SpringBootTest包路径对不对前面说过排查要由外到内先看日志、再看输入、再看环境、最后看源码。不要一上来就怀疑 SpringBoot 自动装配有问题很多情况是项目结构或依赖坐标的问题。6.4 学完第一节建议你动手做这些练习只读文章不动手很难建立实际感觉。我建议第一节看完之后做下面这几个小练习用 IDEA 或 Spring Initializr 新建一个空项目只引入 spring-boot-starter-web。创建一个 Controller写一个返回字符串的 GET 接口启动后访问确认返回结果。在 application.yml 里修改 server.port改成 8081再启动观察端口变化。打开 IDEA 的启动日志找到 Positive matches 和 Negative matches看自动配置判断了哪些内容。自己创建一个 banner.txt放一段自定义内容看看启动时是否能显示出来。这几个练习虽然简单但能把 SpringBoot 的“启动入口、配置读取、自动装配、Web 请求”串成一条线。结语第一节不用急着追深源码SpringBoot 的底层能力很丰富源码也不少但第一遍学习时不需要全部啃完。你最该掌握的是它帮你解决了配置和启动的麻烦自动装配是它在背后做的关键事情。遇到问题先确认依赖、配置和日志不要上来就怀疑框架。我自己的经验是把 SpringBoot 当“工具”用起来很快真正拉开差距的是你对 Spring 底层机制的理解程度。第一节先把最简单的项目跑通把自动配置日志看会再到后面慢慢接触源码、封装自己的 starter这条路会顺很多。