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

歡迎訪問 生活随笔!

生活随笔

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

java

Java 动态代理与class字节码动态修改技术

發(fā)布時間:2023/12/19 java 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Java 动态代理与class字节码动态修改技术 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

代理分兩種技術,一種是jdk代理(機制就是反射,只對接口操作),一種就是字節(jié)碼操作技術。前者不能算技術,后者算是新的技術。未來將有大的動作或者較為廣泛的應用和變革,它可以實現(xiàn)代碼自我的編碼(人工智能,代碼智能)。

先看看jvm class技術:


字節(jié)碼改寫:


(一)jdk 動態(tài)代理:

1.定義業(yè)務邏輯

public interface Service { //目標方法 public abstract void add(); } public class UserServiceImpl implements Service { public void add() { System.out.println("This is add service"); } }2. 利用 java.lang.reflect.Proxy 類和 java.lang.reflect.InvocationHandler 接口定義代理類的實現(xiàn)。
class MyInvocatioHandler implements InvocationHandler {private Object target;public MyInvocatioHandler(Object target) {this.target = target;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("-----before-----");Object result = method.invoke(target, args);System.out.println("-----end-----");return result;}// 生成代理對象public Object getProxy() {ClassLoader loader = Thread.currentThread().getContextClassLoader();Class<?>[] interfaces = target.getClass().getInterfaces();return Proxy.newProxyInstance(loader, interfaces, this);} }
3.使用動態(tài)代理

public class ProxyTest {public static void main(String[] args) {Service service = new UserServiceImpl();MyInvocatioHandler handler = new MyInvocatioHandler(service);Service serviceProxy = (Service)handler.getProxy();serviceProxy.add();} }

執(zhí)行結果:

-----before----- This is add service -----end-----

代理對象的生成過程由Proxy類的newProxyInstance方法實現(xiàn),分為3個步驟:
1、ProxyGenerator.generateProxyClass方法負責生成代理類的字節(jié)碼,生成邏輯比較復雜,了解原理繼續(xù)分析源碼?sun.misc.ProxyGenerator;

byte[] proxyClassFile = ProxyGenerator.generateProxyClass(proxyName, interfaces, accessFlags);

2、native方法Proxy.defineClass0負責字節(jié)碼加載的實現(xiàn),并返回對應的Class對象。

Class clazz = defineClass0(loader, proxyName, proxyClassFile, 0, proxyClassFile.length);

3、利用clazz.newInstance反射機制生成代理類的對象;

使用?反編譯工具 jad?jad com.sun.proxy.$Proxy.1?看看代理類如何實現(xiàn),反編譯出來的java代碼如下:

public final class $proxy1 extends Proxy implements Service {public $proxy1(InvocationHandler invocationhandler) {super(invocationhandler);}public final boolean equals(Object obj) {try {return ((Boolean)super.h.invoke(this, m1, new Object[] {obj})).booleanValue();}catch(Error _ex) { }catch(Throwable throwable) {throw new UndeclaredThrowableException(throwable);}}public final String toString() {try {return (String)super.h.invoke(this, m2, null);}catch(Error _ex) { }catch(Throwable throwable) {throw new UndeclaredThrowableException(throwable);}}public final void add() {try {super.h.invoke(this, m3, null);return;}catch(Error _ex) { }catch(Throwable throwable) {throw new UndeclaredThrowableException(throwable);}}public final int hashCode() {try {return ((Integer)super.h.invoke(this, m0, null)).intValue();}catch(Error _ex) { }catch(Throwable throwable) {throw new UndeclaredThrowableException(throwable);}}private static Method m1;private static Method m2;private static Method m3;private static Method m0;static {try {m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] {Class.forName("java.lang.Object")});m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);m3 = Class.forName("zzzzzz.Service").getMethod("add", new Class[0]);m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);}catch(NoSuchMethodException nosuchmethodexception) {throw new NoSuchMethodError(nosuchmethodexception.getMessage());}catch(ClassNotFoundException classnotfoundexception) {throw new NoClassDefFoundError(classnotfoundexception.getMessage());}} }
從上述代碼可以發(fā)現(xiàn):
1、生成的$proxy1繼承自Proxy類,并實現(xiàn)了Service接口。
2、執(zhí)行代理對象的方法,其實就是執(zhí)行InvocationHandle對象的invoke方法,傳入的參數(shù)分別是當前代理對象,當前執(zhí)行的方法和參數(shù)。

jdk動態(tài)代理使用的局限性
通過反射類ProxyInvocationHandler回調接口實現(xiàn)的jdk動態(tài)代理,要求委托類必須實現(xiàn)一個接口,但事實上并不是所有類都有接口,對于沒有實現(xiàn)接口的類,便無法使用該方方式實現(xiàn)動態(tài)代理。


(二)字節(jié)碼修改技術

了解該技術必然先了解Java class文件格式 《讀《深入jvm原理》之class文件

目前字節(jié)碼修改技術有ASM,javassist等。cglib就是基于封裝的Asm. Spring 就是使用cglib代理庫。

ASM 是一個 Java 字節(jié)碼操控框架。它能夠以二進制形式修改已有類或者動態(tài)生成類。ASM 可以直接產生二進制 class 文件,也可以在類被加載入 Java 虛擬機之前動態(tài)改變類行為。ASM 從類文件中讀入信息后,能夠改變類行為,分析類信息,甚至能夠根據(jù)用戶要求生成新類。
不過ASM在創(chuàng)建class字節(jié)碼的過程中,操縱的級別是底層JVM的匯編指令級別,這要求ASM使用者要對class組織結構和JVM匯編指令有一定的了解。

Java字節(jié)碼生成開源框架介紹--Javassist:

Javassist是一個開源的分析、編輯和創(chuàng)建Java字節(jié)碼的類庫。是由東京工業(yè)大學的數(shù)學和計算機科學系的 Shigeru Chiba (千葉 滋)所創(chuàng)建的。它已加入了開放源代碼JBoss 應用服務器項目,通過使用Javassist對字節(jié)碼操作為JBoss實現(xiàn)動態(tài)AOP框架。javassist是jboss的一個子項目,其主要的優(yōu)點,在于簡單,而且快速。直接使用java編碼的形式,而不需要了解虛擬機指令,就能動態(tài)改變類的結構,或者動態(tài)生成類。


總結

以上是生活随笔為你收集整理的Java 动态代理与class字节码动态修改技术的全部內容,希望文章能夠幫你解決所遇到的問題。

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