自研组件库通过错误码注册中心、线程池任务包装器、全局异常处理器及模块隔离四机制,实现异常ID与错误码强绑定,确保可追溯、可收敛、可校验。

在自研组件库中实现唯一异常 ID 与线程池异常错误码的强绑定,核心不是“给每个异常加个随机 ID”,而是构建一套**可追溯、可收敛、可校验**的异常标识体系。重点在于:ID 不是事后生成的,而是随异常源头定义、在线程执行上下文中透传、在统一出口处强制校验。
一、错误码注册中心 + 唯一 ID 生成规则
避免靠人工写死或拼接字符串导致冲突,必须由框架层自动管控:
- 所有业务模块提交错误码时,必须通过 统一注册接口(如
ErrorCodeRegistry.register(module, bizCode, message)),模块名(如"order"、"pay")作为命名空间前缀 - 错误码格式强制为
{module}_{3位数字},例如order_001、pay_027;注册时校验全局唯一性,重复则启动失败并报明确错误 - 每个错误码实例内部自动生成唯一异常 ID(UUID 或 Snowflake ID),但该 ID 不对外暴露给调用方,仅用于日志追踪和链路归因
二、线程池任务包装器注入上下文 ID
线程池中 Runnable/Callable 的执行是“无状态”的,必须主动携带异常上下文:
- 封装一个通用任务包装器
TracedTask,构造时从当前线程 MDC 或显式传入 traceId + errorScope(如"order-create") - 在
run()或call()执行前后,将该 scope 绑定到当前线程(如MDC.put("error_scope", scope)),确保异常发生时能定位到具体业务环节 - 若使用
submit()提交 Callable,其 Future.get() 抛出的ExecutionException可被拦截,提取原始异常并注入已注册的错误码 + 当前 scope ID
三、全局异常处理器做终局校验与标准化
无论异常来自 Runnable 内部、Future.get() 还是线程中断,最终都收口到统一出口:
- 设置
Thread.setDefaultUncaughtExceptionHandler,并在自定义ThreadFactory中为每个线程设置专属 handler,确保线程池工作线程不漏异常 - handler 中对异常做三步处理:
① 判断是否为已注册的业务异常(检查是否继承自BaseBizException且含有效errorCode)
② 若未注册,拒绝抛出,降级为兜底错误码(如system_999),并记录告警日志(含堆栈+线程名+scope)
③ 强制附加唯一追踪 ID(取自 MDC 或生成新 ID),写入日志并透传至监控系统
四、禁止跨模块复用错误码,强制模块隔离
这是避免冲突最硬性的工程约束:
- 错误码类不提供公共 static 实例,每个模块必须声明自己的常量类(如
OrderErrorCodes、PayErrorCodes),且类名与模块名严格对应 - 编译期通过注解处理器扫描所有
*ErrorCodes类,校验 code 字段是否符合{module}_\d{3}格式,不符合则编译失败 - 运行时禁止通过反射或字符串拼接动态构造错误码;所有
throw new BizException("xxx_001")必须经由注册中心解析,未注册即抛IllegalErrorCodeException

















