我知道这个线程很旧,并且已经接受了答案并暗示了我的答案,但我想我可以用更多的细节和代码来节省别人的时间。我希望有人前段时间对我做过=)
我试图包装 java.lang.Thread#sleep 函数。我找到了 bytebuddy 的示例,但有方法替换,没有 javassist 的示例。最后我做到了。第一步是注册变压器和设置前缀:
instrumentation.addTransformer(transformer, true);
instrumentation.setNativeMethodPrefix(transformer, "MYPREFIX_");
然后在transformer里面修改Thread类:
@Override
public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
if (!"java/lang/Thread".equals(className)) {
return null;
}
try {
// prepare class pool with classfileBuffer as main source
ClassPool cp = new ClassPool(true);
cp.childFirstLookup = true;
cp.insertClassPath(new ByteArrayClassPath(Thread.class.getName(), classfileBuffer));
CtClass cc = cp.get(Thread.class.getName());
// add native method with prefix
CtMethod nativeSleep = CtMethod.make("void MYPREFIX_sleep(long millis) throws InterruptedException;", cc);
nativeSleep.setModifiers(Modifier.PRIVATE + Modifier.STATIC + Modifier.NATIVE);
cc.addMethod(nativeSleep);
// replace old native method
CtMethod m = cc.getDeclaredMethod("sleep", new CtClass[]{CtClass.longType});
m.setModifiers(Modifier.PUBLIC + Modifier.STATIC); // remove native flag
m.setBody("{" +
"System.out.println(\"Start sleep\");" +
"MYPREFIX_sleep($1);" +
"}");
byte[] byteCode = cc.toBytecode();
cc.detach();
return byteCode;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
然后开始改造:
instrumentation.retransformClasses(Thread.class);
像 java.lang.Thread 这样的类的问题之一是,通常你不能从修改的方法调用你的代码,除非你在引导类加载器中推送一些东西。
另请参阅https://docs.oracle.com/javase/8/docs/api/java/lang/instrument/Instrumentation.html#setNativeMethodPrefix-java.lang.instrument.ClassFileTransformer-java.lang.String-了解 jvm 的详细信息解决方法。