設(shè)計(jì)模式之代理模式

Proxy屬于代理型設(shè)計(jì)模式

定義:

為其它對象提供一種代理以控制對這個(gè)對象的訪問控制啸澡;在某些情況下拐邪,客戶不想或者不能直接引用另一個(gè)對象慰毅,這時(shí)候代理對象可以在客戶端和目標(biāo)對象之間起到中介的作用。

作用:

1.實(shí)現(xiàn)無侵入式的代碼擴(kuò)展

2.解耦,交給代理處理

缺點(diǎn):

java系統(tǒng)中的動(dòng)態(tài)代理只能代理接口

應(yīng)用場景:

如Retrofit中請求服務(wù)的接口, 面向切面編程的Aop

Proxy.class

1.創(chuàng)建實(shí)現(xiàn)interfaces接口的對象

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

loader: - 一個(gè)ClassLoader對象扎阶,定義了由哪個(gè)ClassLoader對象來對生成的代理對象進(jìn)行加載
interfaces: -一個(gè)Interface對象的數(shù)組汹胃,表示的是我將要給我需要代理的對象提供一組什么接口,如果我提供了一組接口給它东臀,那么這個(gè)代理對象就宣稱實(shí)現(xiàn)了該接口(多態(tài))着饥,這樣我就能調(diào)用這組接口中的方法了
h: -一個(gè)InvocationHandler對象,表示的是當(dāng)我這個(gè)動(dòng)態(tài)代理對象在調(diào)用方法的時(shí)候惰赋,會關(guān)聯(lián)到哪一個(gè)InvocationHandler對象上

2.生成關(guān)于intfs接口實(shí)現(xiàn)的class對象

Class<?> cl = getProxyClass0(loader, intfs);

通過ProxyClassFactory創(chuàng)建此class對象
步驟一.生成接口實(shí)現(xiàn)類的字節(jié)數(shù)組

byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
 proxyName, interfaces, accessFlags);

步驟二.生成實(shí)現(xiàn)類的class對象

private static native Class<?> defineClass0(ClassLoader loader, String name,byte[] b, int off, int len)

3.生成實(shí)現(xiàn)類對象

Constructor<?> cons = cl.getConstructor(constructorParams);
///////////////省略其他代碼///////////////
return cons.newInstance(new Object[]{h});

由此可知: 實(shí)現(xiàn)類對象是通過Proxy構(gòu)造后, 生成字節(jié)數(shù)組; 再調(diào)用底層代碼將字節(jié)數(shù)組轉(zhuǎn)換成class對象; 最后class對象通過 構(gòu)造器創(chuàng)建對象的方式宰掉,創(chuàng)建了實(shí)現(xiàn)類對象
InvocationHandler.class

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

proxy: - 指代我們所代理的那個(gè)真實(shí)對象
method: - 指代的是我們所要調(diào)用真實(shí)對象的某個(gè)方法的Method對象
args: - 指代的是調(diào)用真實(shí)對象某個(gè)方法時(shí)接受的參數(shù)
根據(jù)3 生成實(shí)現(xiàn)類對象,InvocationHandler作為了實(shí)現(xiàn)類的構(gòu)造參數(shù), 因此
InvocationHandlerinvoke顯然和實(shí)現(xiàn)類對象的方法調(diào)用有關(guān), 到底是什么關(guān)系?
最好看看實(shí)現(xiàn)類長什么樣, 前面有提到 生成的字節(jié)數(shù)組, 因此可以將該字節(jié)數(shù)組生成一個(gè)類,展示出來
1.Subject是一個(gè)接口

public interface Subject {
 /**
 * 寫入字符串
 * @param string
 */
 void writeString(String string);
 /**
 * 讀取字符串
 * @return
 */
 String readString();
}

2.生成實(shí)現(xiàn)類方法

byte[] bytes = ProxyGenerator.generateProxyClass(
 "InterfaceImpl", new Class[]{Subject.class}, Modifier.FINAL | Modifier.PUBLIC);
FilesKt.writeBytes(new File("InterfaceImpl.class"), bytes);

3.實(shí)現(xiàn)類

public final class InterfaceImpl extends Proxy implements Subject, Material {
    /**
    * m0,m1.. 為當(dāng)前的方法對象
    */
    private static Method m1;
    private static Method m3;
    private static Method m2;
    private static Method m4;
    private static Method m5;
    private static Method m0;

