MethodHandle分发器本质是用MethodHandle替代反射调用,配合简单查表(如ConcurrentHashMap)实现50%+性能提升;关键在于缓存类型匹配的句柄并用invokeExact执行,避免asType/bindTo等运行时开销,同时优先用VarHandle访问公有字段以进一步降延迟。

MethodHandle 本身不是分发器,也不内置路由或匹配机制;所谓“MethodHandle 分发器”,实际是指用 MethodHandle 作为底层执行单元,配合轻量级调度逻辑(如 Map
分发结构要简单,句柄执行要干净
消息分发的核心瓶颈往往不在路由判断(HashMap 查 key 或 enum switch 都极快),而在于后续方法调用本身。若每个分支仍走 method.invoke(obj, args),那再好的分发结构也白搭。
- 用
ConcurrentHashMap<class>, MethodHandle></class>缓存每种消息类型的处理句柄,key 是消息类,value 是已构造好的findVirtual或findStatic句柄 - 分发时只做一次类型查表:
MethodHandle mh = handlerMap.get(msg.getClass()); mh.invokeExact(msg); - 避免在分发逻辑中做
asType()、bindTo()或invokeWithArguments()—— 这些操作应提前完成并缓存
句柄必须按消息协议严格构造
消息对象通常是 POJO,分发目标可能是统一接口(如 MessageHandler.handle(T msg))或具体实现类的实例方法。此时句柄签名必须与目标方法完全一致,否则 invokeExact() 会失败。
- 若处理方法是
public void onUserCreated(UserCreatedEvent e),则句柄类型必须为MethodType.methodType(void.class, UserCreatedEvent.class) - 不要用
invoke()去“凑合”类型;报WrongMethodTypeException说明MethodType写错了,比如把UserCreatedEvent.class误写成Object.class - 对泛型消息(如
Command<t></t>),需在编译期确定具体类型,或用桥接方法封装,避免运行时擦除导致签名不匹配
优先考虑 VarHandle 替代字段访问类分发
某些分发场景本质是“根据消息字段值跳转”,例如按 msg.getType() 字符串分发到不同处理器。若该字段是 public 实例字段(如 String type),直接用 VarHandle 比 MethodHandle 更轻:
VarHandle vh = MethodHandles.lookup().findVarHandle(Message.class, "type", String.class);- 获取值:
String type = (String) vh.get(msg);,无异常路径、无对象分配、无适配开销 - 再用
switch (type)或Map.get(type)路由,整体延迟更低
私有处理器支持需跨模块显式授权
若消息处理器定义在模块内且方法为 private,不能靠 setAccessible(true) 绕过——MethodHandle 访问私有成员依赖 Lookup 权限边界。
- 必须在处理器所在类内部构建句柄:
static final MethodHandle HANDLE = MethodHandles.lookup().findSpecial(...); - 跨模块访问需在
module-info.java中声明:opens com.example.handler to your.dispatch.module; - 不可复用其他类的
Lookup实例查找私有方法,JVM 会拒绝










