<strike id="oehix"></strike>

  • <strike id="oehix"></strike>
    <legend id="oehix"><delect id="oehix"><div id="oehix"></div></delect></legend><legend id="oehix"></legend>
    1. <label id="oehix"></label>
      青島青島思途教育

      400-882-1633

      全國學(xué)習專(zhuān)線(xiàn) 8:00-22:00
      青島青島思途教育
      青島中享思途致力于高新技術(shù)人才的免費實(shí)訓。  是一家集軟件開(kāi)發(fā)和IT教育實(shí)訓為一體的科技實(shí)訓學(xué)校。  力爭為更多的全國學(xué)員提供真正具備口碑的技術(shù)實(shí)訓和服務(wù)  
      您當前的位置: >青島匯學(xué)通 >青島培訓學(xué)校 >在Java中運用修復Bug的小技巧

      青島Java學(xué)校新聞

      在Java中運用修復Bug的小技巧

      發(fā)布時(shí)間:2018-12-26 10:49:23 已幫助:744人 來(lái)源:青島青島思途教育

      在Java中運用修復Bug的小技巧

      在Java中運用修復Bug的小技巧
      文章介紹:

        Java是一種編程語(yǔ)言,相信很多熟知Java的同學(xué)都會(huì )碰到一種常見(jiàn)的問(wèn)題那就是在Java中運用動(dòng)態(tài)掛載的過(guò)程中經(jīng)常會(huì )出現很多bug,那么針對性這些我們常見(jiàn)的bug我們應該如何解決呢?以下是小編整理的遇到bug時(shí)候要怎么解決的資料,一起來(lái)看看吧!

        大多數JVM具備Java的HotSwap特性,大部分開(kāi)發(fā)者認為它僅僅是一個(gè)調試工具。利用這一特性,有可能在不重啟Java進(jìn)程條件下,改變Java方法的實(shí)現。典型的例子是使用IDE來(lái)編碼。然而HotSwap可以在生產(chǎn)環(huán)境中實(shí)現這一功能。通過(guò)這種方式,不用停止運行程序,就可以擴展在線(xiàn)的應用程序,或者在運行的項目上修復小的錯誤。這篇文章中,我將演示動(dòng)態(tài)綁定、應用運行期代碼變化進(jìn)行綁定、介紹一些工具API以及ByteBuddy庫,這個(gè)庫提供了一些API代碼改變更方便。


        假設有一個(gè)正在運行的應用程序,通過(guò)校驗HTTP請求中的X-Priority頭部,來(lái)執行服務(wù)器的特殊處理。該校驗使用下面的工具類(lèi)來(lái)實(shí)現:

        classHeaderUtility{staticbooleanisPriorityCall(HttpServletRequestrequest){returnrequest.getHeader("X-Pirority")!=null;}}

        你發(fā)現錯誤了嗎?這樣的錯誤很常見(jiàn),尤其是在測試代碼中常量值分解為靜態(tài)字段重用。在不太理想的情況下,這個(gè)錯誤只會(huì )在產(chǎn)品被安裝的時(shí)候才被發(fā)現,其中頭通過(guò)另外一個(gè)應用生成并沒(méi)有拼寫(xiě)錯誤。

        修復這樣的錯誤并不難。在持續交付的時(shí)代,重新部署一個(gè)新的版本只需要點(diǎn)擊一下按鈕。但在其他情況下,變更可能就不是那么簡(jiǎn)單了,重新部署過(guò)程可能比較復雜,其中停機是不允許的,帶著(zhù)錯誤運行可能會(huì )比較好。但HotSwap給我們提供了另外一種選擇:在不重啟應用的前提下進(jìn)行小幅改動(dòng)。

      1
      AttachAPI:使用動(dòng)態(tài)附件來(lái)滲透另外一個(gè)JVM:

        為了修改一個(gè)運行中的Java程序,我們首先需要一種可以同處在運行狀態(tài)的JVM進(jìn)行通信的方式。因為Java的虛擬機實(shí)現是一個(gè)受到管理的系統,因此擁有進(jìn)行這些操作的標準API。提問(wèn)中涉及到的API被稱(chēng)作attachmentAPI,它是官方Java工具的一部分。使用這個(gè)由運行之中的JVM所暴露的API,能讓第二個(gè)Java進(jìn)程來(lái)同其進(jìn)行通信。

        事實(shí)上,我們已經(jīng)用到了該API:它已經(jīng)由諸如VisualVM或者JavaMissionControl這樣的調試和模擬工具進(jìn)行了應用。應用這些附件的API并沒(méi)有同日常使用的標準JavaAPI打在一起,而是被打到了一個(gè)特殊的文件之中,叫做tools.jar,它只含了一個(gè)虛擬機的JDK打發(fā)布版本。更糟糕的是,這個(gè)JAR文件的位置并沒(méi)有進(jìn)行設置,它在Windows、Linux,特別是在Macintosh上的VM都存在差別,不光文件的位置,連文件名也各異,有些發(fā)行版上就被叫做classes.jar。最后,IBM甚至決定對這個(gè)JAR中含的一些類(lèi)的名稱(chēng)進(jìn)行修改,將所有com.sun類(lèi)挪到com.ibm命名空間之中,又添了一個(gè)亂子。在Java9中,亂糟糟的狀態(tài)才最終得以清理,tools.jar被Jigsaw的模塊jdk.attach所替代。
        在對API的JAR(或者模塊)進(jìn)行了定位之后,我們就該讓其對附件進(jìn)程可用。在OpenJDK上,被用來(lái)連接到另外一個(gè)JVM的類(lèi)叫做VirtualMachine,它向任何由位于同一臺物理機器上的JDK或者是一個(gè)普通的HtpSpotJVM所運行的VM提供了一個(gè)入口點(diǎn)。在通過(guò)進(jìn)程id附加到另外一臺虛擬機上之后,我們就能夠在目標VM指定的一個(gè)線(xiàn)程中運行一個(gè)JAR文件:

        //thefollowingstringsmustbeprovidedbyusStringprocessId=processId();StringjarFileName=jarFileName();VirtualMachinevirtualMachine=VirtualMachine.attach(processId);try{virtualMachine.loadAgent(jarFileName,"World!");}finally{virtualMachine.detach();}

        在收到一個(gè)JAR文件之后,目標虛擬機會(huì )查看該JAR的程序清單描述文件(manifest),并定位處在Premain-Class屬性之下的類(lèi)。這非常類(lèi)似于VM執行一個(gè)主方法的方式。有了一個(gè)Java代理,VM和指定的進(jìn)程id就可以查找到一個(gè)名為agentmain的方法,該方法可以由指定線(xiàn)程中的遠程進(jìn)程來(lái)執行:

        publicclassHelloWorldAgent{publicstaticvoidagentmain(Stringarg){System.out.println("Hello,"+arg);}}

        使用該API,只要我們知道一個(gè)JVM的進(jìn)程id,就可以來(lái)在其上運行代碼,打印出一條Hello,World!消息。甚至有可能同并不熟JDK發(fā)行版一部分的JVM進(jìn)行通信,只要附加的VM是一個(gè)用來(lái)訪(fǎng)問(wèn)tools.jar的JDK安裝程序。

      2
      InstrumentationAPI:修改目標VM的程序:

        到目前來(lái)看一切順利。但是除了成功地同目標VM建立起了通信之外,我們還不能夠修改目標VM上的代碼以及BUG。后續的修改,Java代理可以定義第二參數來(lái)接收一個(gè)Instrumentation的實(shí)例。稍后要實(shí)現的接口提供了向幾個(gè)底層方法的訪(fǎng)問(wèn)途徑,它們中的一個(gè)就能夠對已經(jīng)加載的代碼進(jìn)行修改。

        為了修正“X-Pirority”錯字,我們首先來(lái)假設為HeaderUtility引入了一個(gè)修復類(lèi),叫做typo.fix,就在我們下面所開(kāi)發(fā)的BugFixAgent后面的代理的JAR文件中。此外,我們需要給予代理通過(guò)向manifest文件添加Can-Redefine-Classes:true來(lái)替換現有類(lèi)的能力。有了現在這些東西,我們就可以使用instrumentation的API來(lái)對類(lèi)進(jìn)行重新定義,該API會(huì )接受一對已經(jīng)加載的類(lèi)以及用來(lái)執行類(lèi)重定義的字節數組:

        publicclassBugFixAgent{publicstaticvoidagentmain(Stringarg,Instrumentationinst)throwsException{//onlyifheaderutilityisontheclasspath;otherwise,//aclasscanbefoundwithinanyclassloaderbyiterating//overthereturnvalueofInstrumentation::getAllLoadedClassesClass<?>headerUtility=Class.forName("HeaderUtility");//copythecontentsoftypo.fixintoabytearrayByteArrayOutputStreamoutput=newByteArrayOutputStream();try(InputStreaminput=BugFixAgent.class.getResourceAsStream("/typo.fix")){byte[]buffer=newbyte[1024];intlength;while((length=input.read(buffer))!=-1){output.write(buffer,0,length);}}//Applytheredefinitioninstrumentation.redefineClasses(newClassDefinition(headerUtility,output.toByteArray()));}}

        運行上述代碼后,HeaderUtility類(lèi)會(huì )被重定義以對應其修補的版本。對isPrivileged的任何后續調用現在將讀取正確的頭信息。作為一個(gè)小的附加說(shuō)明,JVM可能會(huì )在應用類(lèi)重定義時(shí)執行完全的垃圾回收,并且會(huì )對受影響的代碼進(jìn)行重新優(yōu)化??傊?,這會(huì )導致應用程序性能的短時(shí)下降。然而,在大多數情況下,這是較之完全重啟進(jìn)程更好的方式。

        當應用代碼更改時(shí),要確保新類(lèi)定義了與它替換的類(lèi)完全相同的字段、方法和修飾符。嘗試修改任何此類(lèi)屬性的類(lèi)重定義行為都會(huì )導致UnsupportedOperationException?,F在HotSpot團隊正試圖去掉這個(gè)限制。此外,基于OpenJDK的動(dòng)態(tài)代碼演變虛擬機支持預覽此功能。

      3
      使用ByteBuddy來(lái)追蹤內存泄漏:

        一個(gè)如上述示例的簡(jiǎn)單的BUG修復代理在你熟悉了instrumentation的API的時(shí)候是比較容易實(shí)現的。只要更加深入一點(diǎn),也可以在運行代理的時(shí)候,無(wú)需手動(dòng)創(chuàng )建附加的class文件,而是通過(guò)重寫(xiě)現有的class來(lái)應用更多通用的代碼修改。

      4
      字節碼操作:

        編譯好的Java代碼所呈現的是一系列字節碼指令。從這個(gè)角度來(lái)看,一個(gè)Java方法無(wú)非就是一個(gè)字節數組,其每一個(gè)字節都是在表示一個(gè)向運行時(shí)發(fā)出的指令,或者是最近一個(gè)指令的參數。每個(gè)字節對應其意義的映射在《Java虛擬機規范》中進(jìn)行了定義,例如字節0xB1就是在指示VM從一個(gè)帶有void返回類(lèi)型的方法返回。因此,對字節碼進(jìn)行增強就是對一個(gè)方法的字節數字進(jìn)行擴展,將我們想要應用的表示額外的業(yè)務(wù)邏輯指令含進(jìn)去。

        當然,逐個(gè)字節的操作會(huì )特別麻煩,而且容易出錯。為了避免手工的處理,許多的庫都提供了更高級一點(diǎn)的API,使用它們不需要我們直接同Java字節碼打交道。這樣的庫其中就有一個(gè)叫做ByteBuddy(當然我就是該庫的作者)。它的功能之一就是能夠定義可以在方法原來(lái)的代碼之前和之后被執行的模板方法。

        以上就是小編給大家整理的Java在中運用動(dòng)態(tài)掛載實(shí)現Bug的熱修復,想要了解更多關(guān)于Java的小技巧,快來(lái)青島中享思途咨詢(xún)【青島Java+大數據工程課程


      上一篇:如何零基礎學(xué)習UI設計
      下一篇:讀完Java秘籍就是大神
      關(guān)于我們 | 聯(lián)系我們 | 青島青島思途教育地址:青島校區總部/市南校區/ 咨詢(xún)電話(huà):400-882-1633
      滬ICP備12032008號-7 網(wǎng)站地圖 注冊 登錄 招生合作 版權/投訴 免責聲明 更新時(shí)間:2024-11-13
      国产自在自线午夜精品视频|一本一道av无码中文字幕|欧美乱综合图片区小说区|做天天爱夜夜爽|合久久综合欧美综合网
      <strike id="oehix"></strike>

    2. <strike id="oehix"></strike>
      <legend id="oehix"><delect id="oehix"><div id="oehix"></div></delect></legend><legend id="oehix"></legend>
      1. <label id="oehix"></label>