Java核心 -- 動(dòng)態(tài)代理

  1. 動(dòng)態(tài)類(lèi)型和靜態(tài)類(lèi)型:語(yǔ)言類(lèi)型是 運(yùn)行時(shí) 檢查,還是 編譯期 檢查
  2. 強(qiáng)類(lèi)型和弱類(lèi)型:為 不同類(lèi)型 的變量賦值時(shí),是否需要進(jìn)行 顯式的類(lèi)型轉(zhuǎn)換
  3. Java是 靜態(tài)的強(qiáng)類(lèi)型語(yǔ)言 ,但提供了類(lèi)似 反射 等機(jī)制,因此也具備了 部分 動(dòng)態(tài)類(lèi)型語(yǔ)言的能力

反射

  1. 反射機(jī)制是Java語(yǔ)言提供的一種基礎(chǔ)功能磺陡,賦予程序 在運(yùn)行時(shí)自省 的能力
  2. 通過(guò)反射可以 直接操作類(lèi)或者對(duì)象
    • 獲取某個(gè)對(duì)象的類(lèi)定義
    • 獲取類(lèi)聲明的屬性和方法
    • 調(diào)用方法或者構(gòu)造函數(shù)
    • 運(yùn)行時(shí)修改類(lèi)定義

setAccessible

  1. AccessibleObject.setAccessible(boolean flag):可以在 運(yùn)行時(shí) 修改成員的 訪問(wèn)限制
  2. setAccessible的應(yīng)用遍布在日常開(kāi)發(fā)、測(cè)試漠畜、依賴注入等框架中
  • 在O/R Mapping框架中币他,為一個(gè)Java實(shí)體對(duì)象,運(yùn)行時(shí)自動(dòng)生成getter/setter方法
  • 繞過(guò)API的訪問(wèn)控制憔狞,來(lái)調(diào)用內(nèi)部API

動(dòng)態(tài)代理

  1. 動(dòng)態(tài)代理是一種方便 運(yùn)行時(shí)動(dòng)態(tài)構(gòu)建代理蝴悉、動(dòng)態(tài)處理代理方法調(diào)用 的機(jī)制
  2. 很多場(chǎng)景都是利用類(lèi)似的機(jī)制來(lái)實(shí)現(xiàn)的,例如用來(lái) 包裝RPC調(diào)用 和 AOP
  3. 實(shí)現(xiàn)動(dòng)態(tài)代理的方式
    • JDK自身提供的動(dòng)態(tài)代理躯喇,主要利用 反射 機(jī)制
    • 字節(jié)碼操作機(jī)制 辫封,類(lèi)似ASM、cglib(基于ASM)和Javassist

解決的問(wèn)題

  1. 動(dòng)態(tài)代理是一種 代理 機(jī)制廉丽,代理可以看作對(duì)調(diào)用目標(biāo)的 包裝 ,對(duì)目標(biāo)代碼的調(diào)用是通過(guò)代理完成的
  2. 通過(guò)代理可以讓 調(diào)用者和實(shí)現(xiàn)者解耦 妻味,例如RPC調(diào)用正压,框架內(nèi)部的尋址、序列化责球、反序列化等焦履,對(duì)調(diào)用者沒(méi)什么意義

發(fā)展歷程

  1. 靜態(tài)代理 -> 動(dòng)態(tài)代理
  2. 靜態(tài)代理:需要引入 額外的工作 拓劝,而這些工作與實(shí)際的業(yè)務(wù)邏輯沒(méi)有關(guān)系
  • 古董技術(shù)RMI,需要rmic之類(lèi)的工具生成靜態(tài)stub等文件嘉裤,增加了很多繁瑣的準(zhǔn)備工作
  1. 動(dòng)態(tài)代理:相應(yīng)的stub等類(lèi)郑临,可以在運(yùn)行時(shí)生成,對(duì)應(yīng)的調(diào)用操作也是動(dòng)態(tài)生成的屑宠,極大地提高生產(chǎn)力

