Android 代理模式(動(dòng)態(tài)代理)及其原理分析

代理模式(動(dòng)態(tài)代理)及其原理分析

概念

有一種設(shè)計(jì)模式叫做代理模式,其中也用到了動(dòng)態(tài)代理今艺。動(dòng)態(tài)代理就是為某一個(gè)對(duì)象提供一個(gè)代理對(duì)象犀勒,已達(dá)到對(duì)這個(gè)對(duì)象的代理訪問(wèn),最典型的例子就是“律師”和“普通民眾”的關(guān)系够滑。

代理模式

我們直接上一個(gè)簡(jiǎn)單的小例子來(lái)闡述這個(gè)模式。
事件:小明要上訴吕世,他找了一個(gè)律師幫他彰触。

這里是上訴的步驟

public interface ILawsuit {
    /**
     * 提交申請(qǐng)
     */
    void submit();
}

接下來(lái)是小明要開(kāi)始上訴,上訴的實(shí)現(xiàn)類(lèi)

public class XiaoMin implements ILawsuit {
    @Override
    public void submit() {
        System.out.println("我要上訴命辖!");
    }
}

接下來(lái)是律師實(shí)現(xiàn)類(lèi)况毅,他也要實(shí)現(xiàn)上訴的步驟

public class Lawyer implements ILawsuit {
    //持有小明的引用
    private ILawsuit mLawsuit;

    public Lawyer(ILawsuit lawsuit) {
        mLawsuit = lawsuit;
    }

    @Override
    public void submit() {
        //除了小明自己的上訴,我還可以加上一些屬于律師的邏輯
        mLawsuit.submit();
    }
}

一個(gè)簡(jiǎn)單的代理模式就實(shí)現(xiàn)了尔艇,這里可以感受出來(lái)代理模式的一些好處了尔许。方便后期邏輯拓展,以及簡(jiǎn)化了客戶(hù)端(使用者)使用這個(gè)對(duì)象(小明)的邏輯终娃。

但是在一個(gè)被代理對(duì)象有大量邏輯或者多個(gè)對(duì)象都需要代理的時(shí)候味廊,我們不可能再去寫(xiě)一個(gè)大量邏輯的代理類(lèi)了,不然也太麻煩了棠耕,因此Java就給我們了一個(gè)快速拿到代理對(duì)象的方法余佛,此時(shí)就沒(méi)有“律師”類(lèi)了,請(qǐng)看下面的一個(gè)實(shí)現(xiàn)代理邏輯的類(lèi):

public class DynamicProxy implements InvocationHandler {
    //代理的對(duì)象的引用
    private Object object;

    public DynamicProxy(Object o) {
        object = o;
    }

