這篇文章主要介紹“Java動(dòng)態(tài)代理指的是什么”,在日常操作中,相信很多人在Java動(dòng)態(tài)代理指的是什么問(wèn)題上存在疑惑,小編查閱了各式資料,整理出簡(jiǎn)單好用的操作方法,希望對(duì)大家解答”Java動(dòng)態(tài)代理指的是什么”的疑惑有所幫助!接下來(lái),請(qǐng)跟著小編一起來(lái)學(xué)習(xí)吧!
站在用戶的角度思考問(wèn)題,與客戶深入溝通,找到西和網(wǎng)站設(shè)計(jì)與西和網(wǎng)站推廣的解決方案,憑借多年的經(jīng)驗(yàn),讓設(shè)計(jì)與互聯(lián)網(wǎng)技術(shù)結(jié)合,創(chuàng)造個(gè)性化、用戶體驗(yàn)好的作品,建站類(lèi)型包括:做網(wǎng)站、網(wǎng)站制作、企業(yè)官網(wǎng)、英文網(wǎng)站、手機(jī)端網(wǎng)站、網(wǎng)站推廣、主機(jī)域名、虛擬空間、企業(yè)郵箱。業(yè)務(wù)覆蓋西和地區(qū)。
一、靜態(tài)代理
描述動(dòng)態(tài)代理之前,先看一看靜態(tài)代理。
定義一個(gè)程序員的接口,只干兩件事情(程序員太忙,別的做不了)
Java程序員長(zhǎng)這個(gè)樣,他會(huì)開(kāi)發(fā)Java代碼,會(huì)調(diào)試Java代碼
有個(gè)很牛逼的叫 Farmerbrag 的程序員,他在開(kāi)發(fā)之前,會(huì)祈禱一下,這樣他開(kāi)發(fā)的代碼就不會(huì)有bug。
我們這么來(lái)描述Farmerbrag(代理類(lèi))
如果Farmerbrag只是一個(gè)普通的Java程序員,那么他的開(kāi)發(fā)結(jié)果是
Farmerbrag is coding java.
Farmerbrag is debugging java.
真正的Farmerbrag(Farmerbrag代理類(lèi))是這樣的
Farmerbrag is praying for the code!
Farmerbrag is coding java.
Farmerbrag's code is bug-free and does not require debugging
靜態(tài)代理優(yōu)點(diǎn)不說(shuō)了,說(shuō)一下缺點(diǎn)
1、增加了代碼維護(hù)復(fù)雜度。代理類(lèi)和實(shí)現(xiàn)類(lèi)具有相同的接口,代理類(lèi)通過(guò)實(shí)現(xiàn)類(lèi)執(zhí)行具體的方法。這樣就出現(xiàn)了大量的代碼重復(fù)。如果接口增加一個(gè)方法,除了所有實(shí)現(xiàn)類(lèi)需要實(shí)現(xiàn)這個(gè)方法外,所有代理類(lèi)也需要實(shí)現(xiàn)此方法。
2、代理對(duì)象只服務(wù)于一種類(lèi)型的對(duì)象。如果要服務(wù)多類(lèi)型的對(duì)象,要為每一種對(duì)象都進(jìn)行代理,靜態(tài)代理在程序規(guī)模稍大時(shí)就無(wú)法勝任。
二、動(dòng)態(tài)代理的例子
接著靜態(tài)代理的例子,F(xiàn)armerbrag會(huì)祈禱這個(gè)功能是他特有的,其他程序員不會(huì)。我們可以定義一個(gè)擁有這項(xiàng)特技的程序員(第一部分靜態(tài)代理就是這么做的),但其他程序員可能具有別的特技,根本定義不完?。ㄓ袥](méi)有感覺(jué)到某些業(yè)務(wù)需求很想這個(gè)場(chǎng)景)
其實(shí)我們不需要去定義他,這個(gè)技能可以后天習(xí)得??纯丛趺醋觯?nbsp;
這個(gè)動(dòng)態(tài)代理的程序員執(zhí)行結(jié)果如下
Farmerbrag is praying for the code!
Farmerbrag is coding java.
Farmerbrag's code is bug-free and does not require debugging
farmerbragProxy的類(lèi)型是Developer接口,不是一個(gè)實(shí)現(xiàn)類(lèi)。farmerbrag在被代理后生成的對(duì)象,并不屬于Developer接口的任何一個(gè)實(shí)現(xiàn)類(lèi),是基于Developer接口和farmerbrag的類(lèi)加載代理出來(lái)的。(mybatis定義的mapper接口怎么就能被調(diào)用執(zhí)行呢)
看一下newProxyInstance()接口的定義
包括三個(gè)參數(shù)
loader和interfaces決定這個(gè)類(lèi)到底是個(gè)怎么樣的類(lèi)。而h是InvocationHandler,決定這個(gè)代理類(lèi)到底是多了什么功能。所以動(dòng)態(tài)代理的內(nèi)容重點(diǎn)就是這個(gè)InvocationHandler。
動(dòng)態(tài)代理的例子采用了lambda表達(dá)式,主要代碼是對(duì)InvocationHandler的實(shí)現(xiàn)。
三、代碼分析
從寫(xiě)代碼的角度,前面2節(jié)已經(jīng)足夠了,下邊對(duì)原理進(jìn)行分析。
看看源碼其中關(guān)鍵的地方。在newProxyInstance()方法中有這樣幾段
1、克隆接口
2、查找或生成指定的代理類(lèi)
3、通過(guò)反射,拿到代理類(lèi)的構(gòu)造函數(shù)
4、通過(guò)構(gòu)造函數(shù)new一個(gè)對(duì)象,并關(guān)聯(lián)InvocationHandler
看到這里有些人可能會(huì)更蒙,InvocationHandler到底是做什么的?反射(reflect)又是怎么回事?代碼到底是怎么就被串改了呢?
四、原理剖析
1、class文件及其加載(反射)
編譯器編譯Java文件,產(chǎn)生.class 文件存放在磁盤(pán)中,文件內(nèi)容是只有JVM虛擬機(jī)能夠識(shí)別的機(jī)器碼。JVM虛擬機(jī)讀取字節(jié)碼文件,取出二進(jìn)制數(shù)據(jù),加載到內(nèi)存中,解析.class 文件內(nèi)的信息,生成對(duì)應(yīng) Class對(duì)象
通過(guò)一段代碼演示手動(dòng)加載class文件字節(jié)碼到系統(tǒng)內(nèi),轉(zhuǎn)換成class對(duì)象,再實(shí)例化的過(guò)程
被加載的類(lèi)我們復(fù)用前面的JavaDeveloper.class
自定義一個(gè)類(lèi)加載器
執(zhí)行代碼得到如下結(jié)果
net.fengyu.proxy.JavaDeveloper
Farmerbrag is coding java.
以上代碼演示了,通過(guò)字節(jié)碼加載成class對(duì)象的過(guò)程
2、運(yùn)行期生成二進(jìn)制字節(jié)碼
JVM通過(guò)字節(jié)碼的二進(jìn)制信息加載類(lèi),如果我們?cè)谶\(yùn)行期的系統(tǒng)中,遵循Java編譯系統(tǒng)組織.class文件的格式和結(jié)構(gòu),生成相應(yīng)的二進(jìn)制數(shù)據(jù),然后把這個(gè)二進(jìn)制數(shù)據(jù)加載轉(zhuǎn)換成對(duì)應(yīng)的類(lèi),這樣,就完成了在代碼中,動(dòng)態(tài)創(chuàng)建一個(gè)類(lèi)的能力。第二節(jié)動(dòng)態(tài)代理例子顯然是這個(gè)能力的一個(gè)子集。
有一些開(kāi)源框架支持運(yùn)行期生成二進(jìn)制字節(jié)碼這個(gè)功能,如ASM,Javassist
ASM 是一個(gè) Java 字節(jié)碼操控框架。能夠以二進(jìn)制形式修改已有類(lèi)或者動(dòng)態(tài)生成類(lèi)。ASM可以直接產(chǎn)生二進(jìn)制 class 文件,也可以在類(lèi)被加載入Java虛擬機(jī)之前動(dòng)態(tài)改變類(lèi)行為。Spring使用的CGLIB也采用ASM框架作為其字節(jié)碼操作的工具。
下邊一段代碼生成一個(gè)跟前面JavaDeveloper幾乎一樣的類(lèi)ASMDeveloper,使用上一小節(jié)的LoadClass類(lèi)運(yùn)行有相同的輸出
這個(gè)例子說(shuō)明,在代碼里生成字節(jié)碼,并動(dòng)態(tài)地加載成class對(duì)象,創(chuàng)建實(shí)例是完全可以實(shí)現(xiàn)的。動(dòng)態(tài)修改某個(gè)類(lèi)當(dāng)然也能做到(動(dòng)態(tài)代理就做這事)。
至此,原理層面基本已經(jīng)說(shuō)清楚了。
3、為什么是InvocationHandler
我們已經(jīng)具有能力動(dòng)態(tài)修改一個(gè)類(lèi)的代碼,使用ASM哪怕生成一個(gè)非常簡(jiǎn)單的類(lèi),代碼量也是又多又復(fù)雜。仔細(xì)思考代理模式中的代理Proxy角色。Proxy角色在執(zhí)行代理業(yè)務(wù)的時(shí)候,無(wú)非是在調(diào)用真正業(yè)務(wù)之前或者之后做一些“額外”業(yè)務(wù)。
代理類(lèi)處理的邏輯很簡(jiǎn)單,在調(diào)用某個(gè)方法前及方法后做一些額外的業(yè)務(wù)。換一種思路就是,在觸發(fā)(invoke)真實(shí)角色的方法之前或者之后做一些額外的業(yè)務(wù)。為了構(gòu)造出具有通用、簡(jiǎn)單的代理類(lèi),可以將所有的觸發(fā)真實(shí)角色動(dòng)作交給一個(gè)觸發(fā)的管理器。這種管理器就是InvocationHandler。
在這種模式之中,代理Proxy和RealSubject需要實(shí)現(xiàn)相同的功能(函數(shù)方法)。
面向?qū)ο蟮木幊讨?,想要約定Proxy和RealSubject實(shí)現(xiàn)相同的功能(函數(shù)方法)有兩種方式
a、定義一個(gè)功能接口,Proxy 和RealSubject都實(shí)現(xiàn)這個(gè)接口。
b、通過(guò)繼承,Proxy繼承自RealSubject,這樣Proxy則擁有了RealSubject的功能,
JDK中提供的創(chuàng)建動(dòng)態(tài)代理的機(jī)制采用a思路;而cglib采用b思路(spring兩者都使用了)。
到此,關(guān)于“Java動(dòng)態(tài)代理指的是什么”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實(shí)踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識(shí),請(qǐng)繼續(xù)關(guān)注創(chuàng)新互聯(lián)網(wǎng)站,小編會(huì)繼續(xù)努力為大家?guī)?lái)更多實(shí)用的文章!
標(biāo)題名稱:Java動(dòng)態(tài)代理指的是什么
文章起源:http://www.rwnh.cn/article12/pcoggc.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供建站公司、面包屑導(dǎo)航、小程序開(kāi)發(fā)、移動(dòng)網(wǎng)站建設(shè)、網(wǎng)站策劃、網(wǎng)站設(shè)計(jì)公司
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)