JDK Proxy + cglib

public class MyDynamicProxy {
    public static void main(String[] args) {
        Hello hello = new HelloImpl();
        MyInvocationHandler handler = new MyInvocationHandler(hello);
        // 構(gòu)造代理實(shí)例
        Hello proxyHello = (Hello) Proxy.newProxyInstance(Hello.class.getClassLoader(), hello.getClass().getInterfaces(), handler);
        // 調(diào)用代理方法
        proxyHello.sayHello();

        // 輸出
        //  MyInvocationHandler Invoking HelloImpl#sayHello
        //  HelloImpl : Hello World
    }
}

interface Hello {
    void sayHello();
}

class HelloImpl implements Hello {
    @Override
    public void sayHello() {
        System.out.println(getClass().getSimpleName() + " : Hello World");
    }
}

@AllArgsConstructor
class MyInvocationHandler implements InvocationHandler {
    private Object target;

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println(getClass().getSimpleName() + " Invoking " + target.getClass().getSimpleName() + "#" + method.getName());
        Object result = method.invoke(target, args);
        return result;
    }
}
  1. 實(shí)現(xiàn)InvocationHandler厢洞,添加 額外 邏輯
  2. 以Hello接口為紐帶,為被調(diào)用目標(biāo)構(gòu)建 代理對(duì)象 典奉,可以使用代理對(duì)象 間接 運(yùn)行調(diào)用目標(biāo)的邏輯
  3. 以 接口 為中心躺翻,相當(dāng)于添加了一種 對(duì)被調(diào)用者沒(méi)有太大意義的限制
  4. 另外實(shí)例化的是 Proxy對(duì)象 ,而不是真正的被調(diào)用類(lèi)型卫玖,可能會(huì)帶來(lái)各種不變和能力退化
  5. 如果 被調(diào)用者沒(méi)有實(shí)現(xiàn)接口 公你,可以通過(guò) cglib 來(lái)實(shí)現(xiàn)動(dòng)態(tài)代理(克服了對(duì)接口的依賴)
  • cglib動(dòng)態(tài)代理的方式:創(chuàng)建目標(biāo)類(lèi)的 子類(lèi) ,可以達(dá)到 近似使用被調(diào)用者本身 的效果

優(yōu)勢(shì)對(duì)比

JDK Proxy

  1. 最小化依賴關(guān)系 假瞬,簡(jiǎn)化開(kāi)發(fā)和維護(hù)陕靠,JDK本身的支持
  2. JDK平滑升級(jí) ,而字節(jié)碼類(lèi)庫(kù)通常需要進(jìn)行 更新 以保證在新版Java上能夠使用
  3. 代碼實(shí)現(xiàn)簡(jiǎn)單

cglib

  1. 侵入性更小脱茉,JDK Proxy是基于 接口 的懦傍,而 限定被調(diào)用者實(shí)現(xiàn)特定接口 是有侵入性的實(shí)踐
  2. 只需操作關(guān)心的類(lèi) ,而不必為其它相關(guān)類(lèi)增加工作量
  3. 高性能

