什麼是 javaagent
java agent是java命令的一個參數。參數 javaagent 可以用於指定一個 jar 包,並且對該 java 包有2個要求:
- 這個 jar 包的MANIFEST.MF 文件必須指定 Premain-Class 項。
- Premain-Class 指定的那個類必須實現 premain()方法。
重點就在 premain 方法,也就是我們今天的標題。從字面上理解,就是運行在 main 函數之前的的類。當Java 虛擬機啓動時,在執行 main 函數之前,JVM 會先運行 -javaagent 所指定 jar 包內 Premain-Class 這個類的 premain 方法,其中,該方法可以簽名如下:
1.public static void premain(String agentArgs, Instrumentation inst)
2.public static void premain(String agentArgs)
JVM 會優先加載 1 簽名的方法,加載成功忽略 2,如果1 沒有,加載 2 方法。這個邏輯在sun.instrument.InstrumentationImpl 類中:
如何使用
1 首先定義一個 MANIFEST.MF 文件:
Manifest-Version: 1.0
Can-Redefine-Classes: true
Can-Retransform-Classes: true
Premain-Class: cn.think.in.java.clazz.loader.asm.agent.PreMainTraceAgent
創建一個Premain-Class 指定的類,類中包含 premain 方法:
public class Main {
public static void premain(String agentArgs, Instrumentation inst) {
System.out.println("agentArgs : " + agentArgs);
inst.addTransformer(new ClassFileTransformer() {
@Override
public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined,
ProtectionDomain protectionDomain, byte[] classfileBuffer)
throws IllegalClassFormatException {
System.out.println("premain load Class :" + className);
return classfileBuffer;
}
}, true);
}
}
將 premain 的類和 MANIFEST.MF 文件打成 jar 包 .
使用 IDEA 的 build ,當然你也可以使用 maven
再簡單創建一個test類
public class AccountMain {
public static void main(String[] args)
throws ClassNotFoundException, InterruptedException, IllegalAccessException, InstantiationException, NoSuchMethodException,
InvocationTargetException {
System.out.println("11111111111");
}
}
}
使用參數 -javaagent:jar包名 啓動要代理的方法。
和類加載器比較
類加載器也可以實現運行時修改代碼。但是對代碼的侵入性很高。使用 java agent 能讓修改字節碼這個動作化於無形,對業務透明,減少侵入性。
agent的缺點
需要設置參數javaagent