📖 本章预览
本章为预览版本,展示部分核心内容。完整内容包含详细源码解析、实战代码和面试要点,加入知识星球即可解锁全部章节。
第七章:生产环境任务被悄悄丢掉了你居然不知道 — 拒绝策略代理增强
本章目标:理解 JDK 动态代理如何透明增强拒绝策略,掌握 try-finally + InvocationTargetException 解包的并发编程细节,学会通过 SPI 自定义拒绝策略。
7.1 JDK 拒绝策略的盲区
JDK 的 RejectedExecutionHandler 只负责"怎么拒绝"(抛异常、丢弃、调用者执行),但不负责"拒绝了要通知谁"。
在生产环境中,任务被拒绝是非常严重的事件,你需要:
- 记录拒绝次数(监控指标)
- 触发告警通知(钉钉/企微/飞书)
- 记录被拒绝的任务信息(排查问题)
如果在每个拒绝策略里都加这些逻辑,代码重复且侵入性强。
DynamicTP 的方案:用 JDK 动态代理透明包装原始拒绝策略,在拒绝前后自动触发 AwareManager 的增强逻辑。
7.2 RejectHandlerGetter — 工厂 + 代理创建
public class RejectHandlerGetter {
/**
* 根据名称构建拒绝策略实例
* 先匹配 JDK 内置的 4 种,匹配不到就走 SPI 加载用户自定义的
*/
public static RejectedExecutionHandler buildRejectedHandler(String name) {
if (Objects.equals(name, ABORT_POLICY.getName())) {
return new ThreadPoolExecutor.AbortPolicy();
} else if (Objects.equals(name, CALLER_RUNS_POLICY.getName())) {
return new ThreadPoolExecutor.CallerRunsPolicy();
} else if (Objects.equals(name, DISCARD_OLDEST_POLICY.getName())) {
return new ThreadPoolExecutor.DiscardOldestPolicy();
} else if (Objects.equals(name, DISCARD_POLICY.getName())) {
return new ThreadPoolExecutor.DiscardPolicy();
}
// SPI 加载自定义拒绝策略
List<RejectedExecutionHandler> loadedHandlers =
ExtensionServiceLoader.get(RejectedExecutionHandler.class);
for (RejectedExecutionHandler handler : loadedHandlers) {
if (name.equalsIgnoreCase(handler.getClass().getSimpleName())) {
return handler;
}
}
throw new DtpException("Cannot find specified rejectedHandler " + name);
}
/**
* 用 JDK 动态代理包装拒绝策略
*/
public static RejectedExecutionHandler getProxy(
RejectedExecutionHandler handler) {
return (RejectedExecutionHandler) Proxy.newProxyInstance(
handler.getClass().getClassLoader(),
new Class[]{RejectedExecutionHandler.class},
new RejectedInvocationHandler(handler));
}
}
为什么用 JDK 动态代理而不是 CGLIB?因为 RejectedExecutionHandler 是接口,JDK 代理就够了,且不需要额外依赖。
7.3 RejectedInvocationHandler — 代理核心逻辑
@Slf4j
public class RejectedInvocationHandler implements InvocationHandler {
private final Object target; // 原始拒绝策略
public RejectedInvocationHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
// args[0] = 被拒绝的 Runnable
// args[1] = ThreadPoolExecutor 实例
beforeReject((Runnable) args[0], (Executor) args[1]);
try {
// 执行原始拒绝策略
return method.invoke(target, args);
} catch (InvocationTargetException ex) {
// 解包代理异常,抛出原始异常
throw ex.getCause();
} finally {
// 无论拒绝策略是否抛异常,afterReject 都会执行
afterReject((Runnable) args[0], (Executor) args[1]);
}
}
🔒 解锁完整内容
本章剩余内容需要解锁后查看
以上仅为本章部分预览内容,完整内容包含更多深度源码解析、实战代码和面试要点。
加入知识星球你将获得:
- ✅ 全部 12 章完整内容 + 持续更新
- ✅ 配套源码 + 实战项目
- ✅ 一对一答疑 + 面试辅导
- ✅ 简历优化 + 内推机会
📚 本章完整目录
以下为本章完整目录结构,加入知识星球即可解锁全部内容。