BaseContext:如何在Service层“隔空取物”获取当前登录用户ID?

在做Spring Boot 的 Web 项目时,在 Controller 或 Service 层经常会看到这样一行代码:

ini 复制代码
// 在 Service 层直接获取当前登录用户的ID 
Long userId = BaseContext.getCurrentId();

这就很神奇了:

  1. 没有传参 :Controller 调用 Service 时,并没有把 userId 作为参数传进来
  2. 没有查库:这一行代码也没有去查询数据库
  3. 数据准确:它总是能精准地拿到当前发送请求的那个用户的 ID,张三发请求拿到张三,李四发请求拿到李四,互不干扰

它是怎么做到的?

有两个核心概念:ThreadLocal 和 Tomcat 的"一请求一线程"模型。

1.容器:ThreadLocal (线程局部变量)

BaseContext 只是一个包装类,它内部的核心是 JDK 提供的 ThreadLocal。

csharp 复制代码
public class BaseContext {
    // 核心:ThreadLocal 对象
    public static ThreadLocal<Long> threadLocal = new ThreadLocal<>();

    public static void setCurrentId(Long id) {
        threadLocal.set(id); // 存入
    }

    public static Long getCurrentId() {
        return threadLocal.get(); // 取出
    }
    
    public static void removeCurrentId() {
        threadLocal.remove(); // 清除
    }
}

ThreadLocal 的作用:

当我们在 线程 A 中往 ThreadLocal 存入数据时,只有 线程 A 能取出来

线程 B 即使访问同一个变量,也完全摸不到 线程 A 的数据

这就是线程隔离(Thread Safety)

2.环境:Tomcat 的"一请求一线程"模型

Spring Boot 内置的 Web 服务器通常是 Tomcat。Tomcat 处理请求的机制是:One Request, One Thread (一个 HTTP 请求,由一个独立的线程全程负责)

当一个用户发起请求(比如"添加购物车")时:

Tomcat 分配 线程 X 来处理这个请求

拦截器 (Interceptor) 是 线程 X 执行的

Controller 是 线程 X 执行的

Service 还是 线程 X 执行的

Mapper 依然是 线程 X 执行的

结论: 只要我们没有手动开启新线程(new Thread),整个后端业务流程就像一场接力赛,但是是同一个运动员(线程 X) 从头跑到尾

流程

基于以上两个原理,我们可以还原 userId 是如何从请求头一步步流转到 Service 层的:

第一步:拦截器 (存入)

请求刚到达后端,拦截器(JwtTokenUserInterceptor)最先拦截

第二步:Controller

拦截器放行后,代码进入 Controller

第三步:Service (取出)

代码进入 Service 层

为什么要这么设计?

使用 ThreadLocal (BaseContext) 的方案,实现了数据在同一线程内的"隐式传递",让代码极其简洁优雅。

总结

  1. BaseContext 利用 ThreadLocal 实现了线程内部的数据隔离存储。
  2. Tomcat 保证了从拦截器到 Service 处于 同一个线程 中。
  3. 二者结合,让我们可以在 Service 层"隔空"获取 Controller 层(拦截器)解析的数据,极大简化了代码结构。
相关推荐
子兮曰3 天前
jev-ultrafast 深度解析:7 秒订机票的浏览器 Agent 是如何炼成的
前端·后端·agent
子兮曰3 天前
Jev 爆发一周:7 秒 Agent 背后的 System One 生态与三场争议
前端·后端·ai编程
爱勇宝3 天前
ZCode 开源 24 小时:一份没有历史的账本,回答不了"有没有偷代码"
前端·后端·chatglm (智谱)
胡写代码3 天前
别再前后端各写一套表单校验了
java·后端
大勇前进3 天前
原生 PHP 还是 Laravel?小项目到底要不要上框架
后端
yuzhi_liu3 天前
我用 LangGraph4j 实现 Multi-Agent Supervisor
后端
alsmile3 天前
Node-RED 之外,国产规则引擎的新方案:基于标准语法,Go 先行实现
后端·开源·go
大白803 天前
PHP 内存溢出排查思路:看懂报错日志,精准定位问题
后端
二月龙3 天前
PHP 接口返回统一响应封装,让前后端对接更省心
后端
盖伦发发3 天前
软件工程SOLID 五大设计原则
后端·软件工程