    /**
     * 實(shí)現(xiàn)方法的調(diào)用
     * @param proxy 真實(shí)對(duì)象(小明)
     * @param method 原方法的對(duì)象
     * @param args 原方法的參數(shù)
     * @return 原方法的返回結(jié)果
     * @throws Throwable
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //實(shí)現(xiàn)方法的調(diào)用
        //每當(dāng)代理對(duì)象調(diào)用一個(gè)方法的時(shí)候窍荧,最后都觸發(fā)的是這一個(gè)方法
        Object result = method.invoke(object, args);
        return result;
    }
}

在這個(gè)(動(dòng)態(tài)代理)的類(lèi)中衙熔,我們實(shí)現(xiàn)了一個(gè)接口,這個(gè)接口就是 InvocationHandler 搅荞,里面只有一個(gè) invoke() 方法红氯,這個(gè)方法就是被代理對(duì)象真正實(shí)現(xiàn)的地方,例如:小明調(diào)用上訴方法咕痛,真正執(zhí)行的是method.invoke(object, args) 痢甘,這一句即是實(shí)現(xiàn)method方法。這個(gè)類(lèi)的實(shí)現(xiàn)就讓我們可以同時(shí)對(duì)多個(gè)代理邏輯相同的對(duì)象進(jìn)行代理茉贡,而且這個(gè)類(lèi)只將所有方法都集中在了一個(gè)invoke() 方法中塞栅,省去了大量重復(fù)代碼,例如可以在這里添加打印日志的功能等腔丧。

接下來(lái)來(lái)看小明再次怎么被代理的:

//對(duì)真實(shí)對(duì)象的代理的邏輯實(shí)現(xiàn) 
DynamicProxy proxy = new DynamicProxy(xiaoMin);

//定義了由哪個(gè)ClassLoader對(duì)象來(lái)對(duì)生成的代理對(duì)象進(jìn)行加載
ClassLoader loader = xiaoMin.getClass().getClassLoader();

//這才是最終的代理對(duì)象
ILawsuit lawyer = (ILawsuit) Proxy.newProxyInstance(loader, new Class[]    
    {ILawsuit.class},proxy);
lawyer.submit();        

這里我們關(guān)注一下Proxy.newProxyInstance(ClassLoader loader,Class<?>[] interfaces, InvocationHandler h);方法放椰,先說(shuō)三個(gè)參數(shù):

  • loader: 一個(gè)ClassLoader對(duì)象作烟,定義了由哪個(gè)ClassLoader對(duì)象來(lái)對(duì)生成的代理對(duì)象進(jìn)行加載。
  • interfaces: 一個(gè)Interface對(duì)象的數(shù)組砾医,表示的是我將要給我需要代理的對(duì)象提供一組什么接口拿撩,如果我提供了一組接口給它,那么這個(gè)代理對(duì)象就宣稱(chēng)實(shí)現(xiàn)了該接口(多態(tài))如蚜,這樣我就能調(diào)用這組接口中的方法了压恒。
  • h: 一個(gè)InvocationHandler對(duì)象,表示的是當(dāng)我這個(gè)動(dòng)態(tài)代理對(duì)象在調(diào)用方法的時(shí)候错邦,會(huì)關(guān)聯(lián)到哪一個(gè)InvocationHandler對(duì)象上探赫。

細(xì)心的你可能發(fā)現(xiàn)了不對(duì)的地方,我們拿到的lawyer對(duì)象如果只是一個(gè)XiaoMin對(duì)象的話(huà)撬呢,那么在調(diào)用submit()方法的時(shí)候不可能觸發(fā)invoke()方法伦吠,而是直接實(shí)現(xiàn)。那么證實(shí) Proxy.newProxyInstance(ClassLoader loader,Class<?>[] interfaces, InvocationHandler h); 返回的不是XiaoMin對(duì)象魂拦,而是一個(gè)JVM根據(jù)ILawsuit接口讨勤、 xiaoMin對(duì)象、proxy動(dòng)態(tài)代理對(duì)象來(lái)生成的一個(gè)對(duì)象晨另。

然后我去跟著這些方法去源碼里面看一下,先看newProxyInstance()方法谱姓,這個(gè)方法負(fù)責(zé)的就是生成代理類(lèi)的對(duì)象:

@CallerSensitive
public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)
    throws IllegalArgumentException
{
    //要求代理邏輯對(duì)象非空
    Objects.requireNonNull(h);

    //根據(jù)傳入的類(lèi)構(gòu)造器和接口對(duì)象借尿,查找或者生成指定的代理類(lèi)
    Class<?> cl = getProxyClass0(loader, intfs);

    //調(diào)用構(gòu)造函數(shù)
    try {
        //拿到含有InvocationHandler類(lèi)型參數(shù)的構(gòu)造方法
        //目的是最后的類(lèi)對(duì)象是跟我們的代理邏輯的對(duì)象相關(guān)聯(lián)
        final Constructor<?> cons = cl.getConstructor(constructorParams);
        final InvocationHandler ih = h;
        
        //生成的類(lèi)的修飾符不是公開(kāi)的話(huà)
        if (!Modifier.isPublic(cl.getModifiers())) {
            //這里其實(shí)是拿到報(bào)異常的
            cons.setAccessible(true);
        }
        //通過(guò)反射拿到生成類(lèi)的實(shí)例
        return cons.newInstance(new Object[]{h});
    }
}

其中的constructorParams是來(lái)自private static final Class<?>[] constructorParams ={ InvocationHandler.class }; 這一句話(huà),也就是實(shí)現(xiàn)我們的代理邏輯的那個(gè)接口的一個(gè)數(shù)組對(duì)象屉来,其實(shí)這里我們根據(jù)最后的返回值return cons.newInstance(new Object[]{h})就應(yīng)該了解到編譯器為我們生成的類(lèi)中的構(gòu)造函數(shù)有一個(gè)是傳入我們的代理邏輯對(duì)象(InvocationHandler對(duì)象)的構(gòu)造函數(shù)路翻,因此實(shí)現(xiàn)了代理邏輯和生成類(lèi)的關(guān)聯(lián),那么此時(shí)我們的生成類(lèi)就包含了我們的被代理類(lèi)(小明)的邏輯和我們(對(duì)小明)的代理邏輯茄靠。

接下來(lái)我們?cè)冱c(diǎn)進(jìn)去這個(gè)方法中的一個(gè)重要操作getProxyClass0(loader, intfs)茂契,經(jīng)過(guò)兩步操作,我們最終是來(lái)到了WeakCache(弱緩存)的public V get(K key, P parameter){}方法:

/**
 *V:        最后的代理類(lèi)泛型對(duì)象
 *key:       classLoader(小明類(lèi)對(duì)應(yīng)的類(lèi)加載器)
 *parameter: 接口類(lèi)(小明的申訴步驟接口)的數(shù)組對(duì)象
 */
public V get(K key, P parameter) {
    Objects.requireNonNull(parameter);

    expungeStaleEntries();

    //根據(jù)類(lèi)加載器拿到一個(gè)從緩存讀取數(shù)據(jù)的key
    Object cacheKey = CacheKey.valueOf(key, refQueue);

    // 從對(duì)應(yīng)的類(lèi)加載器中拿到的并行集合慨绳,存放的值是Supplier(接口“提供者”)
    // map一開(kāi)始是空的掉冶,map也是從這個(gè)方法里進(jìn)行填充的
    ConcurrentMap<Object, Supplier<V>> valuesMap = map.get(cacheKey);
    if (valuesMap == null) {
        // 如果沒(méi)有這個(gè)并行集合,則new 一個(gè)并行集合并放入這個(gè)map脐雪。
        ConcurrentMap<Object, Supplier<V>> oldValuesMap
            = map.putIfAbsent(cacheKey,
                              valuesMap = new ConcurrentHashMap<>());
        if (oldValuesMap != null) {
            valuesMap = oldValuesMap;
        }
    }

    // 創(chuàng)建子鍵厌小,并從valueMap 中檢索可能存在的對(duì)應(yīng)子鍵的Supplier(提供者)
    Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
    Supplier<V> supplier = valuesMap.get(subKey);
    //工廠(Supplier的實(shí)現(xiàn)類(lèi))
    Factory factory = null;

    while (true) {
        // 提供者不為空的話(huà)直接拿到我們需要的代理類(lèi)的Class對(duì)象
        // 返回一個(gè)值,結(jié)束該方法
        if (supplier != null) {
            V value = supplier.get();
            if (value != null) {
                return value;
            }
        }
        
        // 實(shí)例出一個(gè)工廠對(duì)象(判斷代理類(lèi)就是在Factory中生成的)
        if (factory == null) {
            factory = new Factory(key, parameter, subKey, valuesMap);
        }

        //當(dāng)提供者為空的時(shí)候
        if (supplier == null) {
            //如果并行集合中沒(méi)得對(duì)應(yīng)的提供者战秋,則放入剛創(chuàng)建的factory(提供者)
            supplier = valuesMap.putIfAbsent(subKey, factory);
            if (supplier == null) {
                supplier = factory;
            }
        } else {
            // 不為空的話(huà)替換并行集合中對(duì)應(yīng)的元素
            if (valuesMap.replace(subKey, supplier, factory)) {
                // 直接拿到提供者
                supplier = factory;
            } else {
                // 根據(jù)子鍵拿出對(duì)應(yīng)的提供者
                supplier = valuesMap.get(subKey);
            }
        }
    }
}

看到這個(gè)方法是不是腦袋都大了璧亚,沒(méi)錯(cuò),其實(shí)我的腦袋也大了脂信,很多東西是懵懵懂懂的癣蟋。但是我們依舊可以梳理一遍這個(gè)方法的大體邏輯

我們?yōu)榱四玫轿覀兿胍拇眍?lèi)透硝,我們是從弱緩存中去找,先根據(jù)我們的類(lèi)加載器從一個(gè)map中去找疯搅,找的目標(biāo)是也是一個(gè)集合濒生,這是一個(gè)放了可以拿到我們想要的代理類(lèi)的集合————一個(gè)并行集合。但是一般的話(huà)這個(gè)map都是空的秉撇,因?yàn)樗侵苯觧ew 出來(lái)的(這個(gè)類(lèi)的頂部有)甜攀,里面的元素也是在這個(gè)方法中被放進(jìn)去的,那么也就是說(shuō)我們找到的并行集合也可能是個(gè)空的琐馆,對(duì)吧规阀?所以的話(huà)我們也是直接new 一個(gè)并行集合進(jìn)去的。那我們new 出來(lái)的并行集合也是空的啊瘦麸,沒(méi)關(guān)系谁撼,因?yàn)槲覀兘酉聛?lái)往里面添加?xùn)|西就對(duì)了。重點(diǎn)來(lái)了滋饲,我們的Factory類(lèi)厉碟,它本身也是一個(gè)Supplier(接口) 的實(shí)現(xiàn)類(lèi),在實(shí)例化的過(guò)程屠缭,我們根據(jù)Factory構(gòu)造器傳入值箍鼓,生成對(duì)應(yīng)的代理類(lèi),并且factory對(duì)象自身會(huì)被放入緩存集合呵曹,以便下次直接從它拿到目標(biāo)代理類(lèi)款咖。也就是說(shuō)我們可以通過(guò)Factory直接生產(chǎn)出我們想要的代理類(lèi)的,而這個(gè)方法中的其它邏輯則是為了讓我們能夠?qū)崿F(xiàn)保存奄喂,在下一次便可以直接調(diào)用了铐殃,以達(dá)到節(jié)省資源的目的。

