SpringBoot入门:自动装配、Starter与内嵌服务器核心机制
2026/8/29 9:45:54 网站建设 项目流程

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-redis,SpringBoot 会帮你配置 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 底层运行的核心容器仍然是 Spring,IoC、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.xml:Maven 依赖管理文件,SpringBoot 版本和 starter 都在这里声明。
  • src/main/java:Java 源码目录。
  • 启动类:一般放在包根目录,类名带 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-webmvc
  • spring-boot-starter-tomcat
  • jackson-databind
  • spring-boot-starter
  • 以及其他 Web 场景需要的依赖

好处是你不用自己逐个找 jar。坏处是如果你不熟悉 starter 内部依赖,可能引入了一些你根本用不到的库,增加构建体积和启动耗时。

常见的 starter 大致有这些:

starter 名称场景
spring-boot-starter-webWeb 项目,包含 Spring MVC 和内嵌 Tomcat
spring-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.port=8081 java -jar demo.jar --spring.profiles.active=prod 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检查启动类扫描包路径、类上有没有 @RestController
Redis 连接失败检查配置前缀、密码、地址、序列化方式
配置项不生效检查命令行参数、环境变量、config 目录
打包后启动报错看 jar 内容里依赖是否完整、插件是否生效
单元测试找不到上下文确认测试类有没有 @SpringBootTest,包路径对不对

前面说过,排查要由外到内:先看日志、再看输入、再看环境、最后看源码。不要一上来就怀疑 SpringBoot 自动装配有问题,很多情况是项目结构或依赖坐标的问题。

6.4 学完第一节,建议你动手做这些练习

只读文章不动手,很难建立实际感觉。我建议第一节看完之后,做下面这几个小练习:

  1. 用 IDEA 或 Spring Initializr 新建一个空项目,只引入 spring-boot-starter-web。
  2. 创建一个 Controller,写一个返回字符串的 GET 接口,启动后访问确认返回结果。
  3. 在 application.yml 里修改 server.port,改成 8081,再启动,观察端口变化。
  4. 打开 IDEA 的启动日志,找到 Positive matches 和 Negative matches,看自动配置判断了哪些内容。
  5. 自己创建一个 banner.txt,放一段自定义内容,看看启动时是否能显示出来。

这几个练习虽然简单,但能把 SpringBoot 的“启动入口、配置读取、自动装配、Web 请求”串成一条线。

结语:第一节不用急着追深源码

SpringBoot 的底层能力很丰富,源码也不少,但第一遍学习时不需要全部啃完。你最该掌握的是:它帮你解决了配置和启动的麻烦,自动装配是它在背后做的关键事情。遇到问题先确认依赖、配置和日志,不要上来就怀疑框架。

我自己的经验是,把 SpringBoot 当“工具”用起来很快,真正拉开差距的是你对 Spring 底层机制的理解程度。第一节先把最简单的项目跑通,把自动配置日志看会,再到后面慢慢接触源码、封装自己的 starter,这条路会顺很多。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询