當你要調試一個程序時,如果能把你的Java代碼注入到目標程序并運行,這可能會給你的調試開發帶來很大的方便,比如打印出一些全局變量值,屬性等。
本人出于興趣,封裝了一個簡單的Java庫,可以達到這個目的。
這個庫主要的API如下

2



3

4

5

第一個參數: 你要注入的Java程序的PID
第二個參數: 你要把那個jar文件(最好用路徑全名)注入到目標程序
第三個參數: 注入目標程序后運行你指定的那個Class(全名)
該庫可以從這里下載:http://www.aygfsteel.com/Files/javacap/VMAttach.zip
具體有什么用呢?這個看使用者怎么用,下面我弄個簡單的例子。
加入一個程序使用一些Singleton對象,并且已經部署并運行了,現在我可能要查看一下這個Singleton對象的一些內部狀態。
比如,這個程序如下:

?2

?3

?4

?5


?6

?7

?8

?9



10

11


12

13

14



15

16

17

18

19

20

21



22

23

24

25

26

27



28

29

30

31



32

33

34



35

36



37

38



39

40



41

42

43

44

45

46

47

48

49

50

51

52

現在啟動這個Java程序,在命令行窗口運行tasklist查看它的PID,假如為3020。
現在加入我要知道這個程序現在的Singleton 對象的stateNum值為多少,該怎么辦呢?
我們以前一般要以debug模式啟動,然后查看變量,難道正常啟動就沒辦法了?
當然有,我們可以寫個程序,注入到目標進程然后打印出來,不就OK.
當然,這里有個問題,注入的java程序是單獨在一個線程里跑的,它的Context Class Loader是沒有設置的,你要采取一些措施才能找到目標進程已經載入的class,請看下面的代碼:
?2?
?3?import?java.lang.reflect.Field;
?4?import?java.lang.reflect.Method;?
?5?
?6?/**
?7??*?@author?yovn
?8??*
?9??*/
10?public?class?AttachDemo?{?
11?
12??/**
13???*?@param?args
14???*/
15??public?static?void?main(String[]?args)?{
16???try?{
17????Class?cls=null;//the?class?we?try?to?load?that?alrady?loaded?by?target?process
18????
19????//following?code?iterate?the?thread?tree,to?use?every?one?context?class?loader?to?load?the?class?util?success
20????ThreadGroup?group?=?Thread.currentThread().getThreadGroup();
21????while?(group?!=?null)?{
22?????int?tc?=?group.activeCount();
23?????Thread[]?ts?=?new?Thread[tc];
24?????group.enumerate(ts);
25?????for?(int?i?=?0;?i?<?tc;?i++)?{
26??????if?(ts[i]?!=?null)?{
27???????try{
28????????cls=ts[i].getContextClassLoader().loadClass("test.UseSingletonApp$Singleton");
29???????Thread.currentThread().setContextClassLoader(ts[i].getContextClassLoader());
30???????break;
31???????}catch(Exception?e){}
32???????
33??????}
34?????}
35?????group?=?group.getParent();
36????}
37????if(cls==null)
38????{
39?????System.out.println("can?not?load?class");
40?????return;
41????}
42????Field?f?=?cls.getDeclaredField("stateNum");
43????f.setAccessible(true);
44????Method?getInM?=?cls.getMethod("getInstance",?new?Class[]?{});
45????Object?singleton?=?getInM.invoke(null,?new?Object[]?{});//get?the?singleton?object
46????
47????int?stateNum?=?((Integer)?f.get(singleton)).intValue();
48????System.out.println("Singleton's?stateNum?currently?is?:"?+?stateNum);
49???}?catch?(Exception?e)?{
50????e.printStackTrace();
51???}?
52?
53??}?
54?
55?}
56?
57?
現在,你需要把test.AttachDemo類編譯好,單獨打包到一個 jar文件,比如d:盤的attachdemo.jar里。
上面準備好了,你就差注入attachdemo.jar到目標進程3020了,
如下代碼就可以完成注入:
?2?import?com.yovn.labs.vmattach.VMTool;?
?3?
?4?public?class?Test?{
?5?/**
?6???*?@param?args
?7???*?@throws?AttachException?
?8???*/
?9??public?static?void?main(String[]?args)?throws?AttachException?{
10???VMTool.attachJarToVM("3020",?"D:\\attachdemo.jar",?"test.AttachDemo");
11??}?
12?
13?}
14?
15?
運氣不錯的話,你就能在運行UseSingletonApp程序的命令窗口輸出類似:
Singleton's stateNum currently is :1630285997
總結:
目前還不是很完善,只能attach一次,稍后我會完善這個功能。另外就是只支持Window 2000/NT/XP/2003 ,Windows98不支持,Linux/Unix也是還不支持的。