Java結(jié)構(gòu)型設(shè)計(jì)模式中代理模式示例詳解
代理模式
代理模式(Proxy Pattern)屬于結(jié)構(gòu)型模式。
它是指為其他對(duì)象提供一種代理以控制對(duì)這個(gè)對(duì)象的訪問(wèn)。
在某些情況下,一個(gè)對(duì)象不適合或者不能直接引用另一個(gè)對(duì)象,而代理對(duì)象可以在客戶端和目標(biāo)對(duì)象之間起到中介的作用。
在代理模式中,創(chuàng)建具有現(xiàn)有對(duì)象的對(duì)象,以便向外界提供功能接口。
想在訪問(wèn)一個(gè)類(lèi)時(shí)做一些控制的時(shí)候就可以是用代理模式。
分類(lèi)
代理模式屬于結(jié)構(gòu)型模式,分為靜態(tài)代理和動(dòng)態(tài)代理。
1.靜態(tài)代理:靜態(tài)定義代理類(lèi)
靜態(tài)代理需要自己生成代理類(lèi)
2.動(dòng)態(tài)代理:動(dòng)態(tài)生成代理類(lèi)
動(dòng)態(tài)代理不用親自去實(shí)現(xiàn),通常使用現(xiàn)成的API即可。目前普遍使用的是JDK自帶的代理與CGLIB提供的類(lèi)庫(kù)。
主要角色
代理模式一般包含三種角色:
1.抽象主題角色(Subject)
抽象主題類(lèi)的主要職責(zé)是聲明真實(shí)主題與代理的共同接口方法,該類(lèi)可以是接口也可以是抽象類(lèi)
2.真實(shí)主題角色(RealSubject)
該類(lèi)也被稱為被代理類(lèi),該類(lèi)定義了代理所表示的真實(shí)對(duì)象,是負(fù)責(zé)執(zhí)行系統(tǒng)真正的羅輯業(yè)務(wù)對(duì)象
3.代理主題角色(Proxy)
代理主題也被稱為代理類(lèi),其內(nèi)部特有RealSubject的引用,因此具備完全的對(duì)RealSubject的代理權(quán)。
客戶端調(diào)用代理對(duì)象的方法,同時(shí)也調(diào)用被代理對(duì)象的方法,但是會(huì)在代理對(duì)象前后增加一些處理代碼??梢岳斫鉃榇a增強(qiáng),實(shí)際上就是在原代碼羅輯前后增加一些代碼邏輯,而使調(diào)用者無(wú)感知。
作用
1.保護(hù)目標(biāo)對(duì)象,將代理對(duì)象與真實(shí)被調(diào)用目標(biāo)對(duì)象分離
2.增強(qiáng)目標(biāo)對(duì)象
3.降低系統(tǒng)耦合性,提升擴(kuò)展性
靜態(tài)代理與動(dòng)態(tài)代理的區(qū)別
1.靜態(tài)代理只能通過(guò)手動(dòng)完成代理操作,如果被代理類(lèi)增加了新的方法,代理類(lèi)需要同步增加,違背開(kāi)閉原則。
2.動(dòng)態(tài)代理采用在運(yùn)行時(shí)動(dòng)態(tài)生成代碼的方式,取消了對(duì)被代理類(lèi)的擴(kuò)展限制,遵循開(kāi)閉原測(cè)。
3.若動(dòng)態(tài)代理要對(duì)目標(biāo)類(lèi)的增強(qiáng)邏輯進(jìn)行擴(kuò)展,結(jié)合策略模式,只需要新增策略類(lèi)便可完成,無(wú)須修改代理類(lèi)的代碼。
靜態(tài)代理的基本使用
靜態(tài)代理需要自己生成代理類(lèi)
創(chuàng)建抽象主題
public interface ISubject { /** * 買(mǎi)票 */ void buyTickets(); }
創(chuàng)建真實(shí)主題
public class RealSubject implements ISubject { public void buyTickets() { System.out.println("進(jìn)行買(mǎi)票操作"); } }
創(chuàng)建代理主題
public class Proxy implements ISubject { private ISubject subject; public Proxy(ISubject subject) { this.subject = subject; } public void buyTickets() { before(); subject.buyTickets(); after(); } public void before() { System.out.println("買(mǎi)票前的操作"); } public void after() { System.out.println("買(mǎi)票后的操作"); } }
客戶端調(diào)用
public static void main(String[] args) { Proxy proxy = new Proxy(new RealSubject()); proxy.buyTickets(); }
買(mǎi)票前的操作
進(jìn)行買(mǎi)票操作
買(mǎi)票后的操作
JDK動(dòng)態(tài)代理的基本使用
創(chuàng)建抽象主題
public interface IUser { /** * 購(gòu)物 */ void shopping(); }
創(chuàng)建真實(shí)主題
public class User implements IUser{ @Override public void shopping() { System.out.println("user shopping...."); } }
創(chuàng)建代理主題
public class JDKProxy implements InvocationHandler { private Object tarjet; public JDKProxy(Object tarjet) { this.tarjet = tarjet; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("代理user,執(zhí)行shopping()開(kāi)始..."); Object oj = method.invoke(tarjet, args); System.out.println("代理user,執(zhí)行shopping()結(jié)束..."); return oj; } }
客戶端調(diào)用
public static void main(String[] args) { User user = new User(); JDKProxy jdkProxy = new JDKProxy(user); IUser proxyInstance = (IUser) Proxy.newProxyInstance(user.getClass().getClassLoader(), user.getClass().getInterfaces(), jdkProxy); proxyInstance.shopping(); }
代理user,執(zhí)行shopping()開(kāi)始...
user shopping....
代理user,執(zhí)行shopping()結(jié)束...
小優(yōu)化
在調(diào)用時(shí)候,傳入了一推參數(shù),可進(jìn)一步優(yōu)化
public class JDKProxy implements InvocationHandler { private Object tarjet; public Object JDKProxy(Object target){ this.tarjet = target; Class<?> clazz = target.getClass(); return Proxy.newProxyInstance(clazz.getClassLoader(),clazz.getInterfaces(),this); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("代理user,執(zhí)行shopping()開(kāi)始..."); Object oj = method.invoke(tarjet, args); System.out.println("代理user,執(zhí)行shopping()結(jié)束..."); return oj; } }
public static void main(String[] args) { JDKProxy jdkProxy = new JDKProxy(); IUser user= (IUser)jdkProxy.JDKProxy(new User()); user.shopping(); }
CGLIB動(dòng)態(tài)代理的基本使用
CGLIB動(dòng)態(tài)代理也不需要生成代理類(lèi),實(shí)現(xiàn)MethodInterceptor 就可以了。
注意:CGLib不能代理final的方法
創(chuàng)建抽象主題
注意:CGLb代理的目標(biāo)對(duì)象不需要實(shí)現(xiàn)任何接口,就可以通過(guò)動(dòng)態(tài)繼承目標(biāo)對(duì)象實(shí)現(xiàn)動(dòng)態(tài)代理。所以此處可以不用創(chuàng)建接口。直接使用真實(shí)主題。
public interface IUser { public void shopping(); }
創(chuàng)建真實(shí)主題
public class User implements IUser{ @Override public void shopping() { System.out.println("user shopping...."); } }
直接使用真實(shí)主題。
public class User { public void shopping() { System.out.println("user shopping...."); } }
創(chuàng)建代理主題
public class CglibProxy implements MethodInterceptor { @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { System.out.println("代理user,執(zhí)行shopping()開(kāi)始..."); Object invokeSuper = methodProxy.invokeSuper(o, objects); System.out.println("代理user,執(zhí)行shopping()結(jié)束..."); return invokeSuper; } }
客戶端調(diào)用
public static void main(String[] args) { CglibProxy cglibProxy = new CglibProxy(); Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(User.class); enhancer.setCallback(cglibProxy); IUser iUser = (IUser) enhancer.create(); iUser.shopping(); }
小優(yōu)化
在客戶端調(diào)用時(shí),稍顯復(fù)雜,可進(jìn)一步優(yōu)化
public class CglibProxy implements MethodInterceptor { public Object getInstance(Class<?> clazz) throws Exception{ //相當(dāng)于Proxy,代理工具類(lèi) Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(clazz); enhancer.setCallback(this); return enhancer.create(); } @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { System.out.println("代理user,執(zhí)行shopping()開(kāi)始..."); Object invokeSuper = methodProxy.invokeSuper(o, objects); System.out.println("代理user,執(zhí)行shopping()結(jié)束..."); return invokeSuper; } }
public static void main(String[] args) throws Exception { IUser user = (IUser) new CglibProxy().getInstance(User.class); user.shopping(); }
CGLIB與JDK動(dòng)態(tài)代理區(qū)別
1.執(zhí)行條件
JDK動(dòng)態(tài)代理實(shí)現(xiàn)了被代理對(duì)象的接口。CGLb代理的目標(biāo)對(duì)象不需要實(shí)現(xiàn)任何接口,它是通過(guò)動(dòng)態(tài)繼承目標(biāo)對(duì)象實(shí)現(xiàn)動(dòng)態(tài)代理。
2.實(shí)現(xiàn)機(jī)制
JDK動(dòng)態(tài)代理調(diào)用代理方法是由Java內(nèi)部的反射機(jī)制來(lái)實(shí)現(xiàn)的,需要讀取接口信息。CGLib動(dòng)態(tài)代理是通過(guò)FastClass機(jī)制來(lái)實(shí)現(xiàn)的,需要覆蓋父類(lèi)方法。
3.性能
首先都在運(yùn)行期生成字節(jié)碼。
JDK動(dòng)態(tài)代理的代理邏輯簡(jiǎn)單,直接寫(xiě)Class字節(jié)碼,使用反射機(jī)制在生成類(lèi)的過(guò)程中比較高效。
CGLib代理實(shí)現(xiàn)更復(fù)雜,使用ASM框架寫(xiě)Class字節(jié)碼,但是asm在生成類(lèi)之后的相關(guān)執(zhí)行過(guò)程中比較高效。但是可以通過(guò)將asm生成的類(lèi)進(jìn)行緩存,解決asm生成類(lèi)過(guò)程低效問(wèn)題。
一句話:CGLib生成代理類(lèi)比JDK動(dòng)態(tài)代理效率低,但是執(zhí)行效率比JDK動(dòng)態(tài)代理高。
到此這篇關(guān)于Java結(jié)構(gòu)型設(shè)計(jì)模式中代理模式示例詳解的文章就介紹到這了,更多相關(guān)Java代理模式內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java volatile如何實(shí)現(xiàn)禁止指令重排
這篇文章主要介紹了Java volatile如何實(shí)現(xiàn)禁止指令重排,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-11-11Java操作mongodb增刪改查的基本操作實(shí)戰(zhàn)指南
MongoDB是一個(gè)基于分布式文件存儲(chǔ)的數(shù)據(jù)庫(kù),由c++語(yǔ)言編寫(xiě),旨在為WEB應(yīng)用提供可擴(kuò)展的高性能數(shù)據(jù)存儲(chǔ)解決方案,下面這篇文章主要給大家介紹了關(guān)于Java操作mongodb增刪改查的基本操作實(shí)戰(zhàn)指南,需要的朋友可以參考下2023-05-05spring @schedule注解如何動(dòng)態(tài)配置時(shí)間間隔
這篇文章主要介紹了spring @schedule注解如何動(dòng)態(tài)配置時(shí)間間隔,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-11-11SpringBoot使用Druid數(shù)據(jù)源的配置方法
這篇文章主要介紹了SpringBoot使用Druid數(shù)據(jù)源的配置方法,文中代碼實(shí)例相結(jié)合的形式給大家介紹的非常詳細(xì),需要的朋友參考下吧2018-04-04如何實(shí)現(xiàn)nohup?java進(jìn)程號(hào)一直在變方法步驟詳解
這篇文章主要為大家介紹了如何實(shí)現(xiàn)nohup?java進(jìn)程號(hào)一直在變方法步驟詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-11-11Java中Object轉(zhuǎn)換為L(zhǎng)ist類(lèi)型的實(shí)現(xiàn)方法
這篇文章主要介紹了Java中Object轉(zhuǎn)換為L(zhǎng)ist類(lèi)型的實(shí)現(xiàn)方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-03-03Java中checkbox實(shí)現(xiàn)跨頁(yè)多選的方法
最近做了一個(gè)項(xiàng)目其中遇到這樣的需求,要實(shí)現(xiàn)checkbox跨頁(yè)多選功能,經(jīng)過(guò)小編整理,順利解決,今天小編給大家分享Java中checkbox實(shí)現(xiàn)跨頁(yè)多選的方法,需要的的朋友參考下2017-01-01