日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

APM - Javassist 入门 生成一个简单类

發布時間:2025/3/21 java 38 豆豆
生活随笔 收集整理的這篇文章主要介紹了 APM - Javassist 入门 生成一个简单类 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

文章目錄

  • 官網
  • 概述
  • Javassist作用
  • 常用API
  • Javassist 語法
  • Javassist使用流程
  • Demo
  • Demo2
  • 注意事項
  • 參考


官網

http://www.javassist.org/

http://www.javassist.org/tutorial/tutorial.html


概述

Javassist是一個開源的分析、編輯和創建Java字節碼的類庫,可以直接編輯和生成Java生成的字節碼。

相對于bcel, asm等這些工具,開發者不需要了解虛擬機指令,就能動態改變類的結構,或者動態生成類。

Javassist簡單易用, 快速。


Javassist作用

  • 運行時監控插樁埋點
  • AOP動態代理實現(性能上比Cglib生成的要慢)
  • 獲取訪問類結構信息:如獲取參數名稱信息

常用API

類說明
ClassPoolJavassist的類池,使用ClassPool 類可以跟蹤和控制所操作的類, 與 JVM ClassLoader相似
CtClassCtClass提供了類的操作,如在類中動態添加新字段、方法和構造函數、以及改變類、父類和接口的方法。
CtMethod類中的方法,通過它可以給類創建新的方法,還可以修改返回類型,訪問修飾符等, 甚至還可以修改方法體內容代碼
CtConstructor構造函數
CtField類的屬性,通過它可以給類創建新的屬性,還可以修改已有的屬性的類型,訪問修飾符等

Javassist 語法

項目Value
$0, $1, $2, …this and actual parameters
$argsAn array of parameters. The type of $args is Object[].
$$All actual parameters.For example, m($$) is equivalent to m($1,$2,…)
$cflow(…)cflow variable
$rThe result type. It is used in a cast expression.
$wThe wrapper type. It is used in a cast expression.
$_The resulting value
$sigAn array of java.lang.Class objects representing the formal parameter types
$typeA java.lang.Class object representing the formal result type.
$classA java.lang.Class object representing the class currently edited.


Javassist使用流程


Demo

依賴

<dependency><groupId>org.javassist</groupId><artifactId>javassist</artifactId><version>3.18.1-GA</version></dependency> import javassist.*;/*** 使用Javassist 構建 一個新的類 并執行*/ public class FirstJavasisit {public static void main(String[] args) throws CannotCompileException,NotFoundException, InstantiationException, IllegalAccessException {ClassPool pool = new ClassPool(true);// 插入類路徑,通過類路徑去搜索我們要的類pool.insertClassPath(new LoaderClassPath(FirstJavasisit.class.getClassLoader()));// 構建一個新的CtClass對象CtClass targetClass = pool.makeClass("com.artisan.Hello");// 實現一個接口targetClass.addInterface(pool.get(IHello.class.getName()));// 獲取返回類型CtClass returnType = pool.get(void.class.getName());// 方法名稱String mname = "sayHello";// 方法參數CtClass[] parameters = new CtClass[]{pool.get(String.class.getName())};// 實例化方法CtMethod method = new CtMethod(returnType, mname, parameters, targetClass);// 方法中的源碼String src = "{"+ "System.out.println($1);"+ "}";// 設置src到方法中method.setBody(src);// 添加方法targetClass.addMethod(method);// 裝在到當前的ClassLoader中Class cla = targetClass.toClass();// 實例化IHello hello = (IHello) cla.newInstance();// 方法調用hello.sayHello("artisan");}/*** 接口不是必須的,只是為了方便演示,少寫點反射代碼*/public interface IHello {void sayHello(String name);} }


Demo2

讓我們對UserService類 插裝一下

package com.artisan.agent;public class UserService {/*** 無參方法* @throws InterruptedException*/public void sayHello() throws InterruptedException {Thread.sleep(100);System.out.println("hello 小工匠");}/*** 無返回值的* @param name* @param age* @param other* @throws InterruptedException*/public void say2Void(String name,int age,Object other) throws InterruptedException {Thread.sleep(100);System.out.println("hello 小工匠2");}/*** 帶有返回值* @param name* @param age* @param other* @return* @throws InterruptedException*/public String say2(String name,int age,Object other) throws InterruptedException {Thread.sleep(100);System.out.println("hello 小工匠2 with return ");return "ttttt";} }
@Testpublic void test3() throws NotFoundException, CannotCompileException, InterruptedException {// 類加載器ClassPool classPool = new ClassPool();// 追加系統ClassLoaderclassPool.appendSystemPath();// 獲取要操作的類CtClass ctClass = classPool.get("com.artisan.agent.UserService");// 獲取方法CtMethod originMethod = ctClass.getDeclaredMethod("say2Void");// copy 一個新的方法CtMethod newMethod = CtNewMethod.copy(originMethod,ctClass,null);// 設置新名字originMethod.setName(originMethod.getName()+ "$agent");// 對原方法進行包裝,比如加計算方法耗時newMethod.setBody("{ long begin = System.currentTimeMillis();\n" +" say2Void$agent($$);\n" +" long end = System.currentTimeMillis();\n" +" System.out.println(end - begin);" +"}");// 將新方法添加到單簽類中ctClass.addMethod(newMethod);//把修改后的class裝載到JVMctClass.toClass();new com.artisan.agent.UserService().say2Void("art2",18,"xxxx");}@Testpublic void test4() throws NotFoundException, CannotCompileException, InterruptedException {// 類加載器ClassPool classPool = new ClassPool();// 追加系統ClassLoaderclassPool.appendSystemPath();// 獲取要操作的類CtClass ctClass = classPool.get("com.artisan.agent.UserService");// 獲取方法CtMethod originMethod = ctClass.getDeclaredMethod("say2");// copy 一個新的方法CtMethod newMethod = CtNewMethod.copy(originMethod,ctClass,null);// 設置新名字originMethod.setName(originMethod.getName()+ "$agent");// 對原方法進行包裝,比如加計算方法耗時 帶有返回值的的 $rnewMethod.setBody("{ long begin = System.currentTimeMillis();\n" +" say2$agent($$);\n" +" long end = System.currentTimeMillis();\n" +" System.out.println(end - begin);" +" Object s = \"test\" ;" +" return ($r)s ;" +"}");// 將新方法添加到單簽類中ctClass.addMethod(newMethod);//把修改后的class裝載到JVMctClass.toClass();System.out.println((new com.artisan.agent.UserService().say2("art2", 18, "xxxx")));}


注意事項

  • 所引用的類型,必須通過ClassPool獲取后才可以使用
  • 代碼塊中所用到的引用類型,使用時必須寫全量類名
  • 代碼塊內容寫錯了,只有在運行時才報錯
  • javassist只接受單個語句或用大括號括起來的語句塊
  • 動態修改的類,必須在修改之前,jvm中不存在這個類的實例對象。修改方法的實現必須在修改的類加載之前進行

參考

https://baijiahao.baidu.com/s?id=1660843613132087355&wfr=spider&for=pc

https://www.cnblogs.com/scy251147/p/11100961.html

https://blog.csdn.net/21aspnet/article/details/81671777

https://www.cnblogs.com/rickiyang/p/11336268.html

總結

以上是生活随笔為你收集整理的APM - Javassist 入门 生成一个简单类的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。