從事java開發的同學,或多或少聽說過java探針
/javaagent
這個術語。本文不說它的定義,不說它的原理,不說它的高大上的作用,只說它的"hello world"。即運行一個最簡單的例子,實際看看效果,真切的感受后,才能真切清晰的入口。
編碼
用idea創建個maven項目,如下圖,項目名稱隨意,這里我的項目名為:microservice-comb-javaagent
代碼如下 首先,創建一個類:AgentDemo
public class AgentDemo {
/**
* 該方法在main方法之前運行,與main方法運行在同一個JVM中
*/
public static void premain(String agentArgs, Instrumentation inst) {
System.out.println("------ premain方法 有兩個入參 ------ agentArgs:" + agentArgs + " inst:" + inst.toString()); } /** * 如果不存在 {@link AgentDemo#premain(String, Instrumentation)}, 則會執行本方法 */ public static void premain(String agentArgs) { System.out.println("------ premain方法,有一個入參 ------ agentArgs:" + agentArgs); } } 復制代碼
注意:AgentDemo的全限定名會在pom.xml中標簽Premain-Class
引用
其次,再創建一個類:AgentTest
public class AgentTest {
public static void main(String[] args) {
System.out.println(" ------ main方法"); } } 復制代碼
再次,在項目的pom.xml中添加
··· 略
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source> <target>1.8</target> </configuration> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-jar-plugin</artifactId> <configuration> <archive> <manifestEntries> <!-- 值為包含premain方法的類. 啟動方式為命令行啟動時,javaagent JAR文件清單必須包含 Premain-Class 屬性, 代理類必須實現 public static premain()--> <Premain-Class>com.skyler.cobweb.agent.AgentDemo</Premain-Class> <Can-Redefine-Classes>true</Can-Redefine-Classes> <Can-Retransform-Classes>true</Can-Retransform-Classes> </manifestEntries> </archive> </configuration> </plugin> </plugins> </build> 復制代碼
打jar包
將microservice-comb-javaagent
打成jar
包。運行時會使用這個Jar
包.打包命令:mvn clean package
。結果如下圖
運行
你可以有兩個運行方式:idea中直接運行
和命令行運行
- idea中直接運行
需要配置下項目的運行配置的VM options
,如下圖,形式為-javaagent:jarpath[=options]
; 我的內容為:-javaagent:/Users/xx/microservice-comb/microservice-comb-javaagent/target/microservice-comb-javaagent-1.0.0-SNAPSHOT.ar="hello world"
然后,運行AgentTest.main方法,結果如下圖
可以看到,打印出了AgentDemo.premain方法的信息
- 命令行運行
cd
到項目microservice-comb-javaagent的/target/classes路徑下
$ cd xx/target/classes $ java -javaagent:/Users/xx/microservice-comb/microservice-comb-javaagent/target/microservice-comb-javaagent-1.0.0-SNAPSHOT.jar="hello world" com.skyler.cobweb.agent.AgentTest 復制代碼
可以看到,同樣打印出了AgentDemo.premain方法的信息
收獲
這里有個對比,運行時是否加上-javaagent:jar
,這個給你的感受會很明顯和透徹。來再操作下
加上時
$ cd /Users/xx/microservice-comb/microservice-comb-javaagent/target/classes $ java -javaagent:/Users/xx/microservice-comb/microservice-comb-javaagent/target/microservice-comb-javaagent-1.0.0-SNAPSHOT.jar="hello world" com.skyler.cobweb.agent.AgentTest 復制代碼
效果
------ premain方法 有兩個入參 ------ agentArgs:hello world inst:sun.instrument.InstrumentationImpl@a09ee92
------ main方法
復制代碼
不加上時
$ cd /Users/xx/microservice-comb/microservice-comb-javaagent/target/classes $ java com.skyler.cobweb.agent.AgentTest 復制代碼
效果
------ main方法
復制代碼
效果還是很明顯的,不加-javaagent,jar里的類方法沒有執行,也即不會輸出信息
這個對比的目的是突出javaagent的作用。並讓你清晰的感受javaagent的作用:像代理一樣可以在main方法前做些事情,官方的說字節碼增強。通過修改字節碼的方式,讓開發者有機會做些事情,如arthas 和skywalking的建監聽組件
千言萬語抵不上run
一個'hello world'
本文想通過最簡單、最直觀的方式,讓你最快速的、最真切的了解javaagent的作用。下篇展開說javaagent的原理和更實際的使用例子