字段映射组件用 Method.invoke 处理 100 万条记录要 4.2 秒,改成直接调用只要 100 毫秒,CPU profile 里 reflect 相关栈占了三成。日志里能对上时间点,这种反而好排。

每次 invoke 都要做访问检查、参数装箱和数组拷贝,JIT 很难把调用点内联。调用越频繁,这部分固定开销越明显。这一点先确认清楚,后面就不用反复试。

MethodHandle mh = MethodHandles.lookup().unreflect(setter);
mh.invokeExact(target, (Object) value);
// 预热后再计时
for (int i = 0; i < 200000; i++) mh.invokeExact(target, (Object) "x");

这次卡住的地方就在「反射调用性能」这一环,单独把它拎出来验证,别和其他改动混在同一次发布里。线上出问题先对时间点,跟发布、备份、任务执行的时刻排一排,能省掉一半功夫。

日志级别临时调高可以,记得改回去,长期开着既占磁盘又掩盖真问题。权限不要一口气开到最大,先加到够用再往上试,范围小才好收。

处理上按这个顺序:把 Method 缓存成静态常量 不要每次 getDeclaredMethod;高频路径改用 MethodHandle 并提前 unreflect;或者用 LambdaMetafactory 生成函数式接口;setAccessible 只调一次 别放在循环里。

结果对不对很好判断,同一批 100 万条映射耗时降到 400 毫秒以内 profile 里反射栈占比低于 5%。

作者 9823189