    public InterfaceImpl(InvocationHandler var1) throws  {
        super(var1);
    }

    public final boolean equals(Object var1) throws  {
        try {
            /**
            * 間接調(diào)用InvocationHandler對象中的invoke方法
            */
            return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

    public final String readString() throws  {
        try {
            return (String)super.h.invoke(this, m3, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final String toString() throws  {
        try {
            return (String)super.h.invoke(this, m2, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final void writeString(String var1) throws  {
        try {
            super.h.invoke(this, m4, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

    public final String getColor() throws  {
        try {
            return (String)super.h.invoke(this, m5, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final int hashCode() throws  {
        try {
            return (Integer)super.h.invoke(this, m0, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    static {
        try {
            m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
            m3 = Class.forName("chapter_pattern.agent.dynamic.Subject").getMethod("readString");
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            m4 = Class.forName("chapter_pattern.agent.dynamic.Subject").getMethod("writeString", Class.forName("java.lang.String"));
            m5 = Class.forName("chapter_pattern.agent.dynamic.Material").getMethod("getColor");
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}

顯然在調(diào)用實(shí)現(xiàn)類方法的時(shí)候,實(shí)際會通過InvocationHandler對象調(diào)用其重寫的invoke方法轨奄,通常我們會在重寫的invoke方法中去調(diào)用接口的實(shí)現(xiàn)類對象(注意:這個(gè)實(shí)現(xiàn)類對象不是我們通過字節(jié)碼生成的實(shí)現(xiàn)類對象, 而是業(yè)務(wù)中實(shí)現(xiàn)接口的類對象)
動(dòng)態(tài)代理簡單模型

未命名文件(2).png

代碼鏈接:https://github.com/A18767101271/java-/tree/master/src/chapter_pattern/agent/dynamic

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末孟害,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子挪拟,更是在濱河造成了極大的恐慌挨务,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,123評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件玉组,死亡現(xiàn)場離奇詭異耘子,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)球切,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,031評論 2 384
  • 文/潘曉璐 我一進(jìn)店門谷誓,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人吨凑,你說我怎么就攤上這事捍歪。” “怎么了鸵钝?”我有些...
    開封第一講書人閱讀 156,723評論 0 345
  • 文/不壞的土叔 我叫張陵糙臼,是天一觀的道長。 經(jīng)常有香客問我恩商,道長变逃,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,357評論 1 283
  • 正文 為了忘掉前任怠堪,我火速辦了婚禮揽乱,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘粟矿。我一直安慰自己凰棉,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,412評論 5 384
  • 文/花漫 我一把揭開白布陌粹。 她就那樣靜靜地躺著撒犀,像睡著了一般。 火紅的嫁衣襯著肌膚如雪掏秩。 梳的紋絲不亂的頭發(fā)上或舞,一...
    開封第一講書人閱讀 49,760評論 1 289
  • 那天,我揣著相機(jī)與錄音蒙幻,去河邊找鬼映凳。 笑死,一個(gè)胖子當(dāng)著我的面吹牛杆煞,可吹牛的內(nèi)容都是我干的魏宽。 我是一名探鬼主播,決...
    沈念sama閱讀 38,904評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼决乎,長吁一口氣:“原來是場噩夢啊……” “哼队询!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起构诚,我...
    開封第一講書人閱讀 37,672評論 0 266
  • 序言:老撾萬榮一對情侶失蹤蚌斩,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后范嘱,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體送膳,經(jīng)...
    沈念sama閱讀 44,118評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,456評論 2 325
  • 正文 我和宋清朗相戀三年丑蛤,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了叠聋。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,599評論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡受裹,死狀恐怖碌补,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情棉饶,我是刑警寧澤厦章,帶...
    沈念sama閱讀 34,264評論 4 328
  • 正文 年R本政府宣布,位于F島的核電站照藻,受9級特大地震影響袜啃,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜幸缕,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,857評論 3 312
  • 文/蒙蒙 一群发、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧发乔,春花似錦也物、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,731評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至抵栈,卻和暖如春告材,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背古劲。 一陣腳步聲響...
    開封第一講書人閱讀 31,956評論 1 264
  • 我被黑心中介騙來泰國打工斥赋, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人产艾。 一個(gè)月前我還...
    沈念sama閱讀 46,286評論 2 360
  • 正文 我出身青樓疤剑,卻偏偏與公主長得像滑绒,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子隘膘,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,465評論 2 348

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