docs: 架构文档补充统一全局上下文GlobalContext,统筹tid/uid/uname获取和异步传递

This commit is contained in:
zhangjf 2026-02-15 11:42:20 +08:00
parent 43e6e41a4a
commit fccadf63c2

View File

@ -1240,8 +1240,171 @@ public class ReactiveContextFilter implements WebFilter {
}
```
**原 5. 用户上下文管理(已升级为支持异步的版本**
**5. 统一全局上下文管理GlobalContext**
为了统一管理和传递全局参数tid、uid、uname、traceId 等),设计一个综合的 GlobalContext
```java
/**
* 全局上下文持有者
* 统一管理租户ID、用户ID、用户名、TraceId等全局参数
* 支持同步和异步场景
*/
public class GlobalContext {
// ========== 全局参数键名 ==========
public static final String KEY_TENANT_ID = "tid";
public static final String KEY_USER_ID = "uid";
public static final String KEY_USERNAME = "uname";
public static final String KEY_TRACE_ID = "traceId";
public static final String KEY_TENANT_GROUP = "tgroup";
// ========== ThreadLocal 存储 ==========
private static final ThreadLocal<Map<String, Object>> CONTEXT = ThreadLocal.withInitial(HashMap::new);
// ========== 全局上下文载体(支持异步传递)==========
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public static class ContextSnapshot {
private String tenantId;
private Long userId;
private String username;
private String traceId;
private String tenantGroup;
private Map<String, Object> extra;
public static ContextSnapshot create() {
return ContextSnapshot.builder()
.tenantId(getTenantId())
.userId(getUserId())
.username(getUsername())
.traceId(getTraceId())
.tenantGroup(getTenantGroup())
.extra(new HashMap<>(getAll()))
.build();
}
public void apply() {
if (tenantId != null) set(KEY_TENANT_ID, tenantId);
if (userId != null) set(KEY_USER_ID, userId);
if (username != null) set(KEY_USERNAME, username);
if (traceId != null) set(KEY_TRACE_ID, traceId);
if (tenantGroup != null) set(KEY_TENANT_GROUP, tenantGroup);
if (extra != null) extra.forEach((k, v) -> {
if (!CONTEXT.get().containsKey(k)) set(k, v);
});
}
}
// ========== 基础操作 ==========
@SuppressWarnings("unchecked")
public static <T> T get(String key) { return (T) CONTEXT.get().get(key); }
public static void set(String key, Object value) {
CONTEXT.get().put(key, value);
if (value != null) MDC.put(key, String.valueOf(value));
}
public static void clear() {
CONTEXT.get().clear();
MDC.clear();
}
// ========== 便捷方法 ==========
public static String getTenantId() { return get(KEY_TENANT_ID); }
public static void setTenantId(String tenantId) { set(KEY_TENANT_ID, tenantId); }
public static Long getUserId() {
Object uid = get(KEY_USER_ID);
return uid instanceof String ? Long.valueOf((String) uid) : (Long) uid;
}
public static void setUserId(Long userId) { set(KEY_USER_ID, userId); }
public static String getUsername() { return get(KEY_USERNAME); }
public static void setUsername(String username) { set(KEY_USERNAME, username); }
public static String getTraceId() { return get(KEY_TRACE_ID); }
public static void setTraceId(String traceId) { set(KEY_TRACE_ID, traceId); }
// ========== 异步场景支持 ==========
public static ContextSnapshot snapshot() { return ContextSnapshot.create(); }
public static Runnable wrap(Runnable runnable) {
ContextSnapshot snapshot = snapshot();
return () -> { try { snapshot.apply(); runnable.run(); } finally { clear(); } };
}
public static <T> Callable<T> wrap(Callable<T> callable) {
ContextSnapshot snapshot = snapshot();
return () -> { try { snapshot.apply(); return callable.call(); } finally { clear(); } };
}
public static <T> Supplier<T> wrap(Supplier<T> supplier) {
ContextSnapshot snapshot = snapshot();
return () -> { try { snapshot.apply(); return supplier.get(); } finally { clear(); } };
}
public static <T> CompletableFuture<T> supplyAsync(Supplier<T> supplier, Executor executor) {
return CompletableFuture.supplyAsync(wrap(supplier), executor);
}
public static CompletableFuture<Void> runAsync(Runnable runnable, Executor executor) {
return CompletableFuture.runAsync(wrap(runnable), executor);
}
}
```
**6. GlobalContext 使用示例**
```java
// 同步场景
@Service
public class ProjectService {
public void createProject(ProjectDTO dto) {
String tid = GlobalContext.getTenantId();
Long uid = GlobalContext.getUserId();
String uname = GlobalContext.getUsername();
log.info("[{}] 租户 {} 用户 {} 创建项目", tid, uname);
Project project = new Project();
project.setTenantId(tid);
project.setCreatedBy(uid);
projectMapper.insert(project);
}
}
// 异步场景
@Service
public class AsyncService {
@Autowired private ThreadPoolExecutor executor;
public void asyncProcess(Long projectId) {
executor.execute(GlobalContext.wrap(() -> {
String tid = GlobalContext.getTenantId();
Long uid = GlobalContext.getUserId();
String uname = GlobalContext.getUsername();
log.info("[Async] 租户 {} 用户 {} 处理项目 {}", tid, uname, projectId);
Project project = projectMapper.selectById(projectId);
project.setProcessedBy(uid);
projectMapper.updateById(project);
}));
}
public CompletableFuture<Project> asyncQuery(Long projectId) {
return GlobalContext.supplyAsync(() -> {
log.info("[Async] 用户 {} 查询项目 {}", GlobalContext.getUsername(), projectId);
return projectMapper.selectById(projectId);
}, executor);
}
}
```
**原 5. 用户上下文管理(已合并到 GlobalContext**
**7. 调用链上下文过滤器(接收方)**
@ -2971,6 +3134,7 @@ fund-sys/
| v1.1 | 2026-02-13 | 补充多租户架构(一库多租户/一库一租户)和 Head 日志追踪设计 | zhangjf |
| v1.2 | 2026-02-13 | 补充 Shiro 认证框架、服务调用链 uid/uname 传递设计 | zhangjf |
| v1.3 | 2026-02-13 | 补充 HikariCP 连接池、支持异步场景的 UserContext 封装 | zhangjf |
| v1.4 | 2026-02-13 | 补充统一全局上下文 GlobalContext统筹 tid/uid/uname 获取和异步传递 | zhangjf |
---