Skip to content

2026-08-30 · 拿到不熟悉的 Spring Boot 项目,用 Debug 跟一次请求,看它经过哪些类。

用 Debug 追踪请求链路(以 rbac-system 登录为例)

1. 这个方法解决什么问题

拿到一个不熟悉的 Spring Boot 项目,想知道它用了什么、请求经过哪些类。用 Debug 打断点,跟一次请求,调用栈会显示请求走过的路。这套方法对任何 Spring Boot 项目通用。

下面以 rbac-system 登录为例,一步步操作。

2. 前置

  • rbac-system 已在 IDEA 打开,能启动(MySQL 3306 / Redis 6379 在跑,8080 空闲)
  • 用 Debug 启动(甲虫图标)。Run(绿色三角)只启动不暂停,Debug 才会在断点停住

3. 第一步:登录入口打断点

打开 src/main/java/com/zgqin/rbacsystem/system/controller/AuthController.java,在 login() 方法第一行左侧点一下,打红点:

java
@PostMapping("/login")
public Result<LoginResponse> login(@Valid @RequestBody LoginRequest req, HttpServletRequest request) {
    return Result.ok(authService.login(req, request));   // ← 断点打这行
}

点右上角 Debug 启动,等控制台出现 Tomcat started on port 8080

4. 第二步:发请求,触发断点

Git Bash 终端执行(IDEA 底部 Terminal → 左上角下拉 → 选 Git Bash;curl 打网络地址,跟当前目录无关,不用 cd):

bash
curl -X POST http://localhost:8080/api/auth/login \
  -H "Content-Type: application/json" \
  -d '{"username":"root","password":"root"}'

请求停在断点,IDEA 自动切到 Debug 窗口。看两处:

  1. Frames(左下角调用栈):从上往下是请求走过的路
login:28, AuthController
doInvoke:..., InvocableHandlerMethod
invokeAndHandle:..., ServletInvocableHandlerMethod
...
doDispatch:..., DispatcherServlet       ← 请求入口
  1. Variables(右侧变量):能看到 req(请求体)、request(HTTP 请求)

点 F7(Step Into)走进 authService.login(),继续看。

5. 第三步:F7 跟进 AuthService.login(),看登录做了什么

方法内有注释标好的步骤(// 0. 防爆破// 1. 查用户...)。F7 一步一步走,每步经过什么:

步骤做什么用到什么
0. 防爆破isLoginLocked() 读 Redis login:fail:{username}Redis
1. 查用户userMapper.selectOne(...) 按用户名查用户MySQL + MyBatis-Plus
2. 校验密码passwordEncoder.matches(...) BCrypt 比对spring-security-crypto
5. 查角色/权限userMapper.selectRoleCodesByUserId(...) join 4 张表MyBatis-Plus
6. 签发 JWTjwtUtil.createToken(...) 生成令牌jjwt
6.6 登记会话onlineSessionService.createSession(...) 写 Redis 会话Redis
7. 返回组装 LoginResponse 返回前端

走完这一步,这个项目用了什么就都看到了:Redis、MySQL、MyBatis-Plus、jjwt、BCrypt。

5.1 调试节奏:F7 进 / F8 过 / Shift+F8 出

快捷键作用什么时候用
F8 步过执行当前行,不进入方法内部走主流程,一行行看
F7 步入钻进当前行调用的方法内部想确认这个方法用了什么(Redis?MySQL?)
Shift+F8 步出从当前方法跳回上一层看完方法内部,回主流程

思路:F7 进哪个类,这个请求就用到了哪个技术。想确认某一步用了什么,F7 进去看第一行代码用了什么组件,看完 Shift+F8 回来。

5.2 登录链路调试路线图(对照表)

return Result.ok(authService.login(req, request)) 按 F7 进入 AuthService.login() 后:

操作停在哪你看到的说明什么
F7isLoginLocked()redisTemplate.opsForValue().get(LOGIN_FAIL_KEY...)Redis:防爆破计数
Shift+F8 回来,F8userMapper.selectOne(...)查用户MySQL + MyBatis-Plus
F8passwordEncoder.matches(...)比对密码哈希BCrypt:密码不存明文
F8 走到 jwtUtil.createToken(...)第 134 行附近Jwts.builder()...signWith(key)...jjwt:F7 进去看生成 token 的过程
Shift+F8 回来,F8onlineSessionService.createSession(...)写会话Redis:登记会话(登出可吊销)
F8组装 LoginResponse返回体登录完成

F7 进去看到 redisTemplateJwts.builder() 这些名字,就亲眼确认了"登录要经过 Redis、要生成 token"——这就是你想要的"项目用了什么"的证据。

6. 第四步:故意输错密码,看异常怎么处理

先让程序继续跑完(F9),再在 Git Bash 输错密码登录:

bash
curl -X POST http://localhost:8080/api/auth/login \
  -H "Content-Type: application/json" \
  -d '{"username":"root","password":"wrong"}'

这次请求不会停在断点(密码错误走异常分支)。打开 exception/GlobalExceptionHandler.java,看 handleBiz()

java
@ExceptionHandler(BizException.class)
public ResponseEntity<Result<Void>> handleBiz(BizException e) { ... }

流程:Service 抛 BizException → 这里接住 → 转成 {code:401, msg:"用户名或密码错误", data:null}。统一返回格式就是在这里保证的。

7. 第五步:加第二个断点,看带 token 的请求

interceptor/AuthInterceptor.javapreHandle() 第一行打断点,用登录返回的 token 请求(Git Bash 执行):

bash
curl http://localhost:8080/api/system/user/list \
  -H "Authorization: Bearer <token>"

请求先停在 AuthInterceptor,然后才进 Controller。调用栈显示:

preHandle, AuthInterceptor
preHandle, PermissionInterceptor
page, UserController

顺序:认证(你是谁)→ 鉴权(你能干什么)→ 业务代码。

8. 常见坑

现象解法
Debug 启动报端口被占用杀掉占 8080 的进程(netstat -ano | grep 8080 找 PID)
断点不停确认用 Debug(甲虫)启动,不是 Run
断点灰掉方法没被调用,或改了代码没重启(devtools 会自动重启)
复制聊天里的命令出现 @url:\E[200~ 报错别从聊天界面直接复制命令,会被改坏;手打一遍最稳