我先说句实话:Spring Boot 绝对是 Java 后端入门最值得花时间学的一个框架。我接触过不少刚开始学 Spring 生态的人,最大的挫败感来源往往不是代码逻辑有多难,而是"配了三天环境,项目还没跑起来"。Spring Boot 之所以能成为主流,恰恰是把这些让人劝退的配置环节压缩到了极致——你不用再手动建一堆 XML、不用纠结 Tomcat 怎么集成、不用为了一个数据源折腾几个小时。这篇文章我会从零开始,带你完整走一遍"创建第一个 Spring Boot 项目"的全过程,包括环境准备、项目搭建、结构解析、第一个接口的编写,以及我最想重点讲的排查经验和启动原理。不管你是刚学 Java 的小白,还是写过几年 SSH/SSM 想转 Spring Boot 的老手,按这篇文章的思路走一遍,你就能建立起对 Spring Boot 项目的整体认知框架。
1. 为什么是 Spring Boot:弄清楚它解决了什么问题
1.1 传统 Spring 开发的痛点
在 Spring Boot 出现之前,用 Spring 开发一个 Web 项目是什么体验?我举个真实的例子。你光是搭一个能跑起来的最小工程,通常需要经历这些步骤:下载 Spring 相关的一堆 jar 包或者通过 Maven 引入依赖、编写 web.xml 配置 DispatcherServlet、配置 Spring 容器加载路径、配置视图解析器、再手动往服务器里扔一个 war 包。整个过程涉及到的配置文件动辄五六个,任何一个地方写错一个标签,启动报错信息往往晦涩到让人怀疑人生。
更麻烦的是依赖管理。Spring 框架发展早期模块非常多,你要自己判断到底引入哪些 jar,版本又得自己保证兼容性。曾经有个经典的笑话:配依赖配了一天,最后发现只是 spring-core 和 spring-web 的版本差了 0.0.1。这个痛点真实存在,而且非常折磨人。
1.2 Spring Boot 的核心思路:约定优于配置
Spring Boot 的设计哲学其实就一句话:约定优于配置(Convention over Configuration)。什么意思?就是说框架根据你项目里引入的依赖和目录结构,自动帮你设定一套默认行为。你只要遵循这套约定,就几乎不用写显式配置。
比如你引入了 spring-boot-starter-web 这个依赖,Spring Boot 就知道你要开发 Web 项目,自动帮你配置好内嵌的 Tomcat 服务器和 Spring MVC 的基础组件——项目启动后默认监听 8080 端口。你引入 spring-boot-starter-data-jpa,它就默认帮你配置好 Hibernate 和连接池的基本行为。这就是它"简化配置"的核心原理。
用生活化的类比来解释:传统 Spring 就像一个毛坯房,水电、墙面、地板全部要你亲自操办,自由度极高但累人;Spring Boot 则是一个精装修交付的房子,开发商按行业标准默认给你做好了基础装潢,你拎包入住,然后按自己的喜好去布置家具就行。对于绝大多数场景,这套默认配置不仅够用,而且是最佳实践。
1.3 内嵌容器带来的部署方式变革
Spring Boot 的另一个让开发者"真香"的点,是内嵌式容器。传统项目的部署流程一般是:你把项目打成 war 包,然后丢到一个独立的 Tomcat 或 Jetty 的 webapps 目录下,再启动容器。而 Spring Boot 项目可以通过打包插件打成可执行的 jar 包,里面直接内置了 Tomcat 服务器。你只需要在服务器上执行 java -jar 命令就能把应用跑起来。
这种方式带来的好处是巨大的:一是环境依赖极大简化,服务器上只要装了 JDK 就能运行;二是启动速度大幅提升,本地开发时你不需要额外启动任何容器软件,直接在 IDE 里运行 main 方法即可;三是部署粒度变细,你可以同时在一台机器上运行多个不同端口的 Spring Boot 服务,互不干扰,非常适合微服务架构。
2. 环境准备:开发 Spring Boot 项目的基础配置
2.1 JDK 与 Maven 的版本选择
要让第一个 Spring Boot 项目顺利诞生,你需要安装两个核心环境:JDK 和 Maven(当然用 Gradle 也行,但 Maven 的普及率更高,而且 Spring Boot 官方文档的默认示例也是 Maven)。我先说 JDK。这里有一个重要信息:Spring Boot 的不同大版本对 JDK 版本要求不同。以目前主流的 Spring Boot 2.x 来说,它要求 Java 8 起步;而 Spring Boot 3.x 要求 Java 17 起步。我在实际开发中推荐大家直接上 Java 17 加 Spring Boot 3.x,因为它属于新特性更丰富且社区活跃度最高的组合。
安装 JDK 之后,一定要记得配置环境变量 JAVA_HOME 以及 PATH。这一步虽然基础,但很多人在这里出过问题。配置完成后,打开命令行输入 java -version 和 mvn -version,如果都能正确输出版本信息,说明环境没问题。Maven 的安装也类似,从官网下载解压后,把 Maven 的 bin 目录加入 PATH 即可。
2.2 Maven 仓库加速配置
Maven 是一个项目管理和构建工具,核心作用有两个:依赖管理和项目构建。Spring Boot 项目的依赖都是通过 Maven 从中央仓库下载的。但由于网络环境的原因,国内直接访问 Maven 中央仓库经常会出现下载速度极慢甚至超时的情况。我的做法是一开始就配置阿里云镜像。
打开 Maven 安装目录下的 conf/settings.xml 文件,在 mirrors 节点中添加如下配置:
<mirror> <id>aliyunmaven</id> <mirrorOf>central</mirrorOf> <name>阿里云公共仓库</name> <url>https://maven.aliyun.com/repository/central</url> </mirror>配置好之后,以后所有依赖下载都会走阿里云镜像,速度会有质的提升。这个步骤在刚入门时做掉,能省掉后面非常多的等待时间。
2.3 IDE 选择与推荐
Spring Boot 项目开发,IDE 的选择我首推 IntelliJ IDEA。它对新框架的支持非常完善,比如它自带的 Spring Initializr 功能能直接帮你在线生成一个 Spring Boot 项目骨架,省去了手工创建目录结构的工作。社区版(Community)其实也够用,但很多高级的 Spring 插件只在旗舰版(Ultimate)中提供,如果你条件允许,旗舰版会是更顺畅的体验。
当然,Eclipse 装 Spring Tools 插件也能开发 Spring Boot,VS Code 搭配 Java 扩展也可以,但体验上确实相比 IDEA 有一定差距。我的建议是,如果你是初学者,直接一步到位上 IDEA,把学习成本花在框架本身而不是折腾工具上。
3. 创建第一个 Spring Boot 项目:两种方式的完整流程
3.1 通过 Spring Initializr 网页生成项目骨架
最推荐新手的方式是访问 Spring Initializr 的在线服务(start.spring.io),这是官方提供的项目初始化工具。打开页面后,你会看到一系列表单。我来说明几个关键选项的含义:Project 选择 Maven;Language 选择 Java;Spring Boot 版本选择当前稳定版(建议选择最新稳定版本,不用刻意追求最新);Group 填公司的域名倒序(比如 com.example),Artifact 填项目名称(比如 my-first-project);依赖(Dependencies)这一栏,点击右侧的 Add Dependencies,输入 Web 搜索并添加 Spring Web,输入 thymeleaf 搜索添加 Spring Boot Thymeleaf(做页面时用)。选好之后点击 Generate 按钮,浏览器就会下载一个 zip 压缩包,解压后用 IDEA 以 Maven 项目方式导入即可。
这里我要提醒一个新手容易踩的坑:生成的项目压缩包解压后,有个 .gitignore 文件和 Maven 的 mvnw 文件。.mvn/wrapper 里的 maven-wrapper.properties 记录了 Maven 版本号,Spring Initializr 默认使用 Maven 3.6.3 来构建项目。如果你的本地 Maven 版本低于这个版本,建议把本地 Maven 更新一下,或者直接用项目自带的 mvnw 脚本,它会自动下载对应版本的 Maven,不需要你本地装 Maven 也能构建项目。
3.2 在 IntelliJ IDEA 中直接创建
如果你已经装好了 IDEA,更快捷的方式是直接新建项目:File -> New -> Project,左侧选择 Spring Initializr,然后按照网页版的向导一样填写 Group、Artifact、依赖项,IDE 会自动帮你完成项目生成和导入。这种方式省去了下载、解压、导入的中间环节,体验更流畅。我平时自己开发时也基本用这种形式。
3.3 项目目录结构深度解析
项目生成后,你会看到这样的目录结构(以 Maven 项目为例):
my-first-project/ ├── src/main/java/com/example/myfirstproject/ │ ├── MyFirstProjectApplication.java ├── src/main/resources/ │ ├── static/ │ ├── templates/ │ └── application.properties ├── src/test/java/com/example/myfirstproject/ │ └── MyFirstProjectApplicationTests.java ├── mvnw / mvnw.cmd ├── pom.xml └── .gitignore我来逐个说明它们的作用。MyFirstProjectApplication.java 是启动类,里面有一个 main 方法,是整个应用的入口;static 目录存放静态资源(CSS、JS、图片等),templates 目录存放模板文件(比如 Thymeleaf 模板);application.properties 是全局配置文件;pom.xml 是 Maven 的项目对象模型文件,所有的依赖和构建配置都在这里;test 目录存放测试代码。
从结构上看,Spring Boot 项目相比传统 Java Web 项目,最大的区别是少了一堆 webapp/WEB-INF 之类的目录。它不强制要求传统 Servlet 规范的目录结构,这本身就体现了"约定优于配置"的思路。
3.4 启动类与 pom.xml 的每行代码解读
启动类的内容非常精简:
package com.example.myfirstproject; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class MyFirstProjectApplication { public static void main(String[] args) { SpringApplication.run(MyFirstProjectApplication.class, args); } }@SpringBootApplication 是一个组合注解,它集中了 @SpringBootConfiguration、@EnableAutoConfiguration 和 @ComponentScan 三个注解的功能。@EnableAutoConfiguration 是核心,它让 Spring Boot 根据你引入的依赖自动配置应用;@ComponentScan 则让 Spring Boot 能够扫描到当前包以及子包下所有标注了 @Component、@Service、@Repository、@Controller 的组件,并把它们注册为 Spring Bean。这两点理解到位,对后面学习自动装配会有非常大的帮助。
pom.xml 中值得关注的核心是 spring-boot-starter-parent 作为父工程,它统一管理了所有 Spring Boot 相关依赖的版本,因此你在子依赖中几乎不用写版本号,避免了手动维护版本兼容性的痛苦。再往下,spring-boot-starter-web 是 Web 项目的核心 starter;spring-boot-starter-test 则是测试套件,包含了 JUnit、Mockito 等常用测试库。
3.5 第一次启动会发生什么
在 IDEA 中直接运行启动类的 main 方法,第一次启动时控制台会刷出一大段日志。这里我建议新手不要被日志吓到。耐心等待,直到看到类似于 "Tomcat started on port 8080" 和 "Started MyFirstProjectApplication in X seconds" 的字样,就代表启动成功了。然后你在浏览器地址栏输入 http://localhost:8080,理论上如果不写任何接口,你会看到一个错误页。这是因为没有任何内容可访问,并非项目本身有问题。
如果要验证项目确实通了,最简单的方法是在浏览器访问一个不可用的地址,比如 http://localhost:8080/error,它也会返回一个错误 JSON 响应。只要不是连接被拒绝,就说明服务已经正常运行了。
4. 配置文件与自动配置原理:把黑盒变成白盒
4.1 application.properties 与 application.yml 的选择
Spring Boot 支持两种格式的配置文件:application.properties 和 application.yml。两者的本质是等价的,只是语法风格不同。properties 是老牌的键值对格式,用点号分隔层级;yml 则用缩进表示层级,可读性更好,也是现在更流行的选择。我个人的建议是,新项目直接用 yml 格式,因为它的可读性更好,特别是配置内容多了之后,缩进结构的优势会非常明显。
举个例子。你要修改 Web 服务的端口、配置应用名称和一个自定义属性,properties 写法是这样:
server.port=8888 spring.application.name=my-first-project my.custom.config=hello而 yml 写法是这样:
server: port: 8888 spring: application: name: my-first-project my: custom: config: helloyml 写起来层次分明,但我必须提醒一个致命的坑:yml 对缩进极其敏感。它不能使用 Tab 缩进,只能使用空格,且同一层级的属性必须对齐。很多新手的报错就是源自这里,看起来检查了很久,其实只是某一行少了一个空格导致的解析失败。
4.2 如何读取自定义配置项
配置文件存在的意义就是让你在不改代码的情况下调整应用行为。读取配置有三种方式。第一种是最简单的 @Value 注解:
@RestController public class ConfigController { @Value("${my.custom.config}") private String customConfig; @GetMapping("/config") public String getConfig() { return customConfig; } }第二种是使用 @ConfigurationProperties 前缀绑定,适合有一组相关配置的场景。比如你有一个自定义的短信服务配置,包括 accessKeyId 和 accessKeySecret 等字段,就可以创建一个专门的属性类,将前缀相同的配置项整体绑定到一个 Java 对象里,代码更优雅。第三种是通过 Environment 对象,在需要时动态获取配置值。这三种方式各有适用场景,基础阶段掌握第一种就足够应对大多数场景了。
4.3 多环境配置的拆分思路
一个真实项目往往会区分开发环境、测试环境、生产环境。不同环境下的数据库地址、日志级别、服务端口往往不同。Spring Boot 对此提供了非常优雅的支持。你可以创建多个配置文件:application-dev.yml 对应开发环境,application-test.yml 对应测试环境,application-prod.yml 对应生产环境。然后在主配置文件 application.yml 中通过 spring.profiles.active=dev 这一行来指定当前激活的环境。
这样做的好处是,你不用在打包时把整个配置文件的代码改来改去。部署到生产环境时,只需要在启动命令后面加上 --spring.profiles.active=prod 参数就能切换。比如:
java -jar my-app.jar --spring.profiles.active=prod这个功能在实践中的价值怎么强调都不过分。我见过太多没有用多环境配置的项目,每次上线前手动把本地数据库地址改成生产库地址,然后又一个疏忽留下的配置错误导致线上事故。用上 profiles 之后,这类低级错误基本可以从根上断掉。
4.4 自动配置的生效机制浅析
Spring Boot 的自动配置在底层是通过 spring.factories 文件来声明的。在 spring-boot-autoconfigure 这个核心包中,META-INF 目录下有一个 spring.factories 文件,里面列出了一长串以 AutoConfiguration 结尾的配置类。每个配置类上都有一系列条件注解,比如 @ConditionalOnClass、@ConditionalOnMissingBean、@ConditionalOnProperty 等。
以我们最常见的 WebMvcAutoConfiguration 为例,它上面会标注 @ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class })。这意味着只有当你的 classpath 中存在 Servlet、DispatcherServlet 等相关类时,这个自动配置类才会生效。当 spring-boot-starter-web 被引入后,这些类自然齐了,Spring Boot 就会自动帮你设置好 Spring MVC 的各种核心组件。
这种机制让我想起了"按需加载"的概念:你引入什么依赖,框架就自动帮你安排对应的基础设施,不需要你主动开开关关。理解了这个原理,以后再看到网上说"引入某个依赖之后,所有的 Starter 默认都会生效"这种说法,你就能明白并不是生效,而是条件判定满足后才按需生效,哪些自动配置类参与了装配、它们的生效条件是什么,你其实完全可以通过日志输出查看。
5. 编写第一个接口:完成一次 HTTP 请求的完整闭环
5.1 从一个基于 @RestController 的记账本接口开始
我们用一个小例子把 Spring Boot 的 Web 开发串一遍。假设我们要做一个极简的记账本系统,实现记住支出记录的功能。为了聚焦主题,我先用一个内存版,不引入数据库。
首先创建一个用于存放记录信息的模型类:
package com.example.myfirstproject.model; import java.math.BigDecimal; import java.time.LocalDateTime; public class ExpenseRecord { private Long id; private String item; private BigDecimal amount; private LocalDateTime createTime; public ExpenseRecord() { } public ExpenseRecord(Long id, String item, BigDecimal amount, LocalDateTime createTime) { this.id = id; this.item = item; this.amount = amount; this.createTime = createTime; } // getter 和 setter 方法省略 }然后创建一个服务类,负责业务逻辑:
package com.example.myfirstproject.service; import com.example.myfirstproject.model.ExpenseRecord; import org.springframework.stereotype.Service; import java.math.BigDecimal; import java.time.LocalDateTime; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicLong; @Service public class ExpenseService { private final ConcurrentHashMap<Long, ExpenseRecord> store = new ConcurrentHashMap<>(); private final AtomicLong idGenerator = new AtomicLong(1); public ExpenseRecord add(String item, BigDecimal amount) { Long id = idGenerator.getAndIncrement(); ExpenseRecord record = new ExpenseRecord(id, item, amount, LocalDateTime.now()); store.put(id, record); return record; } public ExpenseRecord findById(Long id) { return store.get(id); } }最后是控制器,对外开放 HTTP 接口。@RestController 注解告诉 Spring 这是一个处理 HTTP 请求的控制器,且默认返回值直接写在响应体里。@RequestMapping 指定了这个类所有接口的公共路径前缀,@GetMapping 则处理 GET 请求,@PostMapping 处理 POST 请求。
package com.example.myfirstproject.controller; import com.example.myfirstproject.model.ExpenseRecord; import com.example.myfirstproject.service.ExpenseService; import org.springframework.web.bind.annotation.*; import java.math.BigDecimal; @RestController @RequestMapping("/expense") public class ExpenseController { private final ExpenseService expenseService; public ExpenseController(ExpenseService expenseService) { this.expenseService = expenseService; } @PostMapping("/add") public ExpenseRecord addExpense(@RequestParam String item, @RequestParam BigDecimal amount) { return expenseService.add(item, amount); } @GetMapping("/{id}") public ExpenseRecord getExpense(@PathVariable Long id) { return expenseService.findById(id); } }我把 @Service 加在 ExpenseService 上,其实就相当于告诉 Spring 容器"请帮我创建这个服务类的一个实例,并管理它的生命周期"。而 ExpenseController 的构造器参数 expenseService 会被 Spring 自动注入。这就是 Spring 最核心的依赖注入机制,你没有 new 这个服务对象,但框架在创建控制器时自动把容器中现成的服务实例递给了你。依赖注入的好处是解耦和易于测试,后续你要换成数据库实现时,只需要替换 Service 层的实现,Controller 的代码一行都不用动。
5.2 常见注解的作用对比
上面的代码出现了几个注解,初学者常常搞混。我整理一个最简单的对照关系:
@Controller 会将请求交给视图解析器处理,通常配合模板引擎返回页面;@RestController 则是 @Controller 加 @ResponseBody 的组合,表示方法的返回值直接序列化写入 HTTP 响应体,适用于前后端分离接口开发。@GetMapping 实际上是 @RequestMapping(method = RequestMethod.GET) 的快捷方式,类似还有 @PostMapping、@PutMapping、@DeleteMapping。@RequestParam 用于接收 URL 查询参数,@PathVariable 用于接收路径中的变量。在前后端分离的接口开发中,两者经常都用得上。
5.3 用 curl 和浏览器测试接口
启动项目后,打开命令行工具。先用 POST 添加一条记录:
curl -X POST "http://localhost:8080/expense/add?item=午饭&amount=35.5"如果返回的 JSON 数据中包含你提交的 item 和 amount,以及自动生成的 id 和 createTime 字段,说明接口正常。然后再查询这条数据:
curl "http://localhost:8080/expense/1"浏览器访问也能看到类似结果,不过因为中文编码问题,浏览器可能显示为 Unicode 转义字符,这个后面介绍如何调整响应体编码配置。到这里,你的第一个 Spring Boot 项目已经能够接收参数、执行业务逻辑并返回结构化 JSON 数据了,这实际上是绝大多数企业级后端应用的一个最小缩影。
5.4 关于包扫描范围的一个强制提醒
这里我要单独拎出一个新手最容易踩的坑:启动类的位置。@SpringBootApplication 注解自带组件扫描功能,但它默认只扫描启动类所在包及其子包。假设你的启动类是 com.example.myfirstproject.MyFirstProjectApplication,那么它只会扫描 com.example.myfirstproject 目录下的组件。
很多初学者从网上复制代码,把自己的 Controller 类放在了一个完全不同的包路径下,比如 com.other.controller,然后启动项目访问接口发现 404,抓破脑袋都查不出原因。排查思路是:确认启动类的位置和各个组件类的位置关系。最简单的解决方案是,始终让你的启动类放在包的根路径下,其他类按功能分包放在它的子包里。
6. 常见问题与排查技巧实录
6.1 端口被占用:Address already in use
这是新手最常遇到的第一类启动错误。报错信息类似于 "Port 8080 was already in use"。原因一般是之前启动的实例没关干净,或者有其他程序占用了 8080。
排查思路是先找到占用的进程。Windows 下执行:
netstat -ano | findstr 8080Linux 或 macOS 执行:
lsof -i :8080找到占用进程的 PID 后,直接结束进程,或者换一个端口运行。这里更推荐后一种:在 application.yml 中修改 server.port 为另一个值,比如 8081,立刻就能避开冲突。修改配置后重启项目,问题解决。这个操作本身也演示了前文说的配置文件的核心价值——改配置不用动代码。
6.2 依赖下载缓慢或无法解析
这类问题通常表现为 Maven 构建时卡在某个依赖下载环节持续几分钟,最后报 "Could not transfer artifact" 之类的错误。最直接的原因就是网络无法访问中央仓库或速度过慢。解决方案就是我前面说的配置阿里云镜像。另外,如果你的 IDE 引入了项目但 Maven 仍然使用默认设置,记得检查一下 IDE 中 Maven 的 settings 文件配置是否正确指向了你修改后的 settings.xml。
还有一个隐蔽的问题,如果你在 IDEA 中改了 pom.xml 之后没有自动刷新依赖,也可能导致大量红色报错。这时在 IDEA 右侧的 Maven 面板中点击刷新按钮(蓝色循环箭头),或者使用快捷键 Ctrl+Shift+O 强制刷新依赖即可。
6.3 自动装配失败最常见的报错
当你第一次尝试注入某个类时,可能看到类似 "Field xxx in com.example... required a bean of type 'xxx' that could not be found"。这个报错翻译成人话就是:Spring 容器里没有找到你要的那个类型的对象。
原因有几种:一是没有给对应的实现类加上 @Component / @Service / @Repository 之类的注解,导致它没有被注册为 Bean;二是这个类所在的包没有被启动类扫描到;三是这个类在某个配置类中需要显式声明为 Bean 但你没有声明。排查思路依次检查以上三个方向,绝大多数情况都能找到症结。
6.4 中文乱码的处理
返回数据中的中文变成乱码或者被转义为 "\uXXXX" 格式,这是开发阶段很影响观感的问题。如果是请求参数乱码,需要在配置文件中设置字符集过滤器:
server: servlet: encoding: charset: UTF-8 force: true如果是返回 JSON 时中文显示为 Unicode 转义,那是 Jackson 序列化时的默认行为。可以配置 spring.jackson... 或直接在属性条目中设置:
spring: jackson: default-property-inclusion: non_null其实随着工具的演进,现在大部分 HTTP 客户端和浏览器都能正常显示 Unicode 转义后的内容,这个问题对运行逻辑本身没有影响,不用太焦虑。但如果你的项目对接口返回值有直观展示需求,建议在使用前还是花几分钟确认一下编码层面没有额外问题。
6.5 一个值得养成的习惯:看懂启动日志
很多新手遇到问题,第一反应是把控制台日志翻到最底部看那几行红色的 Error。但实际上,启动类日志中 80% 的内容是 INFO 级别的,它们记录了 Spring 容器加载了哪些配置、哪些自动配置类生效、端口号绑定在哪。这些信息对定位问题价值巨大。
比如你发现项目启动后访问接口始终 404,先检查日志中有没有 "Tomcat started on port(s): 8080",如果没有,说明 Tomcat 根本没起来。再往上翻,找到 "Root WebApplicationContext: initialization completed" 之类的关键行,就是代表 Spring 容器初始化成功。日志是你最好的排障助手,比任何经验都可靠。我建议大家在初期就养成"启动一次,浏览一遍日志"的习惯,时间久了,你对框架的正常启动链路会形成肌肉记忆,一旦异常出现,你会本能地感觉到哪里不对劲。
7. 一些实测下来的体会与建议
最后分享一点个人体会。在带过几位朋友入门 Spring Boot 的过程中,我发现凡是能顺畅走下来的,普遍有一个共同点:他们都会花时间把启动日志完整读上一遍,而不是看到 Tomcat started 就急吼吼去敲接口。这个习惯让他们比别人更早地抓住了 Spring Boot 内部运作的直觉。有人觉得框架启动靠黑盒,出了事全凭猜,但当你熟悉了那几行日志之后,你其实是在和框架进行有来有回的对话。
另外一个小建议:很多人第一次创建项目时,其实并不清楚自己到底需要哪些依赖,于是习惯性地把能点的 Starter 全都加上。我的建议是控制住自己的手。Spring Boot 虽然不会因为多余依赖导致项目跑不起来,但过多的自动装配会让启动速度变慢、内存占用变大,也不利于排查问题。埋头加依赖之前,先问自己一句:我现在真的需要这个功能吗?从最小功能集开始,随着需求逐步补依赖,才是建立项目掌控力的正确顺序。
这个项目虽然很简单,但它已经完整覆盖了配置管理、依赖注入、接口开发、容器启动这些 Spring Boot 最核心的领域。往后不管你是去学数据库整合、写安全认证、还是拆微服务,底层都是这些今天建好的骨架在支撑。动手跑起来,比看十篇文章都管用。