Spring Boot 这东西,说实话我一开始是有点抵触的。那时候还在用 SSM 拼 XML,一个web.xml能写上百行,数据源配错一个单词,Tomcat 启动直接红一片。后来切到 Spring Boot,第一次感受到什么叫“约定优于配置”,项目从创建到跑起来,前后不到五分钟。陆陆续续用了好几年,也带过不少新人,发现大部分人的问题其实都集中在一个点上:不是 Spring Boot 本身难学,而是第一步“项目创建”就没走顺,后面越走越别扭。
这篇文章算是系列的第二篇,默认你已经知道 Spring Boot 是干嘛用的、解决了什么问题,但还没真正动手建过一个项目。咱们这次不聊虚的,直接从基础概念往下挖,然后带着你用 IDEA 把项目从零建起来,再把项目结构、启动过程、核心注解、配置文件的细节全部过一遍。你跟着操作完,不仅能跑通一个 Web 项目,还能搞清楚每个文件、每个注解为什么存在。考虑到现在 IDEA 版本更新快、Spring Boot 版本也一年比一年激进,我会把版本选型、初始化超时、配置加密这些实操里容易踩的坑一并讲清楚。
1. Spring Boot 到底解决了什么问题
1.1 从 SSM 到 Spring Boot:少写了多少配置
我经常会问新人一个问题:你没用 Spring Boot 之前,搭一个 Web 项目需要做哪些事?很多人答不上来,因为他们的第一个项目就是用 Spring Boot 建的,压根没经历过那个年代。我简单回忆一下最原始的 Spring MVC 项目要干的事:
先创建一个 Maven Web 项目,在pom.xml里手动引入 Spring 核心、Spring MVC、Jackson、Servlet API 等一堆依赖,还要操心版本兼容问题。然后写web.xml,在里面配置DispatcherServlet、ContextLoaderListener、字符编码过滤器。接着写一个spring-mvc.xml,配置注解驱动、组件扫描、视图解析器。数据源、事务、MyBatis 的配置也全部是 XML 文件,动不动就是几百行。最让人崩溃的是项目跑不起来,报错还不直观,你根本不知道是包没引全还是 Bean 没扫到。
Spring Boot 做的事情说白了就是把这些繁琐的配置收敛了。它通过“自动配置”机制,在你引入spring-boot-starter-web之后,默认帮你装配好 Spring MVC、内嵌 Tomcat、Jackson 这些组件。你不需要写web.xml,不需要手动注册DispatcherServlet,项目里一个main方法直接启动内嵌容器。这种体验上的转变,对于刚接触 Java Web 开发的人来说,几乎是一种解放。
1.2 “约定优于配置”到底是什么
Spring Boot 的核心哲学是“约定优于配置”,翻译成人话就是:框架先按最常见的场景把默认值设置好,你只要不提出特殊需求,就按默认的规则走。
举几个最直观的例子:
- 项目结构上,代码放在
src/main/java,资源放在src/main/resources,这是 Maven 的标准目录,Spring Boot 沿用这套约定,你不需要额外配置源码路径。 - Web 项目默认端口是
8080,默认上下文路径是/。你要改端口,只需要在配置文件里写一行server.port=8081。 - 配置文件名默认是
application.properties或application.yml,只要你放在classpath下,Spring Boot 会自动读取。 - 组件扫描默认从启动类所在的包开始往下扫,所以启动类一般都放在根包下。
这些约定看起来简单,但背后省掉的是大量的决策成本。你不用去想“我这个配置文件该叫什么名字”,直接按约定来就行。新人学 Spring Boot 最容易犯的一个错误就是不看默认值,一上来就到处加配置,结果反而把项目搞乱了。记住一点:先按默认方式跑通,再想着去定制。
1.3 自动配置背后的核心逻辑
自动配置是 Spring Boot 最让人省心、也最容易让人困惑的机制。省心是因为你不用手动写配置类,困惑是因为一旦出现诡异问题,你根本不知道是谁给你配的。
核心逻辑其实不复杂:Spring Boot 在启动时,会自动加载META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports文件里声明的所有自动配置类。注意,这里的“加载”不是真的全部生效,而是带有条件判断的。每个自动配置类上都会标一堆条件注解,比如@ConditionalOnClass(类路径下存在某个类才生效)、@ConditionalOnMissingBean(容器中不存在某个 Bean 才生效)、@ConditionalOnProperty(配置文件中存在指定属性才生效)。
举个例子,你引入了spring-boot-starter-web,类路径下有Servlet和Spring MVC相关类,那么WebMvcAutoConfiguration就会生效,帮你把 DispatcherServlet、默认的静态资源映射、消息转换器都配好。如果你自己又定义了一个WebMvcConfigurer的 Bean,Spring Boot 会和你自己定义的配置合并,不会暴力覆盖。
理解这一点对排查问题帮助很大:项目里如果多了一个你没写过的 Bean,八成就是自动配置在起作用。你想看生效了哪些条件,可以在配置里加一行debug=true,启动时控制台会输出一份自动配置报告,详细列出哪些配置类生效、哪些未生效以及原因。排查配置问题时,这个文档能省你大量时间。
2. 动手之前的环境准备与版本选型
2.1 JDK、Maven、IDEA 怎么搭配
创建项目之前,先把环境理顺。我见过太多新手卡在环境上:JDK 装了 1.8 和 17 两个版本,IDEA 里项目 SDK 选错了,Maven 用的还是 IDEA 自带的,结果依赖下载奇慢无比,还经常报错。
目前 Spring Boot 3.x 要求 JDK 17 起步,Spring Boot 2.7 是 2.x 最后的版本,支持 JDK 8。如果你机器上同时装了多个 JDK,建议给不同项目做显式指定,IDEA 的Project Structure -> SDK和Settings -> Build Tools -> Maven -> Importer里的 JDK 设置都要保持一致。
Maven 我不是很推荐用 IDEA 自带的,因为自带版本通常偏老,而且它的本地仓库默认在 C 盘用户目录下,时间长了能把系统盘撑爆。建议去 Maven 官网下载一个稳定版,比如 3.8.8 或 3.9.x,然后修改conf/settings.xml,把本地仓库地址改到其他盘,顺便把镜像改成国内源。具体怎么改,下面配置章节会详细讲。
IDEA 的话,社区版(免费版)也能建 Spring Boot 项目,只是在创建向导里少了 Spring Initializr 的图形化选项,需要手动去官网拉模板。如果你用的是 2024 版本,我更推荐直接用 IDEA 自带的 Spring Initializr,体验已经很成熟了。Ultimate 版用户直接在 New Project 里选 Spring Initializr 就行。
2.2 Spring Boot 版本号怎么看
Spring Boot 的版本号有一套自己的规则,比如3.2.5,格式是“主版本.次版本.增量版本”。主版本是重大里程碑,比如 2.x 到 3.x,这意味着底层有很多不兼容的变更。次版本是功能迭代,比如 3.1 到 3.2,会增加新特性,但整体兼容。增量版本是补丁,修 bug、安全漏洞,直接升级就行。
选版本的原则,我个人的建议是:新项目不要追求最新,但也不要选太老的。比如现在是 3.x 时代,你如果还在用 2.7 确实有点跟不上节奏,因为官方维护期已经过了。但如果你刚出 3.5 你就无脑升 3.5,可能遇到一些刚引入的 bug,而且在网上搜解决方案时,资料还不够多。
比较稳妥的做法是:选当前主版本线里最新的稳定版的前一到两个版本,或者直接看 Spring Initializr 默认给你的版本,因为 Spring 官方会把默认版本调成经过较多验证的稳定版本。
2.3 版本太高导致的坑,怎么规避
热词里有“springboot版本太高”这个说法,这确实是很多人会遇到的困惑。其实大多数情况下,不是版本本身有毛病,而是你的运行环境、依赖库跟不上。
- JDK 版本不够:Spring Boot 3.x 必须 JDK 17 以上,你还在用 JDK 8 就会直接启动失败。
- 依赖不兼容:比如用 Spring Boot 3.2 搭配一个旧版的 MyBatis Spring Boot Starter,它内部用的 Spring 6 的 API 可能对不上,启动时会抛
NoSuchMethodError或者ClassNotFoundException。 - Maven 编译器版本不对:
pom.xml里没指定<java.version>,或者 Maven 的 compiler 插件默认用 JDK 8 的级别去编译 17 的语法,直接报错。
规避方法其实很简单:第一,创建项目时确认 Spring Boot 版本和 JDK 版本匹配;第二,用官方的spring-boot-starter-parent做父工程,大部分依赖版本都不用你操心;第三,三方库不要乱给版本号,优先看它有没有针对该 Spring Boot 版本的 Starter。
如果你在 Spring Initializr 初始化时看到版本下拉里有一些后缀是SNAPSHOT或M1、M2的选项,建议别选,那是快照版和里程碑版,适合尝鲜,不适合学习入门。正式项目要用带RELEASE或者纯数字的稳定版。
3. 用 IDEA 创建 Spring Boot 项目的完整实操
3.1 推荐方案一:官方 start.spring.io 初始化
创建一个 Spring Boot 项目,最常见的方式就是去 start.spring.io 生成一个模板包,然后在 IDEA 里打开。
我来说一下为什么推荐这个方式:它是最原生的、不受 IDEA 版本影响的方案。IDEA 里内置的 Spring Initializr 本质上也是去请求这个服务,只是帮你包了一层图形界面。有时候 IDEA 内置功能出问题,直接用浏览器访问官网反而更稳定。
官网界面很简单,你需要填几项:
- Project:选 Maven,Gradle 也可以但生态上 Maven 资料更多。
- Language:Java。
- Spring Boot:选稳定版。
- Project Metadata:Group 一般填公司域名倒序,Artifact 填项目名,Name 一般和 Artifact 一致。
- Packaging:默认 Jar。
- Java:选你本机装的 JDK 主版本。
Dependencies 面板里可以搜索并添加依赖,第一次创建只需要加一个Spring Web就够了,其他的等用到时再手动加。生成后是一个 zip 包,解压后用 IDEA 的Open打开,等 Maven 把依赖下载完就能启动。
这里有个细节:生成的压缩包解压后,目录里会有一个mvnw.cmd和mvnw,这是 Maven Wrapper,它可以帮助你在没有安装 Maven 的机器上使用项目自带的 Maven 版本。如果你是直接用 IDEA 跑,可以忽略它;如果是命令行操作,用./mvnw spring-boot:run跑项目更省心。
3.2 推荐方案二:IDEA 内置创建向导
如果你用的是 IDEA 2024 版本,内置向导已经很成熟了。具体路径是:File -> New -> Project,然后左侧选择Spring Initializr。注意,IDEA 的 New Project 弹窗里默认有很多选项,比如Java、Maven、Gradle、Spring Boot,不要选成普通 Java 项目,那样是没有 Spring Boot 选项的。
进入向导后,界面和 start.spring.io 基本一致,填 Group、Artifact、选择依赖,点 Finish 等着下载即可。IDEA 内置向导的优点是不需要自己再去解压、导入,直接生成一个可识别的项目结构。
但我遇到过不少情况:内置向导的 Server URL 指向的是https://start.spring.io,如果你的网络访问这个地址很慢,甚至是超时,IDEA 就会卡在“Initializing”界面很久,最后报错。这个问题我在 3.3 小节专门说一下怎么绕过。
3.3 初始化超时的排查与替代方案
创建项目时卡在下载模板,这是极其常见的问题。热词“idea 创建springboot 项目超时”说的就是它。
超时原因主要有两类:一类是网络连接start.spring.io不稳定,另一类是 Maven 依赖下载慢。第一类问题,解决方式是把 Server URL 换成国内可用的镜像地址。这里我提供一个思路:在 IDEA 的Settings -> Languages & Frameworks -> Spring Boot里可以修改 Initializr URL,将其指向阿里云的镜像服务,地址是https://start.aliyun.com。注意,阿里云镜像的 Spring Boot 版本列表会比官网滞后,但胜在速度快、稳定。如果你需要拉最新的版本,等初始化完成后再到pom.xml里手动改版本号即可。
第二类问题,解决方式是在 Maven 的settings.xml里配置国内镜像源。常见的镜像地址有阿里云、华为云仓库等。配置方式是在<mirrors>节点下添加一个 mirror,把central仓库指向镜像地址。这一步做完,依赖下载速度会有质的飞跃。
另外再补充一个经验:IDEA 内置向导卡住的时候,不要反复点 Next 或刷新,那样只会让情况更乱。直接 Ctrl+C 取消本次创建,检查网络和镜像配置后重新来一次。
提示:修改完 Maven 的 settings.xml 之后,IDEA 里记得
File -> Reload All Maven Projects,否则不会生效。判断镜像是否生效,可以看 Maven 工具窗口里的日志,如果下载地址变成maven.aliyun.com开头,就说明设置成功了。
3.4 创建完成后需要调整的默认配置
项目创建成功,IDEA 会自动打开这个项目,Maven 开始下载依赖。这个过程第一次会比较久,你可以打开右侧 Maven 面板观察下载进度。
等依赖下完,有 3 个默认设置我建议你检查一下:
- 编码格式:IDEA 的
Settings -> Editor -> File Encodings里,把 Global Encoding、Project Encoding、Default encoding for properties files 全部改成 UTF-8。不然后面写中文注释、返回中文数据时,控制台和页面都会出现乱码。 - Maven 运行器的 JDK:
Settings -> Build Tools -> Maven -> Runner里,把 JRE 选成你项目对应的 JDK 版本。 - Lombok 插件:如果你后面要用 Lombok,IDEA 2021 之后的版本已经内置插件支持,但需要确保
Annotation Processing是开启状态。在Settings -> Build, Execution, Deployment -> Compiler -> Annotation Processors勾选启用。
这些配置不调整,项目也能跑,但跑到一半出现编码乱码、Lombok 不生效的问题,排查起来挺烦的。提前做好基础设置,后面能省事很多。
4. Spring Boot 项目目录结构与启动流程拆解
4.1 一个标准 Spring Boot 项目的目录长什么样
项目创建完成后,目录结构是这样的:
springboot-demo ├── src │ ├── main │ │ ├── java │ │ │ └── com/example/springbootdemo │ │ │ ├── SpringbootDemoApplication.java │ │ │ ├── controller │ │ │ ├── service │ │ │ ├── mapper │ │ │ └── entity │ │ └── resources │ │ ├── static │ │ ├── templates │ │ └── application.properties │ └── test │ └── java │ └── com/example/springbootdemo │ └── SpringbootDemoApplicationTests.java ├── pom.xml ├── mvnw ├── mvnw.cmd └── .gitignore初次创建时,controller、service这些包是不存在的,需要你自己手动创建。static目录放静态资源,比如图片、CSS、JS;templates目录放模板文件,比如 Thymeleaf 的 HTML;application.properties是全局配置文件,我会在后面章节讲怎么改成更清爽的yml格式。
src/test目录下有一个空的测试类,它是 Spring Boot 自动生成的,用@SpringBootTest注解启动一个完整的应用上下文。这个类可以用于写集成测试,但如果你只是快速启动项目,它不影响任何事情,可以暂时忽略。
4.2 启动类为什么长这样
打开SpringbootDemoApplication.java,你会看到:
package com.example.springbootdemo; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class SpringbootDemoApplication { public static void main(String[] args) { SpringApplication.run(SpringbootDemoApplication.class, args); } }这个类有两个关键点。第一,@SpringBootApplication是一个组合注解,它包含了@SpringBootConfiguration、@EnableAutoConfiguration和@ComponentScan。@EnableAutoConfiguration开启自动配置,@ComponentScan让 Spring 扫描当前包及其子包下的所有组件。第二,main方法里调用SpringApplication.run,这个静态方法会创建应用上下文、解析配置、执行自动配置、启动内嵌的 Web 服务器。
有一个细节要特别留意:启动类一定要放在根包下,也就是所有其他包的上级。很多人习惯把启动类放在某个子包下,结果项目启动后 Controller 不生效,访问接口 404,其实就是因为@ComponentScan默认只扫描启动类所在包及其子包,你放在子包下的类根本没被扫描到。
4.3 第一次启动要关注哪些日志
配置完成后,启动项目。第一次启动时控制台会输出几段关键信息:
- Spring Boot 的 ASCII 艺术字体 Banner。
- 日志级别为 INFO 的启动信息,包括当前版本、运行环境。
Tomcat started on port 8080 (http) with context path '',这说明内嵌 Tomcat 启动成功。Started SpringbootDemoApplication in 2.345 seconds,说明整个应用启动完成。
Tomcat started on port 8080和Started ... in x seconds这两行是最需要关注的。如果你的端口被占用,你会在前一行看到端口启动失败的错误;如果 Bean 装配有问题,后一行可能不会出现。
启动完成之后,浏览器访问http://localhost:8080,如果看到一个白页或者错误页,这是正常的,因为你还没有写任何接口。要验证项目真的没问题,可以在 IDEA 的终端里执行:
curl http://localhost:8080/actuator/health会得到一个404。这是因为你还没引入actuator依赖,所以没有这个端点。别急,先写一个接口来验证即可。
5. 核心注解与第一个 REST 接口
5.1 高频注解逐个说明
Spring Boot 项目里,注解的使用频率远高于 XML 配置,建议趁早把它们的含义吃透。我挑几个最常见的:
@RestController:组合注解,包含@Controller和@ResponseBody。标注在类上,表示这个类是一个处理 HTTP 请求的控制器,并且返回值会直接写入 HTTP 响应体,而不是走视图解析器。@RequestMapping:映射 HTTP 请求路径到处理方法上。可以标注在类或方法上,支持指定method属性来限定请求方式。它的便捷派生注解有@GetMapping、@PostMapping、@PutMapping、@DeleteMapping,推荐优先使用派生注解,语义更清晰。@RequestParam:绑定 HTTP 请求参数到方法参数上,支持设置required和defaultValue。@PathVariable:绑定 URL 路径上的占位符参数。@RequestBody:把 HTTP 请求体中的 JSON 数据绑定到 Java 对象上,常用于 POST 请求。@ConfigurationProperties:把配置文件里的属性批量绑定到一个 Java 对象上。相比@Value逐个注入,这个注解维护起来更方便,适合配置项较多的场景。@Autowired:按类型自动注入依赖。为了更好的可读性,现在也推荐在构造器上注入,但在实际项目中@Autowired还是最常见的写法。
5.2 快速写出一个带参数的 GET 接口
既然要验证项目是否跑通,最快的办法就是写一个简单的接口。我建议你建一个controller包,然后创建HelloController.java:
package com.example.springbootdemo.controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; @RestController public class HelloController { @GetMapping("/hello") public String hello(@RequestParam(value = "name", defaultValue = "World") String name) { return "Hello, " + name + "!"; } @GetMapping("/hello/{id}") public String helloWithId(@PathVariable Long id) { return "Hello, id=" + id; } }这段代码里包含了两种常见的参数传递方式。/hello?name=Spring是查询参数方式,@RequestParam负责解析;/hello/100是路径参数方式,@PathVariable负责解析。两者的区别记住一点:查询参数适合过滤、分页等可选项,路径参数适合标识资源 ID。
重启项目(或者启用 DevTools 热更新)后,在浏览器访问这些接口,你会看到对应的字符串输出。如果看到返回结果,说明你的项目已经从“能启动”变成了“能处理业务请求”,这是一个很大的里程碑。
如果你希望返回的是结构化数据,而不是简单字符串,通常我们会定义一个统一的返回对象,比如Result<T>,包含code、message、data三个字段。实际工作中,前后端分离项目基本都采用这种方式统一响应格式。
5.3 统一响应结构的小建议
定义统一响应结构,不只是为了好看,更是为了前后端协作时能有一套固定约定。我经常看到一些半路出家的项目,有的接口直接返回字符串,有的返回 JSON 对象,有的错误时直接抛异常返回默认错误结构,前端对接时非常崩溃。
建议的做法是定义一个泛型类:
package com.example.springbootdemo.common; public class Result<T> { private Integer code; private String message; private T data; public static <T> Result<T> success(T data) { Result<T> result = new Result<>(); result.setCode(200); result.setMessage("success"); result.setData(data); return result; } public static <T> Result<T> error(Integer code, String message) { Result<T> result = new Result<>(); result.setCode(code); result.setMessage(message); return result; } }接口里只需要返回Result.success("Hello"),前端就能拿到统一的结构。这样你在业务代码里只需要关心业务逻辑,返回结构由公共类统一处理。等到后面做全局异常处理时,这个结构还能继续复用。
6. 配置文件、多环境切换与安全细节
6.1 application.yml 的常用写法
Spring Boot 早期版本的默认配置文件是application.properties,现在更推荐用application.yml,因为 YAML 的层级关系更清晰,不会出现一长串点号连接属性名的情况。把.properties改为.yml后,删掉原来的.properties文件就行,Spring Boot 会优先读取yml。
一个常用的application.yml初始模板:
server: port: 8081 servlet: context-path: /demo spring: application: name: springboot-demo datasource: url: jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8 username: root password: 123456 driver-class-name: com.mysql.cj.jdbc.Driver mybatis: mapper-locations: classpath:mapper/*.xml configuration: map-underscore-to-camel-case: true这里有几个细节要注意。server.port改了端口后,访问地址就变成http://localhost:8081。context-path如果设置为/demo,那么所有接口路径前面都要加/demo前缀,例如/demo/hello。这个功能在做接口环境隔离时很有用。
spring.application.name在单体项目里看上去没什么用,但一旦你想接入配置中心或者做微服务,应用名就是身份标识,建议从第一天起就规范命名。
6.2 敏感配置怎么加密,不裸奔
热词里有“springboot yml密文”,这个需求在企业项目里非常常见。我们把数据库密码、第三方密钥直接写在application.yml里,等于把钥匙挂在门上。解决思路有两种,我用最简单的说法讲清楚。
第一种是环境变量占位。配置不直接写死,而是用${DB_PASSWORD}这种占位符,让 Spring Boot 从系统环境变量里取值。这样源码仓库里不会出现明文密码,部署时在服务器上设置环境变量即可。
第二种是使用 Jasypt 对配置做对称加密。引入jasypt-spring-boot-starter依赖,然后在配置里把明文替换成加密后的密文,例如:
spring: datasource: password: ENC(加密后的密文) jasypt: encryptor: password: 加解密密钥项目启动时,Jasypt 会自动把ENC(...)包裹的内容解密。密钥可以通过环境变量传入,避免出现在代码里。这里提醒一句:Jasypt 的密钥本身也要保管好,不要提交到 Git,否则等于没加密。
如果你只做学习项目,这个知识点可以先了解,不需要立即落地。但心里要有个概念:配置里凡是和生产环境相关的敏感信息,都不能以明文形式直接出现在配置文件里。
6.3 多环境 profile 切换
不同环境用不同配置,这是项目从开发走向线上必须解决的问题。开发的数据库和线上数据库不可能是一样的,端口、日志级别、缓存配置也各不相同。Spring Boot 通过 profile 机制解决这个问题。
在resources目录下,你可以建多个配置文件:
application.yml:公共配置。application-dev.yml:开发环境。application-prod.yml:生产环境。
application.yml里通过spring.profiles.active指定当前激活哪个环境,比如:
spring: profiles: active: dev启动的时候也可以用命令参数来覆盖:
java -jar springboot-demo.jar --spring.profiles.active=prod这样同一个 jar 包,部署在开发服务器跑dev,部署在线上跑prod,相当于把复杂环境隔离问题简化成“启动时加一个参数”。想保持配置整洁的,还可以用spring.profiles.group做 profile 分组,比如把dev和db-dev归为一组,但这是进阶用法,入门阶段用上面的方案就够了。
实战中我踩过一个坑,就是application-dev.yml没有放在resources目录下,而是随手建在了项目根目录。Spring Boot 死活读不到,启动时提示找不到数据源,最后花了十分钟才定位到是配置文件路径的问题。记住:Spring Boot 只认classpath下的application*.yml,其他位置就算你放在 pom.xml 同级目录它也不会自动加载。
7. 常见问题与排查技巧实录
7.1 启动类包路径错误导致 404
这是新手最容易踩的坑,也是最容易自查的:项目能正常启动,但访问接口时始终 404。如果你把启动类放在com.example.springbootdemo.controller包里,而 Controller 放在com.example.springbootdemo包的上级,@ComponentScan默认扫描不到,Controller 就不会被注册。
排查方法很简单:看启动类所在包的级联关系,保证所有组件类都在启动类包路径下,或者使用@SpringBootApplication(scanBasePackages = "com.example")显式指定扫描路径。大部分情况下,把启动类挪到根包就能解决。
7.2 端口被占用的一系列连锁问题
启动报Port 8080 was already in use,这种情况很常见。Windows 下可以通过命令行查端口占用:
netstat -ano | findstr 8080拿到进程 PID 后,用任务管理器结束对应进程,或者在命令行执行taskkill /F /PID 进程号。如果你不想杀掉进程,更省事的办法是改项目端口,加上一行server.port=8081。
端口被占用本身不是大问题,但要注意,它有时候是前一次启动的应用没有完全关闭导致的,而不是真的有别的程序占用了。如果你在 IDEA 里频繁重启项目,偶尔会遇到端口被占用的假象,等几秒再启动,或者直接 kill 掉 IDEA 的 Java 进程即可。
7.3 依赖下载慢的终极解决方案
依赖下载慢,不管换什么镜像,核心思路都是修改 Maven 的settings.xml。我给一个完整的镜像配置参考:
<mirrors> <mirror> <id>aliyunmaven</id> <mirrorOf>central</mirrorOf> <name>Aliyun Maven Mirror</name> <url>https://maven.aliyun.com/repository/public</url> </mirror> </mirrors>这个配置的意思是:所有对 Maven 中央仓库的下载请求,全部转发到阿里云的公共镜像。如果你项目里还用到了一些 Google 或 Spring 的专属仓库,比如 Spring 的里程碑版本,可以再加一个 Spring 的 mirror,但一般情况下上面这个配置已经够用。
镜像配置完之后,依赖还是下载慢,那就要检查是不是本地仓库的问题了。第一次下载时,本地仓库是空的,需要从远程拉取大量 JAR 包,这个过程确实急不得。建议第一次创建项目后让它慢慢下,不要中途取消,因为中断后容易出现依赖缺失的恶心问题。中途如果报错,删掉本地仓库里.lastUpdated结尾的文件再重新刷新。
7.4 常见报错速查表
| 报错信息 | 常见原因 | 解决方法 |
|---|---|---|
Cannot determine embedded database driver class for database type NONE | 数据源配置缺失或未引入数据库依赖 | 检查application.yml是否配置了spring.datasource |
Invalid bound statement (not found) | MyBatis 的 Mapper XML 路径配错 | 检查mybatis.mapper-locations是否匹配实际路径 |
Field xxx in Xxx required a bean of type 'yyy' that could not be found | 组件没有被 Spring 扫描到或依赖未注入 | 检查包路径和注解,确认是否存在循环依赖 |
Error creating bean with name 'xxx' | Bean 初始化失败,通常是构造器或配置属性类型不匹配 | 看后续异常堆栈,重点看Caused by |
java.lang.UnsupportedClassVersionError | JDK 版本过低,class 文件版本高于 JVM 版本 | 升级 JDK 或降低项目编译版本 |
Failed to bind properties under 'spring.datasource' | 配置属性类型转换失败 | 检查 YAML 缩进、属性名拼写 |
这张表不是万能的,但能覆盖新手阶段 80% 的启动失败原因。遇到报错时,不要只看第一行,重点看异常堆栈里Caused by后面的内容,那才是根本原因。
7.5 Banner 生成和图个乐
这个属于进阶的趣味技巧。热词里有“springboot banner生成器”,原因是 Spring Boot 启动时默认会打印一段 ASCII 艺术字。你可以用在线生成器做一段自己的 Banner,替换resources目录下的banner.txt文件,想用纯文本、彩色字体都可以。
Banner 虽然是个小东西,但在团队内部做个项目代号展示、或者给新项目加个启动仪式感,效果挺好的。而且操作没有任何风险:只需要在src/main/resources下新建banner.txt,把生成的内容粘贴进去就行。不喜欢的话直接删掉文件就恢复默认了。
8. 面试与实战延伸:把知识体系补完整
8.1 Spring Boot 面试题中常考的几个点
热词里出现了“springboot面试题”,我顺便把高频问题梳理一下,这些问题在社招和校招中出现频率极高:
- Spring Boot 与 Spring 的关系:Spring Boot 本质是 Spring Framework 的封装,核心依然是 IoC 和 AOP,Spring Boot 做的是简化配置、自动化装配、独立运行。
- 自动配置原理是什么:回答时提起
@EnableAutoConfiguration和AutoConfiguration.imports,条件注解@ConditionalOnClass、@ConditionalOnMissingBean等。 - 为什么 Spring Boot 的 jar 能直接运行:因为
spring-boot-maven-plugin把项目打成了一个可执行的 fat jar,内部包含所有依赖和嵌入式的 Tomcat 容器,启动时通过JarLauncher执行。 - 如何理解 starter:starter 是一组依赖的集合,通过 Maven 引入后,配合自动配置类,就注入了对应功能模块的 Bean。
@SpringBootApplication注解的组成:包括@SpringBootConfiguration、@EnableAutoConfiguration、@ComponentScan。
如果基础概念能答上来,面试官往往还会追问“自动配置生效的条件如何控制”,所以前面那一节讲的条件注解要重点掌握。
8.2 项目创建之后,下一步学什么
项目创建成功、第一个接口跑通,这只是热身。接下来往哪个方向走,我给你一个清晰的路线:
第一,把 Spring MVC 的请求处理链路搞清楚。写接口谁都会,但要理解一次 HTTP 请求从进入到返回,经过了哪些组件:DispatcherServlet、HandlerMapping、HandlerAdapter、参数解析器、消息转换器。
第二,掌握数据访问方式。JdbcTemplate 是基础,但实际项目里 MyBatis 和 Spring Data JPA 用得更多。无论选哪个,都要理解事务的传播行为,@Transactional的失效场景。
第三,学会整合常用组件。Redis、RabbitMQ、Elasticsearch 这些中间件,Spring Boot 都有对应的 starter,选择项目实际需要的学,不用贪多。
第四,深入了解部署与运维。项目打包成 jar,部署到服务器上跑起来,配好日志输出、健康检查。热词里出现的“heapdump 敏感信息泄露漏洞”就是一个安全问题,线上项目要限制/actuator/heapdump这类端点的访问权限。
这四个方向走完,你基本从“会创建项目”进阶到了“能开发项目”。
我在实际带项目时有个很深的体会:很多人学 Spring Boot,把太多精力花在用奇技淫巧上,反而忽略了最基础的东西。其实把项目创建、配置、接口、日志、异常处理这五件事做扎实,日常开发就已经够用了。框架本身变化很快,但底层的 Spring IoC 思想、MVC 处理流程、面向约定编程的思维,这些不容易变。你把这些地基打好,以后不管框架怎么升级,学起来都很快。
最后再分享一个小技巧:创建一个新项目时,别急着写业务代码,先把包结构、统一返回、全局异常、日志打印这些基础设施搭好。我见过很多人项目跑起来就往 Controller 里堆业务,三个月后整个项目乱成一锅粥,再想重构就难了。好的开始,真的能省掉后面无数的返工。