Spring Boot入门教程:60分钟快速上手(附真实项目踩坑实录)

张明
2025-12-15 17:54
阅读 622

上周五晚上11点,我瘫在工位上盯着屏幕上疯狂滚动的 java.lang.OutOfMemoryError: GC overhead limit exceeded,一边啃着便利店冷掉的饭团,一边默默把“精通Spring Boot”从简历里删掉。作为去年刚从英国某Top 5高校硕士毕业、带着满脑子分布式系统理论回国找工作的海归,谁能想到入职三个月了还在被一个简单的REST API折磨?

说真的,国内互联网公司的节奏比我在伦敦熬夜赶论文还狠。老板一句“下周上线”,测试同事一句“这个接口压测QPS才80?”,运维大哥一句“你这jar包怎么占了2G内存?”,分分钟让我怀疑自己是不是读了个假硕士。不过吐槽归吐槽,该学的技术还得学——于是就有了这篇《Spring Boot 60分钟快速上手》,纯实战经验总结,没废话,全是血泪教训。

背景:为什么是Spring Boot?

我们团队正在做一个电商促销活动的后端服务,需求很简单:用户下单时调用优惠券服务,判断能否使用优惠券。但问题在于,这个服务要扛住双11级别的流量(老板原话:“至少1万QPS吧,不多”)。之前用纯Servlet写,代码又臭又长,加个新功能得改十处配置,运维部署更是噩梦。

技术老大拍板:“重构!用Spring Boot!”
我内心OS:行吧,反正简历上也得有Spring Boot实战经验不是?

环境准备:别再被Maven搞崩心态

首先,别信网上那些“一行命令创建Spring Boot项目”的鬼话。现实是:

  • IDEA版本太旧?直接报错
  • Maven镜像源在国外?下载依赖等到天荒地老
  • JDK版本不对?Unsupported major.minor version 55.0 直接送你上西天

我的生产环境配置(上海租房党亲测有效):

# JDK 17(公司强制要求,别问为什么)
openjdk version "17.0.8" 2023-07-18

# Maven阿里云镜像(pom.xml里不用改,全局settings.xml加就行)
<mirrors>
  <mirror>
    <id>aliyunmaven</id>
    <mirrorOf>*</mirrorOf>
    <name>阿里云公共仓库</name>
    <url>https://maven.aliyun.com/repository/public</url>
  </mirror>
</mirrors>

然后用Spring Initializr(IDEA内置)勾选这几个核心依赖就够了:

  • Spring Web(必选,不然你写个寂寞)
  • Spring Data JPA(数据库操作简化神器)
  • MySQL Driver(别用H2,线上没人用)
  • Lombok(省去getter/setter,代码清爽一半)

项目结构:别一上来就搞微服务

很多教程一上来就给你整什么Nacos、Sentinel、Gateway,醒醒!你只是想跑个Hello World好吗?

我的建议:单体应用先跑通,再考虑拆。我们项目的目录结构长这样:

coupon-service/
├── src/main/java/com/example/coupon
│   ├── controller/     # 接口层
│   ├── service/        # 业务逻辑
│   ├── repository/     # 数据库操作
│   └── CouponApplication.java  # 启动类
├── src/main/resources
│   ├── application.yml # 配置文件(别用properties!)
│   └── data.sql        # 初始化脚本(开发用)

记住:controller只负责接收参数和返回结果,service写业务逻辑,repository只跟数据库打交道。别把SQL写在controller里,否则测试同事会拿你的工牌当飞镖靶子。

核心代码:一个能扛住压力的真实接口

下面是我写的优惠券校验接口,关键点都加了注释:

@RestController
@RequestMapping("/api/v1/coupons")
@RequiredArgsConstructor // Lombok自动生成构造函数注入
public class CouponController {

    private final CouponService couponService;

    /**
     * 校验优惠券是否可用
     * 注意:这里用了DTO做参数校验,别直接用Entity!
     */
    @PostMapping("/validate")
    public ResponseEntity<CouponValidationResponse> validateCoupon(
            @Valid @RequestBody CouponValidationRequest request) {
        try {
            CouponValidationResponse response = couponService.validate(request);
            return ResponseEntity.ok(response);
        } catch (CouponExpiredException e) {
            // 自定义异常处理,别让500暴露给前端
            return ResponseEntity.badRequest()
                .body(new CouponValidationResponse(false, "优惠券已过期"));
        }
    }
}