最后的最后跨新,我們?cè)偃?strong>Factory中去看看吧富腊,驗(yàn)證我們的猜想是否正確,我們?nèi)フ椅覀兿胍拇a域帐,

在這里我們保留了關(guān)鍵的代碼:

private final class Factory implements Supplier<V> {

    Factory(K key, P parameter, Object subKey,
            ConcurrentMap<Object, Supplier<V>> valuesMap) {
        this.key = key;
        this.parameter = parameter;
        this.subKey = subKey;
        this.valuesMap = valuesMap;
    }

    @Override
    public synchronized V get() { 
        // re-check
        Supplier<V> supplier = valuesMap.get(subKey);
        if (supplier != this) {
            // 簡(jiǎn)單理解赘被,防止意外發(fā)生,返回Null讓其一直循環(huán)
            return null;
        }
      
        // 激動(dòng)的時(shí)候肖揣,這就是我們的目標(biāo)代理類(lèi)
        V value = null;
        try {
            // 再深入就又要扯好遠(yuǎn)帘腹,這里又是另外的工廠類(lèi)了,反正就是生產(chǎn)valueP矶觥Q粲!
            value = Objects.requireNonNull(valueFactory.apply(key, parameter));
        } 
        //哈哈哈,拿到了G蚧;嗤怼!
        return value;
    }
}

