我有一个 Java 8 项目,它通过自定义 Java 代理使用 Javassist 3.20.0-GA 在运行时重写字节码。目标是检测该方法,使原始主体由带有打印语句的 try/finally block 包装。例如,给定这个简单的方法:
public class TimeService {
public long getCurrentTime(){
long time = 0;
try {
time = System.currentTimeMillis();
}
catch(Throwable t){
time = -1;
}
System.out.println("The current time is "+time);
return time;
}
}
我想输出以下修改后的代码(不带注释):
public class TimeService {
public long getCurrentTime(){
try {
System.out.println("Start");
// BEGIN original code
long time = 0;
try {
time = System.currentTimeMillis();
}
catch(Throwable t){
time = -1;
}
System.out.println("The current time is "+time);
return time;
// END original code
}
finally {
System.out.println("Stop");
}
}
}
首先我尝试了以下代码:
CtClass ctClass = ClassPool.getDefault().get("com.example.test.TimeService");
CtMethod ctMethod = ctClass.getDeclaredMethod("getCurrentTime");
ctMethod.insertBefore("System.out.println(\"Start\");");
ctMethod.insertAfter("System.out.println(\"Stop\");", true);
这似乎适用于没有预先存在的 try/catch/finally block 的简单 void 方法,但是 getCurrentTime() 方法的输出很奇怪,System.out.println ("Stop") 语句被重复两次:
public long getCurrentTime() {
boolean var10 = false;
long var10000;
long var5;
try {
var10 = true;
System.out.println("Start");
long time = 0L;
try {
time = System.currentTimeMillis();
} catch (Throwable var11) {
time = -1L;
}
System.out.println("The current time is " + time);
var10000 = time;
var10 = false;
} finally {
if(var10) {
var5 = 0L;
System.out.println("Stop");
}
}
var5 = var10000;
System.out.println("Stop");
return var5;
}
上面的代码在没有错误时“有效”,但假装 System.currentTimeMillis() 抛出异常,然后 var10 永远不会设置为 < em>false,因此 System.out.println("Stop") 语句将被执行两次。使用 boolean 标志作为保护措施在这里效果不佳,因此我更愿意在方法的开头和结尾简单地插入一个 try/finally。
接下来我尝试像这样直接检测和替换方法:
CtClass ctClass = ClassPool.getDefault().get("com.example.test.TimeService");
CtMethod ctMethod = ctClass.getDeclaredMethod("getCurrentTime");
ctMethod.instrument(new ExprEditor(){
public void edit(MethodCall m) throws CannotCompileException {
String start = "{ System.out.println(\"Start\"); }";
String stop = "{ System.out.println(\"Stop\"); }";
m.replace("{ try {"+start+" $_ = $proceed($$); } finally { "+stop+" } }");
}
});
但这变成了乱码,在许多 try/catch/finally block 中多次重复打印输出 “Start” 和 “Stop”(太乱了,无法粘贴在这里)。
我不确定接下来要尝试什么,或者我是否使用了错误的 Javassist API 部分。看起来它应该非常简单——确实如此,使用简单的 void 方法——但是当返回值时,尤其是与预先存在的 try/catch/finally block 结合使用时,输出变得不可预测。
有什么想法或解决方法吗?
提前致谢。
最佳答案
生成的 getCurrentTime
是正确的。只有在抛出异常时才输入 if(var10)
语句。但在这种情况下,您永远不会到达 finally
语句下面的代码。 finally
不捕获异常,它只是执行一些代码并进一步抛出
生成的代码很奇怪,但它最终完成了它应该做的事情。消息“停止”将只打印一次。
关于java - 使用 Javassist 插入包装原始方法逻辑的 try/finally 逻辑,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41156596/