Java 动态代理与class字节码动态修改技术
代理分兩種技術(shù),一種是jdk代理(機制就是反射,只對接口操作),一種就是字節(jié)碼操作技術(shù)。前者不能算技術(shù),后者算是新的技術(shù)。未來將有大的動作或者較為廣泛的應(yīng)用和變革,它可以實現(xiàn)代碼自我的編碼(人工智能,代碼智能)。
先看看jvm class技術(shù):
字節(jié)碼改寫:
(一)jdk 動態(tài)代理:
1.定義業(yè)務(wù)邏輯
public interface Service { //目標(biāo)方法 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í)行結(jié)果:
-----before----- This is add service -----end----- 代理對象的生成過程由Proxy類的newProxyInstance方法實現(xiàn),分為3個步驟:
1、ProxyGenerator.generateProxyClass方法負責(zé)生成代理類的字節(jié)碼,生成邏輯比較復(fù)雜,了解原理繼續(xù)分析源碼?sun.misc.ProxyGenerator;
2、native方法Proxy.defineClass0負責(zé)字節(jié)碼加載的實現(xiàn),并返回對應(yīng)的Class對象。
Class clazz = defineClass0(loader, proxyName, proxyClassFile, 0, proxyClassFile.length);3、利用clazz.newInstance反射機制生成代理類的對象;
使用?反編譯工具 jad?jad com.sun.proxy.$Proxy.1?看看代理類如何實現(xiàn),反編譯出來的java代碼如下:
從上述代碼可以發(fā)現(xiàn):
1、生成的$proxy1繼承自Proxy類,并實現(xiàn)了Service接口。
2、執(zhí)行代理對象的方法,其實就是執(zhí)行InvocationHandle對象的invoke方法,傳入的參數(shù)分別是當(dāng)前代理對象,當(dāng)前執(zhí)行的方法和參數(shù)。
jdk動態(tài)代理使用的局限性
通過反射類Proxy和InvocationHandler回調(diào)接口實現(xiàn)的jdk動態(tài)代理,要求委托類必須實現(xiàn)一個接口,但事實上并不是所有類都有接口,對于沒有實現(xiàn)接口的類,便無法使用該方方式實現(xiàn)動態(tài)代理。
(二)字節(jié)碼修改技術(shù)
了解該技術(shù)必然先了解Java class文件格式 《讀《深入jvm原理》之class文件》
目前字節(jié)碼修改技術(shù)有ASM,javassist等。cglib就是基于封裝的Asm. Spring 就是使用cglib代理庫。
ASM 是一個 Java 字節(jié)碼操控框架。它能夠以二進制形式修改已有類或者動態(tài)生成類。ASM 可以直接產(chǎn)生二進制 class 文件,也可以在類被加載入 Java 虛擬機之前動態(tài)改變類行為。ASM 從類文件中讀入信息后,能夠改變類行為,分析類信息,甚至能夠根據(jù)用戶要求生成新類。
不過ASM在創(chuàng)建class字節(jié)碼的過程中,操縱的級別是底層JVM的匯編指令級別,這要求ASM使用者要對class組織結(jié)構(gòu)和JVM匯編指令有一定的了解。
Java字節(jié)碼生成開源框架介紹--Javassist:
Javassist是一個開源的分析、編輯和創(chuàng)建Java字節(jié)碼的類庫。是由東京工業(yè)大學(xué)的數(shù)學(xué)和計算機科學(xué)系的 Shigeru Chiba (千葉 滋)所創(chuàng)建的。它已加入了開放源代碼JBoss 應(yīng)用服務(wù)器項目,通過使用Javassist對字節(jié)碼操作為JBoss實現(xiàn)動態(tài)AOP框架。javassist是jboss的一個子項目,其主要的優(yōu)點,在于簡單,而且快速。直接使用java編碼的形式,而不需要了解虛擬機指令,就能動態(tài)改變類的結(jié)構(gòu),或者動態(tài)生成類。
總結(jié)
以上是生活随笔為你收集整理的Java 动态代理与class字节码动态修改技术的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 读《深入jvm原理》之class文件
- 下一篇: 前天涯社区执行总编欲直播带货:筹款300