Spring Boot快速上手实战:从零到跑通一个后端服务

黄浩宇
2025-12-22 19:30
阅读 605

上周五晚上十点半,办公室只剩我和运维小哥还在对线上问题。那会儿我刚改完一个基础架构的配置中心推送逻辑,正准备收工,突然收到产品经理的钉钉:“兄弟,能不能帮忙搭个简单的管理后台?就几个接口,明天上线用。” 我看了一眼时间——离双11大促还有两周,我们组自己的中间件压测都还没跑完,结果还要帮业务方搭 CRUD 服务?

但转念一想:正好最近在刷 LeetCode 准备跳槽,顺手练练 Spring Boot 也好。毕竟在字节待了五年,虽然一直在搞自研 RPC 框架和注册中心,但对外招人面试时发现,很多候选人连 Spring Boot 的自动装配原理都说不清。于是我就决定:花一个小时,写个最简但能跑通生产级配置的服务,顺便记录下来,给那些和我一样“被迫营业”的后端兄弟们参考。


为什么是 Spring Boot?

别误会,我在字节内部主要用的是自研框架(基于 Netty + 自定义协议),性能高、监控全、链路追踪无缝集成。但对外输出或者临时支援业务时,Spring Boot 真的是“银弹”——生态成熟、文档齐全、社区活跃,连测试同学都能看懂 application.yml 里改个端口。

更重要的是,资源复用成本低。你随便拉一个 Java 后端,90% 都会 Spring Boot。不像我们内部框架,新来实习生光看 SPI 扩展机制就得懵三天。

所以,哪怕你是基础架构组的“高冷底层佬”,也得会 Spring Boot。不然哪天老板说“这个需求很简单,你搭个 demo 先跑起来”,你就只能硬着头皮上了。


环境准备:Java 别用太老的版本

先确认你的本地环境:

java -version

建议 Java 17 起步。我知道很多老项目还在用 Java 8,但在字节,新服务基本都 Java 17+ 了。Spring Boot 3.x 甚至要求最低 Java 17,如果你还卡在 Java 8,有些新特性比如虚拟线程(Project Loom)就玩不起来。

Maven 或 Gradle 随便选,我个人偏好 Maven(公司模板统一),但如果你喜欢 Kotlin 或更灵活的构建脚本,Gradle 也不错。


第一步:生成项目骨架

打开 https://start.spring.io,这是 Spring 官方的初始化器,比手动建模块快多了。

我这次选的配置如下:

  • Project: Maven
  • Language: Java
  • Spring Boot: 3.2.5(最新稳定版)
  • Group: com.example
  • Artifact: quick-start-demo
  • Dependencies:
    • Spring Web
    • Spring Data JPA
    • H2 Database(开发用内存数据库,省事)
    • Validation
    • Lombok

💡 小技巧:别一上来就加 MyBatis、Redis、Kafka。先跑通最简流程,再按需引入。很多新人一建项目就堆 10 个 starter,结果连 @RestController 返回 JSON 都配错。

点“Generate”下载 ZIP,解压后导入 IDEA。


第二步:写一个能跑的接口

新建一个 Controller:

@RestController
@RequestMapping("/api/v1")
public class DemoController {

    @GetMapping("/hello")
    public String hello() {
        return "Hello, Spring Boot!";
    }
}

启动类保持默认:

@SpringBootApplication
public class QuickStartDemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(QuickStartDemoApplication.class, args);
    }
}

运行 main 方法,看到控制台输出:

Tomcat started on port(s): 8080 (http)

浏览器访问 http://localhost:8080/api/v1/hello,返回 Hello, Spring Boot! —— 搞定!不到 5 分钟。

但别高兴太早,这离“能上线”还差十万八千里。


第三步:加个数据库,别只玩字符串

产品经理要的是管理后台,肯定有数据存储。我们用 JPA + H2 快速演示。

先定义一个实体:

@Entity
@Table(name = "users")
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    @NotBlank
    private String name;
    
    @Email
    private String email;
}

Repository 接口:

public interface UserRepository extends JpaRepository<User, Long> {
}

Controller 补充:

@PostMapping("/users")
public ResponseEntity<User> createUser(@Valid @RequestBody User user) {
    User saved = userRepository.save(user);
    return ResponseEntity.ok(saved);
}

@GetMapping("/users/{id}")
public ResponseEntity<User> getUser(@PathVariable Long id) {
    return userRepository.findById(id)
        .map(ResponseEntity::ok)
        .orElse(ResponseEntity.notFound().build());
}

配置文件 application.yml

spring:
  datasource:
    url: jdbc:h2:mem:testdb
    driver-class-name: org.h2.Driver
  jpa:
    hibernate:
      ddl-auto: create-drop
    show-sql: true
  h2:
    console:
      enabled: true

现在你可以:

  • POST /api/v1/users 创建用户
  • GET /api/v1/users/1 获取用户
  • 访问 http://localhost:8080/h2-console 查看内存数据库(JDBC URL 填 jdbc:h2:mem:testdb

