代理模式

前言

代理模式是常用的java設(shè)計(jì)模式,他的特征是代理類與委托類有同樣的接口,代理類主要負(fù)責(zé)為委托類預(yù)處理消息千劈、過濾消息、把消息轉(zhuǎn)發(fā)給委托類宝泵,以及事后處理消息等。代理類與委托類之間通常會存在關(guān)聯(lián)關(guān)系忍些,一個(gè)代理類的對象與一個(gè)委托類的對象關(guān)聯(lián)鲁猩,代理類的對象本身并不真正實(shí)現(xiàn)服務(wù),而是通過調(diào)用委托類的對象的相關(guān)方法罢坝,來提供特定的服務(wù)

1、靜態(tài)代理

靜態(tài)代理通常用于對原有業(yè)務(wù)邏輯的擴(kuò)充搅窿。比如持有二方包的某個(gè)類嘁酿,并調(diào)用了其中的某些方法。然后出于某種原因男应,比如記錄日志闹司、打印方法執(zhí)行時(shí)間,但是又不好將這些邏輯寫入二方包的方法里沐飘。所以可以創(chuàng)建一個(gè)代理類實(shí)現(xiàn)和二方方法相同的方法游桩,通過讓代理類持有真實(shí)對象,然后在原代碼中調(diào)用代理類方法耐朴,來達(dá)到添加我們需要業(yè)務(wù)邏輯的目的借卧。

這其實(shí)也就是代理模式的一種實(shí)現(xiàn),通過對真實(shí)對象的封裝筛峭,來實(shí)現(xiàn)擴(kuò)展性铐刘。

一個(gè)典型的代理模式通常有三個(gè)角色,這里稱之為代理三要素

首先定義接口

public interface Action {
public void doSomething();
}

真實(shí)對象

public class RealObject implements Action{
public void doSomething() {
    System.out.println("do something");
}
}

代理對象

public class Proxy implements Action {
private Action realObject;

public Proxy(Action realObject) {
    this.realObject = realObject;
}
public void doSomething() {
    System.out.println("proxy do");
    realObject.doSomething();
}
}

運(yùn)行代碼

  Proxy proxy = new Proxy(new RealObject());
  proxy.doSomething();

這種代理模式也最為簡單影晓,就是通過proxy持有realObject的引用镰吵,并進(jìn)行一層封裝。

靜態(tài)代理的優(yōu)點(diǎn)和缺點(diǎn)

先看看代理模式的優(yōu)點(diǎn): 擴(kuò)展原功能挂签,不侵入原代碼疤祭。

再看看這種代理模式的缺點(diǎn):

假如有這樣一個(gè)需求,有十個(gè)不同的RealObject饵婆,同時(shí)我們要去代理的方法是不同的勺馆,比要代理方法:doSomething、doAnotherThing、doTwoAnotherThing谓传,添加代理前蜈项,原代碼可能是這樣的:

 realObject.doSomething();
 realObject1.doAnotherThing();
 realObject2.doTwoAnother();

2、Java動態(tài)代理

在靜態(tài)代理中可以看到Proxy這個(gè)類做的工作無非就是在RealSubject的工作之前或之后插入其他的業(yè)務(wù)代碼续挟,如果每次都手動去實(shí)現(xiàn)Proxy類會比較繁瑣紧卒,Java中引入了第三個(gè)類InvocationHandler,用來統(tǒng)一映射Proxy方法調(diào)用到RealSubject上诗祸。通過newProxyInstance可以幫助我們動態(tài)生成Proxy類實(shí)例跑芳。

接著看一下核心類和方法

public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler invocationHandler)

返回一個(gè)指定接口的代理類實(shí)例,該接口可以將方法調(diào)用指派到指定的調(diào)用處理程序InvocationHandler

public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable

對于InvocationHandler直颅,我們需要實(shí)現(xiàn)invoke方法博个,invoke方法根據(jù)代理類傳遞給自己的method參數(shù)來區(qū)分是什么方法

還是以上面栗子來做示范,F(xiàn)ly接口和Run接口不變功偿,需要添加InvocationHandler的實(shí)現(xiàn):

public class ProxyHandler implements InvocationHandler{

private RealObject mRealObject;

public ProxyHandler(RealObject realobject){
    mRealObject = realobject;
}


public Object invoke(Object proxy, Method method, Object[] args)
        throws Throwable {
    System.out.println("invoke" + method.getName());
    return method.invoke(mRealObject, args);
}

}

生成代理對象

public static void main(String[] args) {

    RealObject realobject = new RealObject();
    ClassLoader classLoader = realobject.getClass().getClassLoader();
    
    Class[] interfaces = realobject.getClass().getInterfaces();
    
    ProxyHandler proxyHandler = new ProxyHandler(realobject);
    
    ProxyUtils.generateClassFile(realobject.getClass(), "AnimalProxy");
    
    Object newProxyInstance = Proxy.newProxyInstance(classLoader, interfaces, proxyHandler);
    Action action = (Action)newProxyInstance;
    action.doSomething;
}