重点来了:别在service里直接写算法逻辑!比如判断优惠券是否满足满减条件,这种规则应该抽成独立的策略类:

// 满减优惠券校验策略
@Component
public class FullReductionValidator implements CouponValidator {
    
    @Override
    public boolean validate(Coupon coupon, Order order) {
        // 这里才是真正的算法逻辑
        if (order.getAmount().compareTo(coupon.getMinSpend()) < 0) {
            return false; // 订单金额不足
        }
        // ...其他校验逻辑
        return true;
    }
}

为什么这么干?因为产品经理明天可能就说:“我们要支持叠加优惠券!” 如果逻辑散落在service各处,改起来就是一场灾难。

配置优化:别让默认配置害死你

Spring Boot的默认配置在开发环境很爽,但在生产环境就是定时炸弹。以下是我们线上必须改的几项:

配置项 开发环境 生产环境 说明
server.tomcat.max-threads 200 500 默认200线程扛不住高并发
spring.datasource.hikari.maximum-pool-size 10 50 连接池太小会阻塞
management.endpoints.web.exposure.include * health,info 别把所有监控端点暴露出去
logging.level.com.example DEBUG WARN 别让日志把磁盘写爆

特别提醒:别在application.yml里写数据库密码!我们用的是K8s的Secret挂载,本地开发用application-local.yml(记得加到.gitignore)。

坑点总结:这些雷我替你踩过了

  1. JPA懒加载陷阱@OneToMany(fetch = FetchType.LAZY) 在controller返回JSON时会触发N+1查询,直接导致接口慢如蜗牛。解决方法:用@EntityGraph 或 DTO投影。

  2. 时间时区问题:MySQL存的时间比Java快8小时?在连接字符串加 serverTimezone=Asia/Shanghai

  3. 内存泄漏:用了@Async但没配线程池,结果默认线程池无界,OOM警告天天见。正确做法:

    @Configuration
    public class AsyncConfig {
        @Bean("taskExecutor")
        public Executor taskExecutor() {
            ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
            executor.setCorePoolSize(5);
            executor.setMaxPoolSize(10);
            executor.setQueueCapacity(100); // 关键!防止OOM
            executor.setThreadNamePrefix("async-pool-");
            executor.initialize();
            return executor;
        }
    }
    
  4. 健康检查失效:Spring Boot Actuator默认不检查数据库连通性。必须手动加:

    management:
      endpoint:
        health:
          show-details: always
      health:
        db:
          enabled: true
    

效果如何?

重构后,接口QPS从80提升到2200+(4核8G机器),内存占用稳定在500MB以内。上周五上线后,运维大哥终于没在群里@我了,测试同事甚至夸我“这次没写bug”(虽然我知道她是在阴阳怪气)。

更重要的是——我的简历终于可以光明正大地写“Spring Boot实战经验”了!毕竟在国内找工作,光有海外学历不够,得有能落地的技术栈。现在每天下班前还能准时溜去静安寺那家咖啡馆写博客,而不是在公司修祖传代码。

最后几句真心话

Spring Boot确实香,但别把它当银弹。它简化的是配置和集成,核心还是你的Java功底和系统设计能力。我在英国学的那些算法和系统原理,其实在调优时比框架本身更重要。

如果你也像我一样,刚回国找工作,被各种“精通Spring Cloud”、“三年高并发经验”的JD吓到——别慌。先把Spring Boot吃透,做出一个能跑的项目,面试时聊清楚你遇到的问题和解决方案,比背八股文有用多了。

对了,下期我打算写《Spring Boot + Redis缓存击穿实战》,因为昨天刚因为缓存雪崩被领导叫去喝茶…… 敬请期待(或者说,为我祈福)。


作者:坐标上海的海归码农,白天修BUG,晚上写博客。最近在面新工作,求内推(Java后端岗),简历可私~

评论 0

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