【发布时间】:2013-08-14 18:48:12
【问题描述】:
除了重新编译 rt.jar 之外,还有什么方法可以用我自己的调用替换 currentTimeMillis() 调用?
1#正确的做法是使用Clock对象和抽象时间。
我知道,但我们将运行由无数尚未实现 Clock 或自己实现的开发人员开发的代码。
2# 使用 JMockit 之类的模拟工具来模拟该类。
尽管这仅适用于禁用 Hotspot -Xint 并且我们使用下面的代码取得了成功,但它不会“持续”在外部库上。这意味着您必须在任何地方模拟它,因为代码超出了我们的控制范围,这是不可行的。 main() 下的所有代码都返回 0 milis(如示例所示),但 new DateTime() 将返回实际的系统 milis。
@MockClass(realClass = System.class)
public class SystemMock extends MockUp<System> {
// returns 1970-01-01
@Mock public static long currentTimeMillis() { return 0; }
}
3# 在启动时使用-Xbootclasspath/p重新声明System(已编辑)
虽然可能,并且您可以创建/更改方法,但有问题的方法被声明为public static native long currentTimeMillis();。如果不深入研究 Sun 的专有和 本机 代码,就无法更改它的声明,这将使其成为逆向工程的练习,并且几乎不是一种稳定的方法。
所有最近的 SUN JVM 崩溃并出现以下错误:
EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x00000, pid=4668, tid=5736
4# 使用自定义 ClassLoader(在 cmets 上建议的新测试)
虽然使用-Djava.system.class.loader JVM 替换系统 CL 很简单,但实际上使用默认的 classLoader 加载了自定义的 classLoader,并且系统甚至没有通过自定义的 CL 推送。
public class SimpleClassLoader extends ClassLoader {
public SimpleClassLoader(ClassLoader classLoader) {
super(classLoader);
}
@Override
public Class<?> loadClass(String name) throws ClassNotFoundException {
return super.loadClass(name);
}
}
我们可以看到java.lang.System是从rt.jar使用java -verbose:class加载的
Line 15: [Loaded java.lang.System from C:\jdk1.7.0_25\jre\lib\rt.jar]
我的选择已经不多了。
我缺少什么方法吗?
【问题讨论】:
-
AspectJ 可能是一个选项。
-
标志不足,但可能与 stackoverflow.com/questions/2001671/… 重复。
-
好吧,我想你总是可以使用 CGLIB 并使用他们的方法拦截器返回你自己的值。
-
好吧,使用
-Djava.system.class.loader选项替换系统类加载器? -
同样对于ClassLoader方式,可以在JVM命令行中指定自定义系统类加载器; 应该影响该 JVM 加载的所有库:
java -Djava.system.class.loader=your.package.CustomClassLoader ...