這便是我們生產(chǎn)我們的目標(biāo)代理類(lèi)的全部過(guò)程啦筒愚,我們應(yīng)該注意的是最后跟隨我們到底的一直有我們的“申訴步驟”的接口赴蝇,以確保我們拿到的是這個(gè)接口的對(duì)象,然后我們就可以執(zhí)行里面的方法了巢掺。

我還在這里制作了一張簡(jiǎn)單的流程圖

proxy.png

由于筆者水平有限句伶,我在找了大篇的博客后也沒(méi)能找出JVM為我們生成的代理類(lèi),所以我們也只能估摸著這個(gè)代理類(lèi)的作用了陆淀,就是在調(diào)用被代理對(duì)象方法的時(shí)候考余,記錄該目標(biāo)方法,并直到調(diào)用invoke()方法中去轧苫,在invoke()方法中我們自行實(shí)現(xiàn)目標(biāo)方法的調(diào)用楚堤。

補(bǔ)充 —— AOP

翻譯過(guò)來(lái)叫做“面向切面的編程”,簡(jiǎn)單說(shuō)含懊,就是找到一個(gè)模塊的切入點(diǎn)身冬,對(duì)它進(jìn)行切面操作。

比如打Log這一操作吧岔乔,我們好多個(gè)對(duì)象酥筝、好多個(gè)方法都需要打上Log,那我們?cè)诿恳粋€(gè)方法里面都打上自己的Log類(lèi)的Log吧雏门。首先嘿歌,打這么多的Log不累嗎?而且這么多Log肯定少不了大量重復(fù)代碼剿配。所以我們面對(duì)打Log這一功能進(jìn)行處理,就用動(dòng)態(tài)代理的形式來(lái)做吧阅束,我給每一個(gè)對(duì)象一個(gè)代理呼胚,讓它執(zhí)行方法的時(shí)候都在這個(gè)代理對(duì)象中去執(zhí)行,那么是不是就是可以在代理對(duì)象中去實(shí)現(xiàn)打Log 的功能了息裸,這樣就將Log和方法分開(kāi)來(lái)了蝇更,簡(jiǎn)化了代碼,增強(qiáng)了后期拓展性呼盆,而且代碼變整潔了年扩,有木有? 访圃。

