E81086713E446D36F62B2AA2A3502B5EB155

Java杂家

杂七杂八。。。一家之言

BlogJava 首页 新随笔 联系 聚合 管理
  141 Posts :: 1 Stories :: 174 Comments :: 0 Trackbacks

当你要调试一个程序时,如果能把你的Java代码注入到目标程序并运行,这可能会给你的调试开发带来很大的方便,比如打印出一些全局变量值,属性等。
本人出于兴趣,封装了一个简单的Java库,可以达到这个目的。

这个库主要的API如下

1 public   class  com.yovn.labs.vmattach.VMTool
2 {
3       public   static   void  attachJarToVM(String pid,String jarPath,String mainClassToRun) throws    AttachException
4
5 }

第一个参数: 你要注入的Java程序的PID
第二个参数: 你要把那个jar文件(最好用路径全名)注入到目标程序
第三个参数: 注入目标程序后运行你指定的那个Class(全名)

该库可以从这里下载:http://www.blogjava.net/Files/javacap/VMAttach.zip

具体有什么用呢?这个看使用者怎么用,下面我弄个简单的例子。
加入一个程序使用一些Singleton对象,并且已经部署并运行了,现在我可能要查看一下这个Singleton对象的一些内部状态。

比如,这个程序如下:

 1 package  test; 
 2
 3 import  java.util.Random; 
 4
 5 /**
 6  *  @author  yovn
 7  *
 8   */

 9 public   class  UseSingletonApp 
10
11   /**
12   *  @param  args
13    */

14   public   static   void  main(String[] args)  {
15   
16    new  Thread(Singleton.getInstance()).start();
17    
18
19  }

20   public   static   class  Singleton  implements  Runnable
21   {
22    private   final   static  Singleton instance = new  Singleton();
23    private   volatile   int  stateNum;
24   
25   
26    private  Singleton()
27    {
28    
29   }

30    public   static  Singleton getInstance()
31    {
32     return  instance;
33   }

34    public   void  run()  {
35     while ( true )
36     {
37     stateNum = new  Random().nextInt();
38      try   {
39      Thread.sleep( 1000 );
40     }
  catch  (InterruptedException e)  {
41       //  TODO Auto-generated catch block
42      e.printStackTrace();
43     }

44    }

45    
46   }

47   
48  }
 
49
50 }

51
52


现在启动这个Java程序,在命令行窗口运行tasklist查看它的PID,假如为3020。
现在加入我要知道这个程序现在的Singleton 对象的stateNum值为多少,该怎么办呢?
我们以前一般要以debug模式启动,然后查看变量,难道正常启动就没办法了?
当然有,我们可以写个程序,注入到目标进程然后打印出来,不就OK.

当然,这里有个问题,注入的java程序是单独在一个线程里跑的,它的Context Class Loader是没有设置的,你要采取一些措施才能找到目标进程已经载入的class,请看下面的代码:

 1 package test; 
 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(nullnew 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了,
如下代码就可以完成注入:

 1 import com.yovn.labs.vmattach.AttachException;
 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也是还不支持的。

posted on 2007-01-04 13:52 DoubleH 阅读(6143) 评论(4)  编辑  收藏

Feedback

# re: 运行时注入你的Java代码到一个已经在运行的Java程序 2007-01-04 14:18 BeanSoft
是用的 JDK 1.6 才能支持吧? 呵, 无源码.. JVMTI 之类的  回复  更多评论
  

# re: 运行时注入你的Java代码到一个已经在运行的Java程序 2007-01-04 14:23 Javacap
@BeanSoft
不是,JDK6里的Attach API估计不是这样实现的。它可能在新的JVM里开了什么服务程序,但是支持多平台,我这个目前只能是 Windows, 但是对JDK没什么要求,只要JDK1.2以上就可以了。  回复  更多评论
  

# re: 运行时注入你的Java代码到一个已经在运行的Java程序 2007-01-05 11:17 iNeo
不错.对于一个WEB服务来说,如果能在某个业务逻辑运行时截获该程序,并读取该程序的相关参数的话,用来排错很有用.  回复  更多评论
  

# re: 运行时注入你的Java代码到一个已经在运行的Java程序 2015-04-07 14:53 ww
wroker.dll 和 vmattach.dll有源码吗?求分享  回复  更多评论
  


只有注册用户登录后才能发表评论。


网站导航: