動態代理用反射技術、類加載技術以及代碼生成技術實作代理邏輯的抽取復用以及代理實體的生成獲取,用常規方式無法抽取復用相同的代理邏輯,因為目標方法的呼叫是不同的,只有通過反射的Method來統一目標方法,進而完成代理邏輯的抽取復用,這樣每個代理方法呼叫這個通用的代理邏輯,但是還是有大量的重復代碼,大量相同的方法,大量內部結構相同的類,既然都相同,也就是生成的邏輯都一樣,那就把這些代理類的生成交給統一的ProxyGenerator來完成,這也消除了全部重復代碼,同時也避免了類爆炸,
動態代理解決的是靜態代理中的代理邏輯相同但是無法抽取復用的難題,用反射的Method同一目標方法的呼叫,進而代理邏輯抽取到InvocationHandler中,進而InvocationHandler依賴目標類,代理類統一依賴InvocattionHnadler,因為InvocationHandler中用到了Method,InvocationHandler可以代理任何目標,進而代理類可以代理任何目標,由于代理類的代碼是相同的,所以代理類可以用代碼生成技術進行統一生成進而消除重復代碼,這樣所有的重復代碼都去除了
動態代理可以為任何類做代理且是在運行時生成,通過呼叫JDK提供的一個代理工廠Proxy.newProxyInstance來生成代理,這個代理工廠需要配置三個引數:
1.生成的代理類的二進制位元組碼的加載器以生成代理類的Class實體去實體化代理類以最終被回傳呼叫
2.被代理的介面
3.代理邏輯,此代理邏輯以InvocationHandler的形式通過已生成的代理類Class實體反射呼叫此代理類的構造器注入到代理實體 它有對目標類的參考,它有裝配代理邏輯的通用介面invoke,這個invoke最關鍵知道代理目標Method,代理類中的方法只需呼叫這個invoke就好了,ProxyGenerator負責Method分配到各個代理類中的方法,
代理類位元組碼生成邏輯:
根據傳進來的介面能做一下事情:
1.class 代理類 extends Proxy implements 要代理的介面 { //繼承Proxy能構造器注入InvocationHandler
2.public 代理類(InvocationHandler h) {
super(h);
3.private static Method 要代理的介面中的方法的Method物件;
4.static {
要代理的介面中的方法的Method物件=Class.forName("要代理的介面的名字")
.getMethod("要代理的介面中的方法的名字",new Class[]{Class.forName}
5.public final 回傳型別 要代理的介面中的方法(引數) {
return (回傳型別)this.h.invoke(this,要代理的介面中的方法的Method物件,引數);
介面類
package com.life.proxy; public interface IUserDao { public void save(); }
目標物件
package com.life.proxy; public class UserDao implements IUserDao{ @Override public void save() { System.out.println("保存資料"); } }
代理工廠
package com.life.proxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class ProxyFactory { private Object target;// 維護一個目標物件 public ProxyFactory(Object target) { this.target = target; } // 為目標物件生成代理物件 public Object getProxyInstance() { return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("開啟事務"); // 執行目標物件方法 Object returnValue =https://www.cnblogs.com/tsai-87/archive/2022/03/21/ method.invoke(target, args); System.out.println("提交事務"); return null; } }); } }
測驗類
package com.life.proxy; import org.junit.Test; public class TestProxy { @Test public void testDynamicProxy (){ IUserDao target = new UserDao(); System.out.println(target.getClass()); //輸出目標物件資訊 IUserDao proxy = (IUserDao) new ProxyFactory(target).getProxyInstance(); System.out.println(proxy.getClass()); //輸出代理物件資訊 proxy.save(); //執行代理方法 } }
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/448175.html
標籤:其他
上一篇:設計模式之享元模式
