2017-10-19 129 views
3

我正在使用Java代理和Javassist向某些JDK類添加一些日誌記錄。本質上,當系統加載一些TLS類時,Javassist會向它們添加一些額外的字節碼來幫助我調試一些連接問題。使用Java代理向類路徑添加一個類

這裏的問題,因爲這個類是包含在代理JAR:

package com.something.myagent; 
public class MyAgentPrinter { 
    public static final void sayHello() { 
     System.out.println("Hello!"); 
    } 
} 

在我代理的變換方法,比方說,我試着用了Javassist來調用這個類:

// this is only called for sun.security.ssl.Handshaker 
ClassPool cp = getClassPool(classfileBuffer, className); 
CtClass cc = cp.get(className); 
CtMethod declaredMethod = cc.getDeclaredMethod("calculateKeys"); 
declaredMethod.insertAfter("com.something.myagent.MyAgentPrinter.sayHello();"); 
cc.freeze(); 
return cc.toBytecode(); 

你認爲這將工作,但相反,我得到這個:

java.lang.NoClassDefFoundError: com/something/myagent/MyAgentPrinter 
    at sun.security.ssl.Handshaker.printLogLine(Handshaker.java) 
    at sun.security.ssl.Handshaker.calculateKeys(Handshaker.java:1160) 
    at sun.security.ssl.ServerHandshaker.processMessage(ServerHandshaker.java:292) 

有什麼辦法可以添加在類[MyAgentPrinter]到應用程序的類路徑?

回答

5

你代理的jar文件,已添加到類路徑中,由the java.lang.instrument package documentation規定:

代理類將被系統類加載器加載(參見ClassLoader.getSystemClassLoader)。這是通常加載包含應用程序main方法的類的類加載器。方法premain將在與應用程序main方法相同的安全和類加載器規則下運行。

這就是Javassist在轉換字節碼時可以找到Agent的類的原因。

問題似乎是,您正在轉換一個sun.**類,該類可能由引導加載程序或擴展加載程序加載。標準類加載委派是
application loader → extension loader → bootstrap loader,因此應用程序加載器可用的類不可用於擴展或引導加載程序加載的類。

所以,將它們提供給所有的類,你要代理的類添加到引導加載程序:

public class MyAgent { 
    public static void premain(String agentArgs, Instrumentation inst) throws IOException { 
     JarURLConnection connection = (JarURLConnection) 
      MyAgent.class.getResource("MyAgent.class").openConnection(); 
     inst.appendToBootstrapClassLoaderSearch(connection.getJarFile()); 

     // proceed 
    } 
} 

這是至關重要的任何其他行動之前,要做到這一點,你想也就是以前的學生,使可用於已裝入的已插裝代碼。這意味着代理類本身,即包含premain方法的類無法被檢測代碼訪問。代理類也不應直接引用MyAgentPrinter以避免意外的早期加載。

更可靠的方法是將Boot-Class-Path條目添加到代理程序jar的清單中,請參閱the 「Manifest Attributes」 section of the package documentation,以便在代理程序啓動之前添加條目。但是,之後,jar文件的名稱不能改變。

+0

您說'代理類將由系統類加載器加載(請參閱ClassLoader.getSystemClassLoader)。但是,問題中的問題是未找到類'AgentPrinter'。如果'AgentPrinter'和'MyAgent'在同一個目錄下,那麼你就可以這麼說,否則可能是我說的 – rakwaht

+0

@rakwaht:我的答案解釋了爲什麼Javassist不會失敗,即找到類,而*測試代碼*失敗。 – Holger

+0

看來你是對的。由於錯誤,我刪除了我的答案。 PS:我upvoted :) – rakwaht