Java靜態(tài)代理和動態(tài)代理詳解
更新時間:2024年11月01日 08:37:09 作者:louisgeek
這篇文章主要介紹了Java靜態(tài)代理和動態(tài)代理,本文通過代碼示例給大家講解的非常詳細,對大家的學(xué)習(xí)或工作有一定的幫助,需要的朋友可以參考下
Java 靜態(tài)代理和動態(tài)代理
- 代理模式主要有靜態(tài)代理和動態(tài)代理兩種實現(xiàn)方式
靜態(tài)代理
- 指程序在運行之前所需要的代理類就已經(jīng)被創(chuàng)建好了
- 通常情況下代理類、目標(biāo)類都需要實現(xiàn)同一個接口
- 代理類內(nèi)部維護了目標(biāo)類的引用,在不改變目標(biāo)類的情況下通過代理類增加功能來擴展目標(biāo)類的邏輯功能,真正的業(yè)務(wù)邏輯還是由目標(biāo)類來實現(xiàn),代理類只是調(diào)用目標(biāo)類的相關(guān)方法,符合開閉原則
- 一般需要為每個目標(biāo)類都創(chuàng)建代理類和接口,可能導(dǎo)致類的數(shù)量大大增加
- 通常情況下接口一旦修改,代理類和目標(biāo)類都需要修改,代碼耦合度較高
示例
接口
public interface ILogin { void doLogin(); }
目標(biāo)類
public class UserLogin implements ILogin { @Override public void doLogin(){ System.out.print("用戶登錄邏輯"); } }
代理類
public class UserLoginProxy implements ILogin { private UserLogin mUserLogin; public UserLoginProxy() { mUserLogin = new UserLogin(); } @Override public void doLogin(){ //... System.out.print("登錄前邏輯"); //真正的業(yè)務(wù)邏輯還是由目標(biāo)類來實現(xiàn) mUserLogin.doLogin(); System.out.print("登錄后邏輯"); //... } }
使用
public static void main(String[] args){ // ILogin iLogin = new UserLoginProxy(); iLogin.doLogin(); }
動態(tài)代理
- 動態(tài)代理指在程序運行時通過反射機制等技術(shù)動態(tài)創(chuàng)建出代理對象
- 基于接口的動態(tài)代理,通常通過 java.lang.reflect.Proxy 類和 java.lang.reflect.InvocationHandler 接口實現(xiàn)動態(tài)代理
- 基于類的動態(tài)代理,比如使用 CGLIB(Code Generation Library,一個強大的 Java 字節(jié)碼生成庫)
- InvocationHandler 調(diào)用處理器,是一個接口,有個 invoke 方法
- 通過使用 Proxy#newProxyInstance 來創(chuàng)建指定接口的代理實現(xiàn)類,當(dāng)調(diào)用代理對象任何方法時都會調(diào)用 InvocationHandler#invoke 方法,可以在這個方法中拿到傳入的參數(shù),注解等
- 只能實現(xiàn)基于接口的動態(tài)代理,因為 Java 是單繼承的,它在動態(tài)生成 $ProxyX 代理類的時候已經(jīng)繼承 Proxy 類了
- 可以減少類的數(shù)量,降低工作量,靈活性高,可以在運行時動態(tài)地為不同的委托類創(chuàng)建代理對象
- 減少對業(yè)務(wù)接口的依賴,降低耦合,便于后期維護,可以用于實現(xiàn) AOP 面向切面編程,比如在某個邏輯功能前后添加日志記錄、監(jiān)控性能和權(quán)限檢查控制等操作
- 由于因為使用了反射,所以會在運行時會消耗一定的性能
private InvocationHandler mInvocationHandler = new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //target 是目標(biāo)類對象 Object result = method.invoke(target,args); // return result; } }; //方式1 //創(chuàng)建代理類的 Class 對象,參數(shù) (ClassLoader 類加載器,Class<?>) Class<?> proxyClass = Proxy.getProxyClass(Toast.class.getClassLoader(), Toast.class); //通過反射實例化代理對象 Toast toastProxy = (Toast) proxyClass.getConstructor(InvocationHandler.class).newInstance(mInvocationHandler); //方式2,是方法1的簡化版,newProxyInstance 內(nèi)部代碼邏輯和方法1基本一致 //直接創(chuàng)建代理對象,參數(shù) (ClassLoader 類加載器,Class<?>[],InvocationHandler) Toast toastProxy2 = (Toast) Proxy.newProxyInstance(Toast.class.getClassLoader(),new Class<?>[]{Toast.class}, mInvocationHandler);
示例
接口
public interface ICalculator { int add(int a, int b); int minus(int a, int b); }
目標(biāo)類
public class Calculator implements ICalculator { @Override public int add(int a, int b) { return a + b; } @Override public int minus(int a, int b) { return a - b; } }
動態(tài)代理的處理類
public class CalculatorInvocationHandler implements InvocationHandler { private Object target; public CalculatorInvocationHandler(Object target) { this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // 在方法調(diào)用前可以添加一些邏輯 Object result = method.invoke(target, args); // 在方法調(diào)用后也可以添加一些邏輯 return result; } }
使用
//目標(biāo)類 ICalculator calculator = new Calculator(); //代理類 ICalculator proxyCalculator = (ICalculator) Proxy.newProxyInstance( calculator.getClass().getClassLoader(), calculator.getClass().getInterfaces(), new CalculatorInvocationHandler(calculator) );
到此這篇關(guān)于Java靜態(tài)代理和動態(tài)代理詳解的文章就介紹到這了,更多相關(guān)Java靜態(tài)和動態(tài)代理內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Curator實現(xiàn)zookeeper的節(jié)點監(jiān)聽詳解
這篇文章主要介紹了Curator實現(xiàn)zookeeper的節(jié)點監(jiān)聽詳解,Curtor框架中一共有三個實現(xiàn)監(jiān)聽的方式,一種是NodeCache監(jiān)聽指定節(jié)點,一種是pathChildrenCache監(jiān)聽子節(jié)點,一種是TreeCache可以監(jiān)控所有節(jié)點 相當(dāng)于以上兩種的合集,需要的朋友可以參考下2023-12-12SpringBoot啟動流程SpringApplication準(zhǔn)備階段源碼分析
這篇文章主要為大家介紹了SpringBoot啟動流程SpringApplication準(zhǔn)備階段源碼分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-04-04SpringBoot中日志切面實現(xiàn)小結(jié)
本文介紹了SpringBoot中日志切面實現(xiàn)小結(jié),通過定義一個自定義注解和創(chuàng)建一個日志切面類,為方法添加日志記錄功能,感興趣的可以了解一下2024-11-11java搭建一個Socket服務(wù)器響應(yīng)多用戶訪問
本篇文章主要介紹了java搭建一個Socket服務(wù)器響應(yīng)多用戶訪問,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-02-02SpringBoot創(chuàng)建多模塊項目的全過程記錄
這篇文章主要給大家介紹了關(guān)于SpringBoot創(chuàng)建多模塊項目的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-01-01