SpringBoot项目从零搭建的注意事项 凌晨两点你在 IDEA 里删掉刚生成的 pom.xml因为不小心引入了某个花里胡哨的依赖项目启动直接报红。这一幕几乎每个用 SpringBoot 的人都有过。从零搭建一个小项目看似简单但真正让你卡住半天的往往不是业务逻辑而是一堆“我以为没问题”的初始化细节。这篇文字不聊高深架构就讲那些踩过无数坑才总结出的硬规矩每一条都对应一次惨痛教训。记住第一条空项目不是一张白纸而是一颗定时炸弹它爆炸的时间通常在你自信满满点击 Run 之后的三秒。依赖版本别信最新信你的环境很多人一上来就直奔 start.spring.io把最新版本号当成圣旨。SpringBoot 3.x 要求 JDK17可你本机还是 JDK8于是控制台给你打出一长串看不懂的 IllegalStateException。版本选择的本质是环境适配而不是追逐时髦。先确认三件事JDK 版本、Maven/Gradle 版本、以及你准备部署的服务器操作系统。这三者是地基地基没对齐上层再豪华也是危楼。建议直接使用与 JDK 相匹配的 SpringBoot 稳定版本比如 JDK8 就锁死 2.7.xJDK17 再考虑 3.x。别用 2.6 和 2.7 这种小版本号的中间版本它们多数是为了给 3.x 铺路存在大量隐藏的 deprecated 警告。更关键的是每个依赖都要问一句“它为什么在这里”哪怕多一个 commons-io也可能因为传递依赖把 logback 挤走然后你得到一份神秘的日志空转。包结构先想清楚你打算活几年新建项目时IDEA 默认给你建一个主类然后你就开始往里面乱丢 Controller、Service、Mapper。三周后这个项目变成了一个三百层的巨无汉堡连你自己都找不到业务入口。包结构不是美术作业而是你的思维外骨骼。我见过最稳妥的起步方式是反向分层先建infrastructure配置、安全、公共工具、domain实体、仓储接口、application服务用例、interfaces对外 API。这种洋葱式结构的好处是你在一开始就强制隔离了外部依赖和核心逻辑。比如domain里的实体类绝不允许出现JsonFormat或者TableField这类注解那会让领域模型被框架绑架。很多项目从零开始就注定了重构的宿命原因只有一个他们在第一行代码时就放弃了分层的尊严。配置管理别把变量写死在配置文件里application.yml 里塞满数据库账号密码、第三方密钥、甚至某个内部服务的基础地址这是比代码里写死字符串更隐蔽的毒瘤。你在本地跑得好好的一上测试环境就 500因为配置里写的是localhost。配置文件的唯一职责是提供可替换的默认值而不是存储任何机密的真相。从搭建第一天就引入spring.profiles.active机制写application-dev.yml、application-prod.yml并且在bootstrap.yml里用环境变量占位符${DB_PASSWORD}。不要担心那多出来的几个文件它们在未来救命的次数绝对超过你的想象。另外敏感配置一律走环境变量或配置中心哪怕你就是自娱自乐的单人项目——因为泄露一次的代价远远高于搭建时的那点麻烦。还有个小细节spring.config.import这个属性在 SpringBoot 2.4 之后改变了加载方式如果发现配置没生效先检查这个。日志体系别让 System.out 毁掉排障新项目最容易犯的毛病是用System.out.println打印调试信息。你以为是省事其实是在给自己埋雷。日志是程序的听觉你阉割掉它就等于闭着眼写业务。从零搭建时直接引入 logback slf4j 并配置异步输出。日志级别要分清业务状态用 info参数跟踪用 debug错误堆栈用 error而绝不能用 println 来输出。你还需要考虑日志文件的滚动策略按天分割、保留 30 天这些规则写在logback-spring.xml里而不是写死在应用的配置中。我见过最悲催的情况某订单系统上线三天后磁盘被日志打满查了半天发现是某个基础库每秒钟打一条 warn。从一开始就给你的日志系统装上“刹车片”——对每个 logger 设置超长堆栈的截断阈值并强制核心业务必须带上 traceId。这玩意儿在分布式排查里是命根子但单机模式下同样重要。数据访问事务和连接池不是默认配置如果你用了 spring-boot-starter-jdbc 或 mybatis-plus你以为默认配置就万事大吉错。默认的 HikariCP 连接池最大连接数只有 10而你的接口一多就瞎等。可这只是冰山一角。从零开始的正确做法是手动声明一个DataSourceBean把连接池的初始大小、最大最小等待时间全写在配置里并且明确设置spring.datasource.hikari.connection-init-sql为SELECT 1。没有这一条数据库重启一次你的应用就卡死一遍。事务方面初学者在 Service 类上草率地加Transactional却没有想过它默认只回滚 RuntimeException而 checked exception 会让事务悄悄提交。这种错误连资深开发都可能中招。给所有业务类设计一个清晰的自定义异常体系并且在事务注解上显式指定rollbackFor Exception.class。更要命的是很多项目从零开始就忘记配置数据库连接的超时重连机制一旦网络抖动数据源里全是死连接。接口设计返回体与错误码从第一天就定死你可能觉得写接口嘛返回个 Map 或者直接返回实体类多方便。等到对接前端的时候前端同学要在每个接口里判断data到底是对象还是数组就只想骂人。接口规范不是后话而是项目生存的底线。从搭建那天起就要定义一个统一的ResultT包装类包含 code、message、data 三个字段并且提供一个全局异常处理器RestControllerAdvice。错误码别用 0 表示成功、-1 表示失败这种简陋方式那会导致你永远无法区分“参数错误”和“业务超时”。低错误粒度的项目最后只能靠猜来排障。另外ControllerAdvice里还要处理参数校验异常、数据库唯一键冲突、以及一些安全异常。我说的不是生搬硬套而是让你把这个能力变成项目的默认组件这样后面每个人写新接口时都自动继承这套标准。测试先建测试目录再写代码很多人在从零搭建时直接删掉 src/test 目录嫌它碍事。这是最愚蠢的删除行为。测试不是可选项它是你重构时唯一的安全绳。先别急着写业务至少先做三件事配置测试用的application-test.yml用 H2 或者 Testcontainers、引入 spring-boot-starter-test、然后写一个空的SpringBootTest类验证上下文能加载。然后给你的配置类写一个冒烟测试调用context.getBean检查核心 Bean 是否存在。这一步能帮你过滤掉 90% 的装配错误——比如某个 Bean 忘记加注解导致整个应用启动失败。你在大干一场之前必须确认地基能承受你的重量。等业务逻辑开始写建议强制用WebMvcTest和DataJpaTest切分测试边界别每次测试都把整个 Spring 容器跑起来不然三分钟后你就会想砸电脑。安全与校验先认输再谈保护你以为 SpringSecurity 是大型项目的专属错了。任何一个暴露在公网上的接口哪怕只是内网开发都值得在最开始就加认证机制。安全不是功能它是你所有业务的准入门槛。从零搭建时要决定用 session 还是 JWT如果是内部微服务建议直接集成 Spring Security 和 OAuth2 资源服务器至少需要设置默认的登录页和禁用 CSRF。往大了说CSRF、XSS、SQL 注入这些事儿不是靠写代码防御的而是靠框架约束。对参数校验一定要用ValidatedNotBlank这种声明式校验而不是在代码里手动写if (xxx null) return。手写校验等于把自己的眼睛蒙上跳舞哪一步都可能失足。必须配置全局的异常处理把校验错误信息翻译成用户能读的中文提示否则前端拿到的是一串英文模板用户体验极差。构建与部署Maven 插件别选太流行的最后说打包。你敲下mvn package得到一个 jar然后用java -jar跑起来好像大功告成了。但你有没有想过这个 jar 里真的只包含需要的东西吗很多从零搭建的项目死于无意义的依赖。用 spring-boot-maven-plugin 是标配但注意repackage和package的配合不要额外引入一个 fat jar 的插件。更关键的是你的 Dockerfile 必须写在项目最初阶段而不是发布前才想起来。先写一个示例 Dockerfile基于 eclipse-temurin加一个非 root 用户暴露端口设置 healthcheck。然后在 CI 里跑docker build确保每次改动不会破坏镜像。这个习惯能让你从物理机部署的痛苦中彻底解脱而且一旦出现环境不一致你只需对比镜像层就知道哪里出了问题。关于 JVM 参数最好在启动脚本里显式设置-Xms和-Xmx不要依赖默认值。默认的堆大小会让你在流量高峰突然 GC 停摆然后你会陷入“为什么线上比本地慢十倍”的幻觉。一个看似零搭建的项目实际上是在给你铺设一条长期的运行轨道。你选择省事的那几分钟未来会以十倍工时偿还。不要用战术上的勤奋来掩盖战略上的懒惰。从环境对齐、包结构、配置隔离、日志规范、数据访问、接口统一、测试保护、安全边界、到最后制品构建这十个关卡如果你在第一天就全部打通后面写起业务就像在高速公路上开车。否则你就是在沼泽地里裸奔。真正的效率不是用最少的代码启动而是用最少的痛苦演进。愿你的 SpringBoot 项目从第一个SpringBootApplication开始就有一个清晰的灵魂。