可以看出來核心代碼就是
Proxy.newProxyInstance(classLoader, interfaces, proxyHandler);
我們分別來講解下這三個(gè)參數(shù)分別是什么作用

  • classLoader:類加載器盆佣,我們手動寫的都是java文件,需要編譯成class文件械荷,這個(gè)是遵循JVM規(guī)范的二進(jìn)制文件共耍,然后通過classLoader將class文件加載進(jìn)內(nèi)存,生成我們需要的class對象吨瞎,這個(gè)class對象通過反射就可以拿到類的所有信息痹兜。在這邊的作用其實(shí)就是將Java動態(tài)生成的class文件進(jìn)行加載得到動態(tài)代理的class對象,以便后面其他操作颤诀。

  • interfaces:這個(gè)就是接口字旭,可以看出無論代理或者RealSubject都是實(shí)現(xiàn)同樣的接口,Java替我們動態(tài)生成的class文件中的方法其實(shí)就是接口中的方法崖叫。這個(gè)其實(shí)也是Java動態(tài)代理的缺點(diǎn)遗淳,即使RealSubject中聲明的方法,但是接口中沒有聲明該方法归露,那么在生成的代理中就沒有洲脂,也就是動態(tài)生成的代理類中只有接口中的方法,這個(gè)后面看栗子就清楚了剧包。

  • proxyHandler:就是InvocationHandler的實(shí)現(xiàn)類恐锦,集成管理Proxy方法的調(diào)用映射到RealSubject中,主要就是在invoke中方法實(shí)現(xiàn)疆液。在我們這個(gè)例子就是實(shí)現(xiàn)將Proxy方法調(diào)用映射到RealObject對應(yīng)的方法上一铅。

總結(jié)

動態(tài)代理和靜態(tài)代理最大的不同就是Java SDK替我們動態(tài)生成了代理類代碼,代理方法的調(diào)用最后都通過InvocationHandler映射到具體的實(shí)現(xiàn)類中堕油。動態(tài)代理在Android中應(yīng)用也是很多的潘飘,在下一篇里面會介紹一下 Android 反射注解和動態(tài)代理的綜合使用


點(diǎn)贊加關(guān)注是給我最大的鼓勵(lì)!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末肮之,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子卜录,更是在濱河造成了極大的恐慌戈擒,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,946評論 6 518
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件艰毒,死亡現(xiàn)場離奇詭異筐高,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)丑瞧,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,336評論 3 399
  • 文/潘曉璐 我一進(jìn)店門柑土,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人绊汹,你說我怎么就攤上這事稽屏。” “怎么了西乖?”我有些...
    開封第一講書人閱讀 169,716評論 0 364
  • 文/不壞的土叔 我叫張陵狐榔,是天一觀的道長。 經(jīng)常有香客問我获雕,道長荒叼,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 60,222評論 1 300
  • 正文 為了忘掉前任典鸡,我火速辦了婚禮,結(jié)果婚禮上坏晦,老公的妹妹穿的比我還像新娘萝玷。我一直安慰自己,他們只是感情好昆婿,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,223評論 6 398
  • 文/花漫 我一把揭開白布球碉。 她就那樣靜靜地躺著,像睡著了一般仓蛆。 火紅的嫁衣襯著肌膚如雪睁冬。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,807評論 1 314
  • 那天看疙,我揣著相機(jī)與錄音豆拨,去河邊找鬼。 笑死能庆,一個(gè)胖子當(dāng)著我的面吹牛施禾,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播搁胆,決...
    沈念sama閱讀 41,235評論 3 424
  • 文/蒼蘭香墨 我猛地睜開眼弥搞,長吁一口氣:“原來是場噩夢啊……” “哼邮绿!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起攀例,我...
    開封第一講書人閱讀 40,189評論 0 277
  • 序言:老撾萬榮一對情侶失蹤船逮,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后粤铭,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體挖胃,經(jīng)...
    沈念sama閱讀 46,712評論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,775評論 3 343
  • 正文 我和宋清朗相戀三年承耿,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了冠骄。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,926評論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡加袋,死狀恐怖凛辣,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情职烧,我是刑警寧澤扁誓,帶...
    沈念sama閱讀 36,580評論 5 351
  • 正文 年R本政府宣布,位于F島的核電站蚀之,受9級特大地震影響蝗敢,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜足删,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,259評論 3 336
  • 文/蒙蒙 一寿谴、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧失受,春花似錦讶泰、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,750評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至兄旬,卻和暖如春狼犯,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背领铐。 一陣腳步聲響...
    開封第一講書人閱讀 33,867評論 1 274
  • 我被黑心中介騙來泰國打工悯森, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人罐孝。 一個(gè)月前我還...
    沈念sama閱讀 49,368評論 3 379
  • 正文 我出身青樓呐馆,卻偏偏與公主長得像,于是被迫代替她去往敵國和親莲兢。 傳聞我的和親對象是個(gè)殘疾皇子汹来,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,930評論 2 361

推薦閱讀更多精彩內(nèi)容