Java深入分析動(dòng)態(tài)代理
"代理"這個(gè)詞相信大家并不陌生,簡單來說就是代替廠家來售賣商品,代理替代廠家售賣商品,顧客找代理購買商品。也就是說:1)顧客和廠家之間是不可見的,顧客不知道背后的廠家是誰。2)代理可以對顧客進(jìn)行“定位”,更精確的售賣給需要的客戶群體。
代理模式
代理模式:為其他對象提供一種代理以控制對這個(gè)對象的訪問,也就是創(chuàng)建一個(gè)代理對象作為客戶端和目標(biāo)對象之間的中介,主要目的就是保護(hù)目標(biāo)對象或增強(qiáng)目標(biāo)對象
通過使用代理模式,通常有以下兩個(gè)優(yōu)點(diǎn):
\1) 可以隱藏被代理類的實(shí)現(xiàn)
\2) 可以實(shí)現(xiàn)客戶與被代理類間的解耦,在不修改被代理類代碼的情況下能夠做一些額外的處理
靜態(tài)代理
所謂的動(dòng)態(tài)代理,就是通過聲明一個(gè)明確的代理類來訪問源對象,一個(gè)代理只能服務(wù)于一種產(chǎn)品,當(dāng)有n種產(chǎn)品時(shí),就需要n個(gè)代理,這樣就不利于業(yè)務(wù)的發(fā)展。
舉例:我們有兩個(gè)接口,Mouse和Keyboard,每個(gè)接口都有一個(gè)實(shí)現(xiàn)類
實(shí)現(xiàn)類中的代碼如下:
public class LogitechMouse implements Mouse{ @Override public void sell() { System.out.println("出售羅技鼠標(biāo)"); } } public class HHKBKeyboard implements Keyboard{ @Override public void sell() { System.out.println("出售HHKB鍵盤"); } }
現(xiàn)在我們要做的就是讓代理在調(diào)用sell()
前輸出一句售前了解,調(diào)用后輸出一句售后服務(wù)
那我們只需寫兩個(gè)代理類MouseProxy
和KeyboardProxy
public class MouseProxy implements Mouse { private Mouse mouse; public MouseProxy(Mouse mouse) { this.mouse = mouse; } @Override public void sell() { System.out.println("售前了解"); mouse.sell(); System.out.println("售后服務(wù)"); } } public class KeyboardProxy implements Keyboard{ private Keyboard keyboard; public KeyboardProxy(Keyboard keyboard) { this.keyboard = keyboard; } @Override public void sell() { System.out.println("售前了解"); keyboard.sell(); System.out.println("售后服務(wù)"); } }
最終執(zhí)行為:
public class Test { public static void main(String[] args) { Mouse logitechMouse = new LogitechMouse(); MouseProxy mouseProxy = new MouseProxy(logitechMouse); mouseProxy.sell(); Keyboard hhkbKeyboard = new HHKBKeyboard(); KeyboardProxy keyboardProxy = new KeyboardProxy(hhkbKeyboard); keyboardProxy.sell(); } }
輸出:
售前了解
出售羅技鼠標(biāo)
售后服務(wù)
售前了解
出售HHKB鍵盤
售后服務(wù)
靜態(tài)代理的代碼非常簡單易懂,這種模式雖好,但是也有明顯的缺點(diǎn):
- 會存在大量冗余的代理類,這里只有兩個(gè)接口,如果有n個(gè)接口,那么就要定義n個(gè)代理類。
- 不易維護(hù),一旦接口更改,代理類和被代理類都要更改。
那么這個(gè)時(shí)候就可以使用動(dòng)態(tài)代理來解決了
動(dòng)態(tài)代理
代理類在程序運(yùn)行時(shí)創(chuàng)建代理的方式叫動(dòng)態(tài)代理,也就是說代理類并不是在java代碼中定義的,而是在運(yùn)行的時(shí)候動(dòng)態(tài)生成的
JDK動(dòng)態(tài)代理
JDK從1.3版本就開始支持動(dòng)態(tài)代理類的創(chuàng)建。主要核心類只有2個(gè):java.lang.reflect.Proxy
和java.lang.reflect.InvocationHandler
還是上面的例子,用JDK動(dòng)態(tài)代理如下:
public class JDKProxy implements InvocationHandler { private Object object; public JDKProxy(Object object) { this.object = object; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("售前了解"); Object invoke = method.invoke(object, args); System.out.println("售后服務(wù)"); return invoke; } }
當(dāng)我們調(diào)用代理類對象的方法時(shí),這個(gè)“調(diào)用”會轉(zhuǎn)送到invoke方法中,
代理類對象作為proxy參數(shù)傳入,
參數(shù)method標(biāo)識了我們具體調(diào)用的是代理類的哪個(gè)方法,
args為這個(gè)方法的參數(shù)。
這樣一來,我們對代理類中的所有方法的調(diào)用都會變?yōu)閷nvoke的調(diào)用,這樣我們可以在invoke方法中添加統(tǒng)一的處理邏輯(也可以根據(jù)method參數(shù)對不同的代理類方法做不同的處理)。因此我們可以在中介類的invoke方法中實(shí)現(xiàn)輸出售前了解,再調(diào)用被代理類的方法,再輸出售后服務(wù)。
執(zhí)行代碼
public class Test { public static void main(String[] args) { Mouse logitechMouse = new LogitechMouse(); JDKProxy jdkProxy = new JDKProxy(logitechMouse); Mouse mouse= (Mouse)Proxy.newProxyInstance(jdkProxy.getClass().getClassLoader(), new Class[]{Mouse.class}, jdkProxy); mouse.sell(); HHKBKeyboard hhkbKeyboard = new HHKBKeyboard(); JDKProxy jdkProxy1 = new JDKProxy(hhkbKeyboard); Keyboard keyboard = (Keyboard)Proxy.newProxyInstance(jdkProxy1.getClass().getClassLoader(), new Class[]{Keyboard.class}, jdkProxy1); keyboard.sell(); } }
可以看到無論多少個(gè)接口,只需要一個(gè)代理類就可以了。
CGLIB動(dòng)態(tài)代理
代理類:
public class CGLIBProcy implements MethodInterceptor { private Enhancer enhancer = new Enhancer(); private Object object; public CGLIBProcy(Object object) { this.object = object; } public Object getProxy(){ //設(shè)置需要?jiǎng)?chuàng)建子類的類 enhancer.setSuperclass(object.getClass()); enhancer.setCallback(this); //創(chuàng)建代理對象 return enhancer.create(); } // o: cglib 動(dòng)態(tài)生成的代理類的實(shí)例 // method:實(shí)體類所調(diào)用的都被代理的方法的引用 // objects 參數(shù)列表 // methodProxy:生成的代理類對方法的代理引用 @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { System.out.println("售前了解"); Object invoke = method.invoke(object, objects); System.out.println("售后處理"); return invoke; } }
執(zhí)行代碼:
public class Test { public static void main(String[] args) { Mouse logitechMouse = new LogitechMouse(); CGLIBProcy cglibProcy = new CGLIBProcy(logitechMouse); Mouse proxy = (Mouse)cglibProcy.getProxy(); proxy.sell(); cglibProcy = new CGLIBProcy(new HHKBKeyboard()); Keyboard keyboard = (Keyboard)cglibProcy.getProxy(); keyboard.sell(); } }
JDK代理與CGLIB代理的區(qū)別
- JDK動(dòng)態(tài)代理實(shí)現(xiàn)接口,CGLIB動(dòng)態(tài)繼承思想
- JDK動(dòng)態(tài)代理(目標(biāo)對象存在接口時(shí))執(zhí)行效率高于CIGLIB
- 如果對象有接口實(shí)現(xiàn),選擇JDK代理,如果沒有接口實(shí)現(xiàn)選擇CGILB代理
到此這篇關(guān)于Java深入分析動(dòng)態(tài)代理的文章就介紹到這了,更多相關(guān)Java動(dòng)態(tài)代理內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- 一文了解Java動(dòng)態(tài)代理的原理及實(shí)現(xiàn)
- Java實(shí)現(xiàn)JDK動(dòng)態(tài)代理的原理詳解
- 深入理解Java動(dòng)態(tài)代理與靜態(tài)代理
- Java實(shí)例講解動(dòng)態(tài)代理
- Java的動(dòng)態(tài)代理和靜態(tài)代理詳解
- Java動(dòng)態(tài)代理的示例詳解
- Java?靜態(tài)代理與動(dòng)態(tài)代理解析
- 帶你重新認(rèn)識Java動(dòng)態(tài)代理
- Java實(shí)現(xiàn)動(dòng)態(tài)代理的實(shí)例代碼
相關(guān)文章
java 中使用匿名類直接new接口詳解及實(shí)例代碼
這篇文章主要介紹了java 中使用匿名類直接new接口詳解及實(shí)例代碼的相關(guān)資料,需要的朋友可以參考下2017-03-03Java實(shí)現(xiàn)數(shù)據(jù)庫連接池的方法
這篇文章主要介紹了Java實(shí)現(xiàn)數(shù)據(jù)庫連接池的方法,涉及java數(shù)據(jù)庫連接池的創(chuàng)建、連接、刷新、關(guān)閉及狀態(tài)獲取的常用技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-07-07Java解析http協(xié)議字符串的方法實(shí)現(xiàn)
本文主要介紹了Java解析http協(xié)議字符串的方法實(shí)現(xiàn),我們探討了如何使用Java解析HTTP協(xié)議字符串,并將其封裝成了一個(gè)HttpRequest類,具有一定的參考價(jià)值,感興趣的可以了解一下2023-09-09Mybatis Plus 實(shí)現(xiàn)批量插入的示例代碼
本文主要介紹了Mybatis Plus 實(shí)現(xiàn)批量插入的示例代碼,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-09-09JAVA實(shí)現(xiàn)基于Tcp協(xié)議的簡單Socket通信實(shí)例
本篇文章主要介紹了JAVA實(shí)現(xiàn)基于Tcp協(xié)議的簡單Socket通信實(shí)例,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-01-01詳解Spring AOP 攔截器的基本實(shí)現(xiàn)
本篇文章主要介紹了詳解Spring AOP 攔截器的基本實(shí)現(xiàn),小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-03-03