Spring Boot 项目最容易走向两个极端:一种是只用 Initializr 点几下就开始写业务,后面配置、数据库、日志、异常处理全靠临时补;另一种是刚起步就搬一个巨大的脚手架,里面权限、代码生成、网关、监控、前端后台一股脑全上,最后删不干净也改不动。
更稳的方式是先把“最小可运行骨架”和“后续脚手架边界”分开。项目早期先把依赖、配置、数据库访问和基础约定立住,等重复问题真的出现,再抽成脚手架或公共模板。
第一步:用 Initializr 拿到干净骨架
新项目可以先从 Spring Initializr 开始,而不是从别人完整业务仓库里复制。
常见基础选择:
- JDK 17;
- Spring Boot 3;
- Maven 或 Gradle,个人项目里 Maven 更直观;
- Spring Web;
- Validation;
- MySQL Driver 或对应数据库驱动;
- MyBatis 或 MyBatis-Plus,按项目习惯选择;
- Lombok 如果团队接受,可以加入,但不要让实体语义完全依赖注解魔法。
初始化完成后,建议先做一次干净提交。这个提交只包含官方生成骨架和最小配置,不掺业务代码。后面如果项目结构改乱了,还能很清楚地看到自己到底改过哪些地方。
第二步:先跑通健康接口
项目创建后,不要急着连数据库。先跑一个最小 HTTP 接口,确认启动、端口、日志和返回结构都正常。
比如:
@RestController
class HealthController {
@GetMapping("/health")
public Map<String, String> health() {
return Map.of("status", "ok");
}
}
这一步看似简单,但能提前确认:
- JDK 版本是否正确;
- 依赖是否能下载;
- 本地端口是否冲突;
- 应用能否正常启动;
- IDE 和命令行运行是否一致。
等最小接口稳定,再引入数据库、缓存、异步任务等组件,排障会简单很多。
第三步:配置读取要从一开始规范
Spring Boot 配置很灵活,但灵活也容易乱。
建议一开始就定下几个约定:
- 公共默认配置放
application.yml; - 本地真实密码、私有路径和账号放本机私有配置;
- 不把真实密钥写进源码默认值;
- 复杂配置使用
@ConfigurationProperties映射成对象; - 对外可调参数写清单位和语义。
例如:
@ConfigurationProperties(prefix = "app.task")
public class TaskProperties {
private int workerCount;
private Duration timeout;
}
这种方式比到处 @Value("${xxx}") 更适合长期维护。配置集中成对象后,字段可以加校验、说明和默认值,也方便测试。
读取 resources 文件时也要小心。开发环境里通过文件路径能读到,不代表打成 JAR 后还能读到。更稳的方式是通过 ClassPathResource、ResourceLoader 或 Spring 注入资源,而不是依赖本机相对路径。
第四步:数据库访问先小后全
如果项目使用 MyBatis,可以先手写一组最小 Mapper,确认连接、SQL、事务和返回结构都跑通,再考虑代码生成。
起步阶段至少确认:
- 数据源配置是否清楚;
- 表字段和 Java 字段命名规则是否一致;
- 时间字段的时区语义是否明确;
- SQL 是否有必要注释;
- Mapper XML 或注解风格是否统一;
- 事务边界放在 Service 层,而不是 Controller 里临时拼。
mybatis-generator 或类似代码生成工具适合在表较多时节省重复劳动,但不要一开始就把生成代码当成架构。生成器应该服务于项目约定,而不是让项目被生成器目录结构牵着走。
一个实用原则是:生成模型和基础 CRUD 可以自动化,核心业务查询、复杂关联和状态流转逻辑应该人工审查。
第五步:异常、返回值和校验要早定
早期项目可以轻,但不要每个接口自己随手返回。
建议尽早统一三件事:
- 请求入参校验;
- 统一响应结构;
- 全局异常处理。
入参用 Bean Validation:
public record CreateUserRequest(
@NotBlank String name,
@Email String email
) {
}
Controller 里接收:
@PostMapping("/users/create")
public ApiResponse<Long> create(@Valid @RequestBody CreateUserRequest request) {
return ApiResponse.ok(userService.create(request));
}
全局异常处理再把校验错误、业务错误和未知错误统一成前端能识别的格式。这样项目还小的时候就能避免“有的接口返回 true,有的返回字符串,有的直接抛堆栈”的混乱。
第六步:启动后逻辑不要塞进 main 方法
有些逻辑需要应用启动成功后执行,比如初始化缓存、检查配置、预热任务或注册本地计划任务。
这类逻辑不要直接写在 main 方法里。Spring Boot 提供了 CommandLineRunner、ApplicationRunner、事件监听等方式。选择哪种不重要,关键是要让启动钩子有明确边界:
- 能失败就要给出清楚日志;
- 不要在启动线程里做很久的阻塞操作;
- 涉及远程写操作时默认 dry-run 或显式确认;
- 可以重复执行的任务要保证幂等。
如果只是开发环境初始化数据,也要和生产启动逻辑分开,避免上线时误执行。
什么时候需要脚手架
脚手架的价值不是“看起来完整”,而是把重复问题稳定沉淀下来。
适合抽成脚手架的内容包括:
- 统一响应和异常处理;
- 参数校验范式;
- 日志和请求追踪;
- 数据库分页和审计字段;
- 本地配置加载约定;
- 代码生成规则;
- Swagger 或 OpenAPI 输出;
- 常见测试基类;
- Docker Compose 本地依赖;
- README 和运行命令模板。
不适合过早塞进脚手架的内容包括:
- 尚未稳定的业务权限模型;
- 不确定是否长期使用的第三方组件;
- 一次性页面和临时接口;
- 复杂但没有复用需求的领域逻辑;
- 为了显得“企业级”而加入的网关、注册中心和治理组件。
脚手架应该让新项目更快进入业务,而不是让每个新项目先花两天删模板。
参考开源项目时看什么
看开源 Spring Boot 项目,不要只看功能多不多。更重要的是看它有没有适合自己的边界。
可以重点看:
- 是否支持当前 JDK 和 Spring Boot 版本;
- 启动命令是否清楚;
- 数据库初始化是否可靠;
- 模块拆分是否服务业务,而不是过度分层;
- 权限和用户体系是否能删掉或替换;
- 前后端是否强绑定;
- 是否有测试和接口文档;
- 配置里是否混入示例账号或过期依赖。
像商城后台、管理系统、权限脚手架、代码生成平台这类项目,都可以作为参考,但不要整包复制后再慢慢删。复制越大,项目早期的认知负担越重。
一条轻量起步流程
一个更稳的 Spring Boot 起步流程可以这样走:
- Initializr 生成最小骨架。
- 提交原始骨架。
- 跑通健康接口。
- 建立配置分层和本地私有配置。
- 接入数据库和最小 Mapper。
- 补统一响应、校验和异常处理。
- 写一个真实业务接口。
- 加最小测试和 README。
- 只有当重复出现时,再沉淀脚手架能力。
这条流程不重,但能把项目后期最容易散的地方先固定住。
小结
Spring Boot 项目起步,真正重要的不是依赖选得多全,而是边界清楚。
Initializr 用来拿干净骨架,配置读取要从一开始规范,MyBatis 先跑通再生成,异常和响应尽早统一,启动钩子不要塞进 main 方法。至于脚手架,应该从重复实践里长出来,而不是一开始就把所有可能用到的功能塞进项目。
这样项目既不会太空,也不会一出生就背着一整套用不上的模板包袱。




