posts - 15,comments - 65,trackbacks - 0
                想必不少人聽說過javaagent,但是很少人聽說Instrumentation,其實(shí)Instrumentation就是javaagent的實(shí)現(xiàn)機(jī)制,說到Instrumentation,就必須想了解javaattach機(jī)制,那就先說下attach的實(shí)現(xiàn)。

                  大家進(jìn)行jstack的時(shí)候,是不是經(jīng)常看到兩個(gè)線程Signal Dispatcher Attach Listener線程,可能不知道是干嘛的吧,這兩個(gè)線程是實(shí)現(xiàn)attach的關(guān)鍵所在,其中前者是在jvm啟動(dòng)的時(shí)候就會(huì)創(chuàng)建的,后者只有接收過attach請(qǐng)求的時(shí)候vm才會(huì)創(chuàng)建,顧名思義,Signal Dispatcher是分發(fā)信號(hào)的, Attach Listener 是處理attach請(qǐng)求的,那么兩者有什么關(guān)系呢,當(dāng)我們執(zhí)行attach方法的時(shí)候,會(huì)向目標(biāo)vm發(fā)出一個(gè)SIGQUIT 的信號(hào),目標(biāo)vm收到這個(gè)信號(hào)之后就會(huì)創(chuàng)建Attach Listener線程了,當(dāng)然jvm保證了不會(huì)多創(chuàng)建。
           1  path = findSocketFile(pid);
           2         if (path == null) {
           3             File f = new File(tmpdir, ".attach_pid" + pid);
           4             createAttachFile(f.getPath());
           5             try {
           6                 sendQuitTo(pid);
           7 
           8                 // give the target VM time to start the attach mechanism
           9                 int i = 0;
          10                 long delay = 200;
          11                 int retries = (int)(attachTimeout() / delay);
          12                 do {
          13                     try {
          14                         Thread.sleep(delay);
          15                     } catch (InterruptedException x) { }
          16                     path = findSocketFile(pid);
          17                     i++;
          18                 } while (i <= retries && path == null);
          19                 if (path == null) {
          20                     throw new AttachNotSupportedException(
          21                         "Unable to open socket file: target process not responding " +
          22                         "or HotSpot VM not loaded");
          23                 }
          24             } finally {
          25                 f.delete();
          26             }
          27         }
                  Attach機(jī)制說得簡(jiǎn)單點(diǎn)就是提供A進(jìn)程可以連上B進(jìn)程(當(dāng)然是java進(jìn)程),創(chuàng)建socket進(jìn)行通信,A通過發(fā)命令給B,B然后對(duì)命令進(jìn)行截取從自己的vm中獲取信息發(fā)回給客戶端vm,但是并不是隨便發(fā)指令都會(huì)處理的,那么attach Listener接收哪些命令呢,如下所示
          static AttachOperationFunctionInfo funcs[] = {
            { "agentProperties",  get_agent_properties },
            { "datadump",         data_dump },
            { "dumpheap",         dump_heap },
            { "load",             JvmtiExport::load_agent_library },
            { "properties",       get_system_properties },
            { "threaddump",       thread_dump },
            { "inspectheap",      heap_inspection },
            { "setflag",          set_flag },
            { "printflag",        print_flag },
            { "jcmd",             jcmd },
            { NULL,               NULL }
          };
                   Instrumentation的實(shí)現(xiàn)其實(shí)主要使用了load這個(gè)指令,它用來實(shí)現(xiàn)讓target vm動(dòng)態(tài)加載agentlib,Instrumentation的實(shí)現(xiàn)在一個(gè)名為libinstrument.dylib的動(dòng)態(tài)lib庫,linux下是libinstrument.so,它是基于jvmti接口實(shí)現(xiàn)的,因此在對(duì)其進(jìn)行l(wèi)oad的時(shí)候會(huì)創(chuàng)建一個(gè)agent實(shí)例,并往jvmti環(huán)境注冊(cè)一些回調(diào)方法,比如監(jiān)聽類文件加載的事件,vm初始化完成事件等,執(zhí)行Agent_OnAttach,這里會(huì)創(chuàng)建一個(gè)Instrumentation實(shí)例并返回給用戶供大家擴(kuò)展Instrumentation,比如增加一些transform。并會(huì)執(zhí)行Instrumentation實(shí)例的loadClassAndCallAgentmain方法,該方法主要執(zhí)行agent的MF文件里定義的 Agent-Class類的agentmain方法,當(dāng)vm初始化完畢之后,會(huì)調(diào)用loadClassAndCallPremain方法,該方法主要執(zhí)行agent的MF文件里定義的 Agent-Class類的pre main方法。在類進(jìn)行加載的時(shí)候會(huì)調(diào)用Instrumentation的transform方法,可以看看參數(shù)里有個(gè)byte數(shù)組,這個(gè)數(shù)組其實(shí)就是正在加載的class字節(jié)碼,所以如果要字節(jié)碼增強(qiáng)在這里就可以入手啦,甚至可以實(shí)現(xiàn)偷天換日.
          posted @ 2013-04-12 22:38 你假笨 閱讀(2206) | 評(píng)論 (0)編輯 收藏
                 本文最初發(fā)表在http://www.lovestblog.cn,轉(zhuǎn)載請(qǐng)注明出處,謝謝。
           最近在忙一個(gè)項(xiàng)目,使用的是Flex+Spring+Hibernate,期間碰到一個(gè)問題,有必要在此記錄一下,也方便有相似問題的來者參考下
                  問題描述:有一個(gè)用戶表和一個(gè)用戶詳情表,這兩個(gè)表是一個(gè)一對(duì)一的單向關(guān)聯(lián)關(guān)系,即在用戶表中一個(gè)外鍵引用用戶詳情表,我在UserInfo的映射文件中使用的是many-to-one,設(shè)置了unique="true"表示一對(duì)一關(guān)系,設(shè)置了cascade="save-update"表示的是在保存useInfo對(duì)象的時(shí)候會(huì)自動(dòng)保存與之關(guān)聯(lián)的userDetails臨時(shí)對(duì)象,即我希望的是先執(zhí)行一個(gè)在用戶詳情表中的插入語句然后再執(zhí)行一個(gè)在用戶表中的插入語句,userInfo對(duì)象是從flex端傳過來的,當(dāng)然也設(shè)置了userDetails屬性的值,在userInfo的dao文件中save方法是這樣的
              public IvUserInfo save(IvUserInfo transientInstance) {
                  log.debug(
          "saving IvUserInfo instance");
                  
          try {
                      getHibernateTemplate().save(transientInstance);
                      log.debug(
          "save successful");
                  } 
          catch (RuntimeException re) {
                      log.error(
          "save failed", re);
                      
          throw re;
                  }
                  
          return transientInstance;
              }
          后面發(fā)現(xiàn)執(zhí)行的sql語句只有一條插入語句,就是在用戶表中的一個(gè)插入,由于外鍵的關(guān)聯(lián)作用,是用戶表的這條插入也無法執(zhí)行,這就是問題所在了。
                  問題解決:這個(gè)問題我也沒有具體研究Hibernate的源碼,我先寫了個(gè)測(cè)試類,發(fā)現(xiàn)僅僅在java中執(zhí)行操作的話是可以正確執(zhí)行兩條插入語句的,但是通過flex傳過來就有問題了,那說明是flex端傳參數(shù)過來的問題,于是我試著修改UserInfo的save方法:

          public IvUserInfo save(IvUserInfo transientInstance) {
                  log.debug(
          "saving IvUserInfo instance");
                  
          try {
                      IvUserDetails ud
          =new IvUserDetails();
                      ud.setQq(transientInstance.getIvUserDetails().getQq());

                      transientInstance.setIvUserDetails(ud);
                      getHibernateTemplate().save(transientInstance);
                      log.debug(
          "save successful");
                  } 
          catch (RuntimeException re) {
                      log.error(
          "save failed", re);
                      
          throw re;
                  }
                  
          return transientInstance;
              }
          這樣一來問題解決了,順利執(zhí)行了兩條插入語句。
                 如果朋友知道具體原因的話希望給我留言了,同時(shí)也希望該記錄能幫助碰到此類問題的朋友。
          posted @ 2010-06-22 11:20 你假笨 閱讀(1576) | 評(píng)論 (0)編輯 收藏
                   歡迎光臨筆者博客http://www.lovestblog.cn
                  最近兩天本人在為本博實(shí)現(xiàn)rss發(fā)布和訂閱,本來是想在前端實(shí)現(xiàn)xml的生成和修改,因?yàn)橛胊s3的E4X操作xml比較方便,但是后面發(fā)現(xiàn)不能為元素設(shè)置CDATA值,于是只好作罷,便只能依靠后臺(tái)的java來實(shí)現(xiàn)此功能了,當(dāng)然操作xml的話,我首先想到了dom4j,dom4j操作xml還是比較方便的,即可以輕松實(shí)現(xiàn)我們的CDATA設(shè)置,也可以為我們?nèi)我馕恢貌迦朐靥峁┝藢?shí)現(xiàn),對(duì)于在指定位置新增節(jié)點(diǎn)開始我有點(diǎn)蒙了,后面通過網(wǎng)上搜索資源加之自己的一些理解,而實(shí)現(xiàn)了此功能,下面展示了部分代碼供今后參考吧:
          1. public static int createXMLFile(String filename,List list){   
                       
            /** 返回操作結(jié)果, 0表失敗, 1表成功 */  
                       
            int returnValue = 0;    
                       Document document 
            = DocumentHelper.createDocument();   
                       Element rssElement 
            = document.addElement("rss");   
                       rssElement.addAttribute(
            "version""2.0");     
                       Element channelElement 
            = rssElement.addElement("channel");   
                       Element titleElement 
            = channelElement.addElement("title");   
                       titleElement.setText(
            "你假笨(nijiaben)心情技術(shù)博客");    
                          
                       Element linkElement 
            = channelElement.addElement("link");   
                       linkElement.setText(
            "http://www.lovestblog.cn");   
                          
                       Element descriptionElement 
            = channelElement.addElement("description");   
                       descriptionElement.setText(
            "專注于Java,Flex技術(shù)開發(fā)研究");   
                          
                       Element languageElement 
            = channelElement.addElement("language");   
                       languageElement.setText(
            "zh-cn");   
                          
                       Element lastBuildDateElement 
            = channelElement.addElement("lastBuildDate");   
                       lastBuildDateElement.setText(
            new java.text.SimpleDateFormat("yyyy-mm-dd hh:mm:ss",Locale.CHINA).format(((ArticleInfo)(list.get(0))).getCreateTime()));             
                                
                       
            for(int i=list.size()-1;i>0;i--){   
                           ArticleInfo ainfo
            =(ArticleInfo)(list.get(i));   
                           Element itemElement 
            = channelElement.addElement("item");   
                           Element title1Element 
            = itemElement.addElement("title");   
                           title1Element.setText(ainfo.getTitle());   
                           Element description1Element 
            = itemElement.addElement("description");   
                           
            int maxLen=5000;   
                           
            if(ainfo.getRssContent().length()<5000){   
                               maxLen
            =ainfo.getRssContent().length();   
                           }
               
                           description1Element.addCDATA(ainfo.getRssContent().substring(
            0, maxLen));          
                           Element pubDate
            =itemElement.addElement("pubDate");   
                           pubDate.setText(
            new java.text.SimpleDateFormat("yyyy-mm-dd hh:mm:ss",Locale.CHINA).format(ainfo.getCreateTime()));                     
                           Element link1Element
            =itemElement.addElement("link");   
                           link1Element.setText(
            "http://www.lovestblog.cn");   
                       }
               
                       
            try{   
                           
            /** 將document中的內(nèi)容寫入文件中 */  
                           XMLWriter writer 
            = new XMLWriter(new FileOutputStream(path+filename));   
                           writer.write(document);   
                           writer.close();   
                           
            /** 執(zhí)行成功,需返回1 */  
                           returnValue 
            = 1;   
                       }
            catch(Exception ex){   
                           ex.printStackTrace();   
                       }
               
                       
            return returnValue;   
                    }
              
          posted @ 2010-04-01 12:14 你假笨 閱讀(3093) | 評(píng)論 (1)編輯 收藏

                    本文最新發(fā)布于http://www.lovestblog.cn,歡迎轉(zhuǎn)載該文,但請(qǐng)注明文章出處,謝謝合作。 

                    mysql的from從句用來指定參與查詢的表,當(dāng)然也可以是生成的中間表,在表前我們有時(shí)需要指定數(shù)據(jù)庫,這主要是用在我們需要訪問當(dāng)前數(shù)據(jù)庫之外的數(shù)據(jù)庫中的表的情況,在這中情況下我們采用"."操作符來進(jìn)行,如userdb.user,其實(shí)userdb為數(shù)據(jù)庫名,user為表名,這是對(duì)mysql數(shù)據(jù)庫而言的,對(duì)于DB2和Oracle就不是通過指定數(shù)據(jù)庫名了,而是指定sql用戶了,這就是說不同sql用戶可以建立相同名字的表,但是同一個(gè)sql用戶只能建立唯一名字的表。這就是它們?cè)谶@表規(guī)范上面的區(qū)別。對(duì)于列規(guī)范,mysql可以在需要查詢的列則可以采用如下形式進(jìn)行訪問:“數(shù)據(jù)庫名.表名.列名”。對(duì)于多個(gè)表的規(guī)范,也就是涉及查詢多個(gè)表的情況下,執(zhí)行的過程是采用笛卡爾積的形式進(jìn)行的。也就是說生成的中間表的列數(shù)為兩個(gè)表中列數(shù)的總和,而行的總數(shù)等于一個(gè)表中的行的數(shù)量與另外一個(gè)表中行的數(shù)量的乘積。
                 對(duì)于from從句中使用假名的情況,比如select u.id,name,age,a.account from utb as u,atb as a where u.id=a.user_id,在我們使用假名之后,那么在該sql語句的任何地方都只能使用假名,不能使用真實(shí)的表名,同時(shí)上面的as關(guān)鍵字也是可以省略的,也就是說對(duì)于上面的語句不能用atb來取代a,utb來取代u了。雖然from從句不是我們指定的第一條語句,但是絕對(duì)是第一個(gè)被處理的語句,所以在聲明假名前使用假名不會(huì)導(dǎo)致錯(cuò)誤。如果一條from從句引用到兩個(gè)有著相同名稱的表,則必須使用假名。如:

          1select p.playerno
          2from players as p,players as par
          3where par.fn="jp" and par.ln="l" and p.birth_date<par.birth_date


                 對(duì)于多個(gè)表間的連接處理可能會(huì)導(dǎo)致有相同的結(jié)果,即有重復(fù)的結(jié)果,sql并不會(huì)自動(dòng)從最終結(jié)果中刪除重復(fù)的行,這是如果我們不希望在結(jié)果中出現(xiàn)重復(fù)的行,那么我們可以在select后直接指定distinct。如:

          1select distinct T.playerno 
          2from teams as T,penalties as pen 
          3where T.playerno=pen.playerno。

           

                  接下來說說連接哈,對(duì)于內(nèi)連接,如果是兩個(gè)表的話,就取兩個(gè)表的一個(gè)交集,如果是左外連接的話,那就是左邊的表全取,右邊沒有的用null替代,弱國(guó)是右外連接的話,那就是右邊的表全取,左邊沒有的用null表示。下面看看一個(gè)具體的例子:

          1--表stu        --表exam 
          2id name        id grade 
          31, Jack         156 
          42, Tom         276
          53, Kity         1189
          64, nono 

           

          內(nèi)連接 (顯示兩表id匹配的)

          1select stu.id,exam.id,stu.name, exam.grade from stu (inner) join exam on stu.id=exam.id 
          2-------------------------------- 
          31 1 Jack 56 
          42 2 Tom 76 

           

          左連接(顯示join 左邊的表的所有數(shù)據(jù),exam只有兩條記錄,所以stu.id,grade 都用NULL 顯示)

          1select stu.id,exam.id,stu.name, exam.grade from stu left (outer) join exam on stu.id=exam.id 
          21 1 Jack 56 
          32 2 Tom 76 
          43 NULL Kity NULL 
          54 NULL nono NULL 

           

          右連接(與作連接相反,顯示join右邊表的所有數(shù)據(jù))

          1select stu.id,exam.id,stu.name, exam.grade from stu right join exam on stu.id=exam.id 
          21 1 Jack 56 
          32 2 Tom 76 
          4NULL 11 NULL 89 

           

          內(nèi)連接取交集,外連接分左和右,
          左連接左邊的全取,
          右連接右邊的全取

                對(duì)于連接的列的名稱相同的話,那么可以使用using來替代條件,如上面的內(nèi)連接可以這樣改寫:
              

          1  select stu.id,exam.id,stu.name, exam.grade from stu inner join exam using(id)。

                對(duì)于左外連接使用的情況一般是當(dāng)左表的連接列中存在未出現(xiàn)在右表的連接列中的值時(shí),左外連接才有用。
                還有個(gè)全外連接的,也就是說只要在兩個(gè)表中出現(xiàn)的記錄都會(huì)在中間表中出現(xiàn),當(dāng)右表有而左表沒有或當(dāng)左表有而右表沒有的時(shí)候用null表示。具體語法如下:select stu.id,exam.id,stu.name, exam.grade from stu full join exam using(id)。
                交叉連接:就是顯示求表的笛卡爾積,select * from teams cross join penalties.這句完全等價(jià)于select teams.*,penalties.* from teams,penalties.
                聯(lián)合連接:select * from teams union join penalties,這個(gè)其實(shí)很容易理解,產(chǎn)生結(jié)果所包含的列為兩個(gè)表所有的列和,對(duì)于數(shù)據(jù)的列出,首先列出左表的數(shù)據(jù),對(duì)于屬于右表的列,用null表示,接下來列出右表的數(shù)據(jù),對(duì)于屬于左表的列用null表示。
                 自然連接:select * from teams nature inner join penalties where division='first';此句完全等同與select t.playerno,t.teamno,t.division,pen.paymentno,pen.payment_date,pen.amount from teams  as t inner join penalties as pen on t.playerno=pen.playerno where dividion='first'.相比就知道,我們無須顯示指出必須要連接到哪些列,sql會(huì)自動(dòng)查找兩表中是否有相同名稱的列,且假設(shè)他們必須在連接條件中使用。此處的on或using從句是多余的,因此不允許使用。

                 下面看個(gè)例子創(chuàng)建一個(gè)稱為towns的虛擬表:

          1select *
          2from (select 'Stratford' as town,4 as number 
          3       union
          4       select 'Plymouth',6
          5       union
          6       select 'Inglewood',1                 
          7       union
          8       select 'Douglas',2) as towns
          9order by town;


          結(jié)果為:

          1town             number
          2----------------------
          3Douglas              2
          4Inglewood           1
          5Plymouth            6
          6Stratford            4


           

          posted @ 2009-09-24 15:51 你假笨 閱讀(2030) | 評(píng)論 (0)編輯 收藏
          主站蜘蛛池模板: 沂南县| 凤台县| 阿城市| 达州市| 永春县| 墨竹工卡县| 浦东新区| 高尔夫| 博兴县| 丹凤县| 丰原市| 新巴尔虎左旗| 罗定市| 湟中县| 普安县| 神木县| 巩留县| 雷波县| 慈利县| 荣成市| 邳州市| 河西区| 丘北县| 固始县| 虹口区| 巴楚县| 偃师市| 河曲县| 惠州市| 宝山区| 德庆县| 崇礼县| 南乐县| 翼城县| 全南县| 德令哈市| 克东县| 新建县| 鄱阳县| 涡阳县| 溆浦县|