性能對(duì)比

  1. 在 主流 的JDK版本中芦劣,JDK Proxy在 典型場(chǎng)景 可以提供 對(duì)等的性能水平 粗俱,在數(shù)量級(jí)的差距并不是廣泛存在的
  2. 反射機(jī)制的性能在 現(xiàn)代 JDK中,已經(jīng)得到了 極大的改進(jìn)和優(yōu)化 虚吟,同時(shí)JDK的很多功能同樣使用了 ASM 進(jìn)行字節(jié)碼操作
  3. 在選型時(shí)寸认,性能并不是唯一考量,而 可靠性串慰、可維護(hù)性和編程工作量 才是更主要的考慮因素
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末偏塞,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子邦鲫,更是在濱河造成了極大的恐慌灸叼,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,607評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件庆捺,死亡現(xiàn)場(chǎng)離奇詭異古今,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)滔以,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,239評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)捉腥,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人你画,你說(shuō)我怎么就攤上這事抵碟√已” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,960評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵拟逮,是天一觀的道長(zhǎng)撬统。 經(jīng)常有香客問(wèn)我,道長(zhǎng)敦迄,這世上最難降的妖魔是什么恋追? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,750評(píng)論 1 294
  • 正文 為了忘掉前任,我火速辦了婚禮颅崩,結(jié)果婚禮上几于,老公的妹妹穿的比我還像新娘。我一直安慰自己沿后,他們只是感情好沿彭,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,764評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著尖滚,像睡著了一般喉刘。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上漆弄,一...
    開(kāi)封第一講書(shū)人閱讀 51,604評(píng)論 1 305
  • 那天睦裳,我揣著相機(jī)與錄音,去河邊找鬼撼唾。 笑死廉邑,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的倒谷。 我是一名探鬼主播蛛蒙,決...
    沈念sama閱讀 40,347評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼渤愁!你這毒婦竟也來(lái)了牵祟?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,253評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后牢屋,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,702評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡收奔,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,893評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了办桨。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片筹淫。...
    茶點(diǎn)故事閱讀 40,015評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖呢撞,靈堂內(nèi)的尸體忽然破棺而出损姜,到底是詐尸還是另有隱情,我是刑警寧澤殊霞,帶...
    沈念sama閱讀 35,734評(píng)論 5 346
  • 正文 年R本政府宣布摧阅,位于F島的核電站,受9級(jí)特大地震影響绷蹲,放射性物質(zhì)發(fā)生泄漏棒卷。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,352評(píng)論 3 330
  • 文/蒙蒙 一祝钢、第九天 我趴在偏房一處隱蔽的房頂上張望比规。 院中可真熱鬧,春花似錦拦英、人聲如沸蜒什。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,934評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)灾常。三九已至,卻和暖如春铃拇,著一層夾襖步出監(jiān)牢的瞬間钞瀑,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,052評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工慷荔, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留雕什,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,216評(píng)論 3 371
  • 正文 我出身青樓显晶,卻偏偏與公主長(zhǎng)得像贷岸,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子吧碾,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,969評(píng)論 2 355

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

  • Java設(shè)計(jì)模式——代理模式 代理模式主要分為接口凰盔,委托類(lèi),代理類(lèi) 接口:規(guī)定具體方法委托類(lèi):實(shí)現(xiàn)接口倦春,完成具體的...
    vczyh閱讀 661評(píng)論 0 0
  • 一户敬、基本概念 1.什么是代理? 在闡述JDK動(dòng)態(tài)代理之前睁本,我們很有必要先來(lái)弄明白代理的概念尿庐。代理這個(gè)詞本身并不是計(jì)...
    小李彈花閱讀 16,442評(píng)論 2 40
  • 反射和動(dòng)態(tài)代理放有一定的相關(guān)性,但單純的說(shuō)動(dòng)態(tài)代理是由反射機(jī)制實(shí)現(xiàn)的呢堰,其實(shí)是不夠全面不準(zhǔn)確的抄瑟,動(dòng)態(tài)代理是一種功能行...
    小刀愛(ài)編程閱讀 1,277評(píng)論 0 0
  • 1 何言ってんだ、そんなわけないだろう枉疼。 說(shuō)什么呢皮假,怎么可能鞋拟。 2よくない。 才不好呢惹资! 3そんなことはどうで...
    阿星筆記呀閱讀 1,007評(píng)論 2 18
  • 少年時(shí)就時(shí)時(shí)想褪测,若我死后我會(huì)在何處猴誊? 老人說(shuō):人死如燈滅。但那一縷輕煙又是飄向何方呢侮措? 持有現(xiàn)代科學(xué)觀點(diǎn)的人...
    索南耶西措閱讀 231評(píng)論 0 0