🚨 注意:ddl-auto: create-drop 只用于开发!生产环境必须用 Flyway 或 Liquibase 管理 schema,否则 DBA 会追杀你。


第四步:配置分离与生产就绪

在字节,所有服务都要求配置外置、日志结构化、健康检查完备。Spring Boot 天然支持这些。

1. 多环境配置

创建:

  • application-dev.yml(开发)
  • application-prod.yml(生产)

主配置 application.yml 中指定:

spring:
  profiles:
    active: dev

生产配置示例(关键项):

server:
  port: 8080
  shutdown: graceful  # 平滑关闭,避免请求中断

logging:
  level:
    com.example: INFO
  pattern:
    console: "%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n"
  file:
    name: logs/app.log

management:
  endpoints:
    web:
      exposure:
        include: health,info,metrics,prometheus
  endpoint:
    health:
      show-details: always

这样,/actuator/health 就能被 K8s 的 liveness probe 调用,运维同学再也不用半夜 call 你说“服务挂了但进程还在”。

2. 资源路径与静态文件

Spring Boot 默认从 classpath:/static/ 提供静态资源。如果你要嵌入一个简单的前端页面(比如 Swagger UI 或管理面板),直接放进去就行。

但注意:不要把敏感配置或内部工具暴露在公网。我们曾经有个实习生把 Actuator 端点全开,结果被安全扫描扫出一堆 info 泄露,差点背 PIP。


第五步:打包与部署

执行:

./mvnw clean package

生成 target/quick-start-demo-0.0.1-SNAPSHOT.jar

运行:

java -jar target/*.jar --spring.profiles.active=prod

在字节,我们会把这个 JAR 打包进 Docker 镜像,然后由 ArgoCD 自动部署到 K8s。但如果你只是本地测试或小团队,直接 nohup java -jar ... & 也能凑合。

💡 经验之谈:JAR 包默认包含 Tomcat,所以一个文件就能跑。但如果你追求极致性能(比如 QPS > 1w),可以考虑换成 Undertow 或 Netty,不过对大多数业务场景,Tomcat 足够了。


踩坑记录:那些让我想砸键盘的瞬间

  1. Lombok 不生效
    IDEA 没装 Lombok 插件,或者 Maven 没加 annotation processor。解决:装插件 + 在 pom.xml<annotationProcessorPaths>

  2. H2 数据库连接失败
    控制台提示 Database may be already in use。原因:上次进程没关干净。解决:删掉 *.mv.db 文件,或改用 jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1

  3. 跨域问题
    前端调接口报 CORS 错误。别急着加 @CrossOrigin,最好在网关层统一处理。临时方案:

    @Bean
    public CorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration config = new CorsConfiguration();
        config.setAllowedOrigins(List.of("*"));
        config.setAllowedMethods(List.of("*"));
        config.setAllowedHeaders(List.of("*"));
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", config);
        return source;
    }
    
  4. 时区不对
    数据库存的时间比本地早 8 小时。在 application.yml 加:

    spring:
      jpa:
        properties:
          hibernate.jdbc.time_zone: UTC
      datasource:
        url: jdbc:mysql://...?serverTimezone=Asia/Shanghai
    

性能与资源考量

虽然 Spring Boot 上手快,但它不是“轻量级”。一个空服务启动就要 1~2 秒,内存占用 200MB+。在字节的基础架构组,我们经常对比:

框架 启动时间 内存占用 冷启动延迟 适用场景
Spring Boot 1.5s 250MB 中后台、业务服务
Quarkus 0.3s 80MB 极低 Serverless、边缘计算
自研 RPC 框架 0.8s 150MB 高并发核心链路

所以,别无脑上 Spring Boot。如果你要做高频交易系统或 IoT 设备代理,它可能不是最优解。但对于 90% 的企业应用,它的开发效率碾压一切。


最后:别只停留在“能跑”

我见过太多人学 Spring Boot 到“能返回 JSON”就停了。但真正的差距在于:

  • 你会不会看 @ConditionalOnClass 源码理解自动装配?
  • 你会不会用 Micrometer 接入 Prometheus 做指标监控?
  • 你会不会通过 @Async + 线程池优化耗时操作?
  • 你会不会用 @Transactional 的传播行为避免脏读?

这些才是面试官想听的,也是你在字节、阿里、腾讯这类公司立足的根本。


结语

这篇文章花了我两个深夜(没错,又是凌晨一点),但值得。因为 Spring Boot 虽然简单,但简单不等于肤浅。掌握它,是你从“CRUD 工程师”迈向“系统设计者”的第一步。

现在,我的管理后台已经上线了,产品经理发了个红包。而我,继续回去刷我的算法题——毕竟,下一份 offer 还在等着我。

如果你觉得有用,欢迎转发给那个还在手写 Servlet 的兄弟。共勉。

评论 0

最热最新
暂无评论
匿名用户Lv.1
0
影响力
0
文章
0
粉丝