[英]Spring MVC exception - Invoking request method resulted in exception : public static native long java.lang.System.currentTimeMillis()
[英]java.lang.System.currentTimeMillis() replace method
除了重新編譯rt.jar
之外,還有什么方法可以用我自己的方法替換currentTimeMillis()
調用嗎?
1# 正確的做法是使用Clock
對象和抽象時間。
我知道,但我們將運行由無數尚未實現Clock
或已實現自己的開發人員開發的代碼。
2# 使用像 JMockit 這樣的模擬工具來模擬該類。
即使這僅適用於禁用熱點-Xint
並且我們使用下面的代碼取得了成功,但它不會“持久”在外部庫上。 這意味着您必須在任何地方模擬它,因為代碼不受我們控制,這是不可行的。 main()
下的所有代碼都返回 0 毫秒(如示例所示),但new DateTime()
將返回實際的系統毫秒。
@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# 使用自定義類加載器(根據評論建議進行新測試)
雖然使用-Djava.system.class.loader
替換系統 CL 很簡單, -Djava.system.class.loader
JVM 實際上加載自定義 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
是使用java -verbose:class
從rt.jar
加載的
Line 15: [Loaded java.lang.System from C:\jdk1.7.0_25\jre\lib\rt.jar]
我的選擇不多了。
有什么我想念的方法嗎?
您可以使用 AspectJ 編譯器/編織器來編譯/編織有問題的用戶代碼,用您自己的代碼替換對 java.lang.System.currentTimeMillis() 的調用。 以下方面將做到這一點:
public aspect CurrentTimeInMillisMethodCallChanger {
long around():
call(public static native long java.lang.System.currentTimeMillis())
&& within(user.code.base.pckg.*) {
return 0; //provide your own implementation returning a long
}
}
我不是 100% 確定我是否在這里監督某些事情,但是您可以像這樣創建自己的System
類:
public static class System {
static PrintStream err = System.err;
static InputStream in = System.in;
static PrintStream out = System.out;
static void arraycopy(Object src, int srcPos, Object dest, int destPos, int length) {
System.arraycopy(src, srcPos, dest, destPos, length);
}
// ... and so on with all methods (currently 26) except `currentTimeMillis()`
static long currentTimeMillis() {
return 4711L; // Your application specific clock value
}
}
而不是在每個 java 文件中導入您自己的System
類。 在 Eclipse 中重新組織導入應該可以解決問題。 並且所有 java 文件都應該使用您的應用程序特定的System
類。
正如我所說,這不是一個好的解決方案,因為每當 Java 更改原始類時,您都需要維護您的System
類。 此外,您必須確保始終使用您的課程。
正如評論中所討論的,原始問題中的選項 #3 可能確實有效,成功替換了默認的System
類。
如果這是真的,那么調用currentTimeMillis()
應用程序代碼將按預期調用替換。
也許出乎意料的是,像java.util.Timer
這樣的核心類也會被替換!
如果上述所有情況均屬實,那么崩潰的根本原因可能是System
類的成功替換。
為了進行測試,您可以將System
替換為功能與原始版本相同的副本,以查看崩潰是否消失。
不幸的是,如果這個答案被證明是正確的,那么我們似乎又有了一個新問題。 :) 它可能是這樣的:
“您如何向應用程序類提供更改后的
System.currentTimeMillis()
,但為核心類保留默認實現?”
我曾嘗試使用 javassist 刪除本機 currentTimeMills,添加一個純 Java 並使用 bootclasspath/p 加載它,但我遇到了與您相同的異常訪問沖突。 我相信這可能是因為在靜態塊中調用了本機方法 registerNatives ,但是反匯編本機庫確實太多了。
因此,與其更改 System.currentTimeMills,不如更改用戶代碼? 如果用戶代碼已經編譯(你沒有源代碼),我們可以使用 findbugs 之類的工具來識別使用 currentTimeMillis 並拒絕代碼(也許我們甚至可以用你自己的實現替換對 currentTimeMills 的調用)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.