你可能會(huì)問(wèn)了厨幻,我給每一個(gè)對(duì)象都搞一個(gè)代理是不是更麻煩喲?那么,我的第二個(gè)目的就是要簡(jiǎn)化這一實(shí)現(xiàn)過(guò)程了况脆,是不是饭宾?例如Retrofit 第三方庫(kù)就有采用一種方法————利用Apt(編譯時(shí)掃描和處理注解),使用的時(shí)候在需要代理的對(duì)象上面加上簡(jiǎn)單的注解就實(shí)現(xiàn)了這一功能格了,在這里就不詳細(xì)解釋如何實(shí)現(xiàn)的了看铆。

筆者水平有限,有寫(xiě)得不好的地方盛末,請(qǐng)大膽指出~
請(qǐng)支持原創(chuàng)哦~
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末弹惦,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子悄但,更是在濱河造成了極大的恐慌棠隐,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,682評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件算墨,死亡現(xiàn)場(chǎng)離奇詭異宵荒,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)净嘀,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,277評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)报咳,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人挖藏,你說(shuō)我怎么就攤上這事暑刃。” “怎么了膜眠?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,083評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵岩臣,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我宵膨,道長(zhǎng)架谎,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,763評(píng)論 1 295
  • 正文 為了忘掉前任辟躏,我火速辦了婚禮谷扣,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘捎琐。我一直安慰自己会涎,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,785評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布瑞凑。 她就那樣靜靜地躺著末秃,像睡著了一般。 火紅的嫁衣襯著肌膚如雪籽御。 梳的紋絲不亂的頭發(fā)上练慕,一...
    開(kāi)封第一講書(shū)人閱讀 51,624評(píng)論 1 305
  • 那天惰匙,我揣著相機(jī)與錄音,去河邊找鬼贺待。 笑死徽曲,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的麸塞。 我是一名探鬼主播秃臣,決...
    沈念sama閱讀 40,358評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼哪工!你這毒婦竟也來(lái)了奥此?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,261評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤雁比,失蹤者是張志新(化名)和其女友劉穎稚虎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體偎捎,經(jīng)...
    沈念sama閱讀 45,722評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡蠢终,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了茴她。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片寻拂。...
    茶點(diǎn)故事閱讀 40,030評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖丈牢,靈堂內(nèi)的尸體忽然破棺而出祭钉,到底是詐尸還是另有隱情,我是刑警寧澤己沛,帶...
    沈念sama閱讀 35,737評(píng)論 5 346
  • 正文 年R本政府宣布慌核,位于F島的核電站,受9級(jí)特大地震影響申尼,放射性物質(zhì)發(fā)生泄漏垮卓。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,360評(píng)論 3 330
  • 文/蒙蒙 一师幕、第九天 我趴在偏房一處隱蔽的房頂上張望粟按。 院中可真熱鬧,春花似錦们衙、人聲如沸钾怔。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,941評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至愚臀,卻和暖如春忆蚀,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,057評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工馋袜, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留男旗,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,237評(píng)論 3 371
  • 正文 我出身青樓欣鳖,卻偏偏與公主長(zhǎng)得像察皇,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子泽台,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,976評(píng)論 2 355

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

  • Java代理和動(dòng)態(tài)代理機(jī)制分析和應(yīng)用 概述 代理是一種常用的設(shè)計(jì)模式什荣,其目的就是為其他對(duì)象提供一個(gè)代理以控制對(duì)某個(gè)...
    丸_子閱讀 3,024評(píng)論 6 57
  • 設(shè)計(jì)模式概述 在學(xué)習(xí)面向?qū)ο笃叽笤O(shè)計(jì)原則時(shí)需要注意以下幾點(diǎn):a) 高內(nèi)聚、低耦合和單一職能的“沖突”實(shí)際上怀酷,這兩者...
    彥幀閱讀 3,747評(píng)論 0 14
  • 目錄:1.代理模式定義&實(shí)現(xiàn)2.裝飾模式定義&實(shí)現(xiàn)3.靜態(tài)代理4.動(dòng)態(tài)代理:JDK動(dòng)態(tài)代理稻爬、Cglib動(dòng)態(tài)代理5....
    lbcBoy閱讀 1,599評(píng)論 2 3
  • 18:44 總算 找到了綠 很干凈穩(wěn)重的顏色 像一個(gè)面容沉靜的 小獸似的少年 洋溢著青春活力 往上拔節(jié)生長(zhǎng)...
    陸沉__閱讀 138評(píng)論 0 0
  • 2018年8月7日下午中國(guó)抗衰老促進(jìn)會(huì)副秘書(shū)長(zhǎng)肖連敏,原衛(wèi)生部副部長(zhǎng)孫隆椿蜕依,原大連市政協(xié)主席桅锄、慈善總會(huì)會(huì)長(zhǎng)...
    水月禪心_0c6d閱讀 1,427評(píng)論 0 0