做者:小傅哥
博客:https://bugstack.cnjava
沉澱、分享、成長,讓本身和他人都能有所收穫!
經過前面兩篇 javassist
的基本內容,大致介紹了;類池(ClassPool)、類(CtClass)、屬性(CtField)、方法(CtMethod),的使用方式,並經過建立不一樣類型的入參出參方法,基本能夠掌握如何使用這樣的代碼結構進行字節碼編程。編程
那麼,今天咱們嘗試使用 javassist
去修改一個正在執行中的類裏面的方法內容。也就是在運行時從新加載類信息api
可能在你平時的 CRUD 開發中並無想到過這樣的 燒操做,但它卻有不少的應用場景在使用,例如;多線程
人的大腦很難創造未知的事物,因此須要學習。請多看小傅哥的碼文,少搞CRUDapp
關於字節編程中全部涉及的代碼,均可以經過關注公衆號
:bugstack蟲洞棧,回覆:源碼,進行獲取。dom
jdi
包爲了讓案例目標更具色彩
,咱們模擬一個謝飛機老婆,經過系統查詢本身男友前女朋友數量
的 危機 方法,須要緊急處理的過程。socket
爲了保障家庭的和諧化解危機,咱們經過動態從新加載類,將謝飛機前女朋友數量修改成0
並返回。依次安定家庭和諧。最終謝飛機會給我錢,當作報酬組件化
讓謝飛機很慌的方法性能
public class ApiTest { public String queryGirlfriendCount(String boyfriendName) { return boyfriendName + "的前女朋友數量:" + (new Random().nextInt(10) + 1) + " 個"; } }
可預見的結果;學習
你到底幾個前女朋友!!! 謝飛機的前女朋友數量:3 個 謝飛機的前女朋友數量:5 個 謝飛機的前女朋友數量:8 個
德萊聯盟,王牌工程師,申請出棧
/** * 公衆號:bugstack蟲洞棧 * 博客棧:https://bugstack.cn - 沉澱、分享、成長,讓本身和他人都能有所收穫! * 本專欄是小傅哥多年從事一線互聯網Java開發的學習歷程技術彙總,旨在爲你們提供一個清晰詳細的學習教程,側重點更傾向編寫Java核心內容。若是能爲您提供幫助,請給予支持(關注、點贊、分享)! */ public class GenerateClazzMethod { public static void main(String[] args) throws Exception { ApiTest apiTest = new ApiTest(); System.out.println("你到底幾個前女朋友!!!"); // 模擬謝飛機老婆一頓查詢 new Thread(() -> { while (true){ System.out.println(apiTest.queryGirlfriendCount("謝飛機")); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } }).start(); // 監聽 8000 端口,在啓動參數裏設置 // java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=8000 HotSwapper hs = new HotSwapper(8000); ClassPool pool = ClassPool.getDefault(); CtClass ctClass = pool.get(ApiTest.class.getName()); // 獲取方法 CtMethod ctMethod = ctClass.getDeclaredMethod("queryGirlfriendCount"); // 重寫方法 ctMethod.setBody("{ return $1 + \"的前女朋友數量:\" + (0L) + \" 個\"; }"); // 加載新的類 System.out.println(":: 執行HotSwapper熱插拔,修改謝飛機前女朋友數量爲0個!"); hs.reload(ApiTest.class.getName(), ctClass.toBytecode()); } }
javassist.tools.HotSwapper
,是 javassist
的包中提供的熱加載替換類操做。在執行時須要啓用 JPDA(Java平臺調試器體系結構)。ctMethod.setBody
,重寫方法的內容在上面兩個章節已經很清楚的描述了。$1 是獲取方法中的第一個入參,大括號{}
裏是具體執行替換的方法體。hs.reload
執行熱加載替換操做,這裏的 ctClass.toBytecode()
獲取的是處理後類的字節碼。-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=8000
Listening for transport dt_socket at address: 8000 你到底幾個前女朋友!!! 謝飛機的前女朋友數量:3 個 謝飛機的前女朋友數量:5 個 謝飛機的前女朋友數量:8 個 :: 執行HotSwapper熱插拔,修改謝飛機前女朋友數量爲0個! 謝飛機的前女朋友數量:4 個 謝飛機的前女朋友數量:5 個 謝飛機的前女朋友數量:0 個 謝飛機的前女朋友數量:0 個 謝飛機的前女朋友數量:0 個 謝飛機的前女朋友數量:0 個 謝飛機的前女朋友數量:0 個 謝飛機的前女朋友數量:0 個 謝飛機的前女朋友數量:0 個 謝飛機的前女朋友數量:0 個 謝飛機的前女朋友數量:0 個 謝飛機的前女朋友數量:0 個 謝飛機的前女朋友數量:0 個 謝飛機的前女朋友數量:0 個 謝飛機的前女朋友數量:0 個 謝飛機的前女朋友數量:0 個 謝飛機的前女朋友數量:0 個 謝飛機的前女朋友數量:0 個 謝飛機的前女朋友數量:0 個 謝飛機的前女朋友數量:0 個 謝飛機的前女朋友數量:0 個 謝飛機的前女朋友數量:0 個 謝飛機的前女朋友數量:0 個 謝飛機的前女朋友數量:0 個 ... Process finished with exit code -1
當看到前女朋友數量爲 0 時,謝飛機露出了羞澀的微笑,並兌現了承諾,將4毛錢給了王牌工程師小傅哥
。
棧
Javassist
對 ASM
這樣的字節碼操做封裝起來提供的API
確實很好操做,在一些場景下也不須要考慮 JVM
中局部變量和操做數棧。但若是須要更高的性能,能夠考慮使用 ASM
。