E81086713E446D36F62B2AA2A3502B5EB155

          Java雜家

          雜七雜八。。。一家之言

          BlogJava 首頁 新隨筆 聯系 聚合 管理
            40 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.aygfsteel.com/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也是還不支持的。

          posted on 2007-01-04 13:52 DoubleH 閱讀(6165) 評論(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有源碼嗎?求分享  回復  更多評論
            


          只有注冊用戶登錄后才能發表評論。


          網站導航:
           
          主站蜘蛛池模板: 永胜县| 榕江县| 莒南县| 会东县| 平山县| 都兰县| 鹰潭市| 荣成市| 汽车| 随州市| 西盟| 宜黄县| 南木林县| 云南省| 教育| 吉林省| 北辰区| 青冈县| 望江县| 海宁市| 枞阳县| 镇赉县| 酒泉市| 渝中区| 延庆县| 庆城县| 乳山市| 高碑店市| 大同县| 萨嘎县| 梧州市| 安仁县| 吴桥县| 宝坻区| 宁阳县| 晋宁县| 福海县| 武乡县| 山东省| 和田县| 吉林省|