docs: 架构文档补充统一全局上下文GlobalContext,统筹tid/uid/uname获取和异步传递
This commit is contained in:
parent
43e6e41a4a
commit
fccadf63c2
@ -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. 调用链上下文过滤器(接收方)**
|
**7. 调用链上下文过滤器(接收方)**
|
||||||
|
|
||||||
@ -2971,6 +3134,7 @@ fund-sys/
|
|||||||
| v1.1 | 2026-02-13 | 补充多租户架构(一库多租户/一库一租户)和 Head 日志追踪设计 | zhangjf |
|
| v1.1 | 2026-02-13 | 补充多租户架构(一库多租户/一库一租户)和 Head 日志追踪设计 | zhangjf |
|
||||||
| v1.2 | 2026-02-13 | 补充 Shiro 认证框架、服务调用链 uid/uname 传递设计 | zhangjf |
|
| v1.2 | 2026-02-13 | 补充 Shiro 认证框架、服务调用链 uid/uname 传递设计 | zhangjf |
|
||||||
| v1.3 | 2026-02-13 | 补充 HikariCP 连接池、支持异步场景的 UserContext 封装 | zhangjf |
|
| v1.3 | 2026-02-13 | 补充 HikariCP 连接池、支持异步场景的 UserContext 封装 | zhangjf |
|
||||||
|
| v1.4 | 2026-02-13 | 补充统一全局上下文 GlobalContext,统筹 tid/uid/uname 获取和异步传递 | zhangjf |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user