运行时注入你的Java代码到一个已经在运行的Java程序

运行时注入你的Java代码到一个已经在运行的Java程序

当你要调试一个程序时,如果能把你的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( 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了,
如下代码就可以完成注入:

 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也是还不支持的。

你可能感兴趣的:(运行时注入你的Java代码到一个已经在运行的Java程序)