新聞中心
1.深夜奏對

已經(jīng)快三更天了, Java帝國的國王還在看著IO大臣的奏章發(fā)呆,他有點想不明白, 帝國已經(jīng)給臣民了提供了這么多的東西,他們?yōu)槭裁催€不滿意呢? 集合、IO、反射、網(wǎng)絡(luò)、線程、泛型、JDBC ......在IT界哪一個不都是響當(dāng)當(dāng)?shù)挠餐ㄘ? 有了這些技術(shù),寫個Java程序多簡單啊, 臣民們?yōu)楹芜€整天抗議呢?
這還是昨天IO大臣的一個奏章,其中說到各個部落要醞釀一場大規(guī)模的抗議游行,抗議Java不支持動態(tài)性,不能在運行時修改一個類,導(dǎo)致不能用聲明的方式來編程。
國王憤憤地想,我的政策太開明了,這些刁民不知好歹,蹬鼻子上臉,以后要堅決加強東廠西廠錦衣衛(wèi)鎮(zhèn)撫司等紀檢法的建設(shè),有意見可以上訪, 不能這么胡鬧,增加社會不穩(wěn)定因素。帝國正在和Python, PHP等國家開戰(zhàn),處處都要銀子,攘外必先安內(nèi)啊。
想到這里,國王立刻命令呂公公宣IO大臣進宮。
IO大臣半夜里被從熱騰騰的的被窩里拽出來,心里老大不情愿, 迷迷糊糊地跟著呂公公進了宮。
“陛下半夜三更還在為國事操勞,真乃臣等之罪也 !” IO大臣雖然心里不情愿,但還是畢恭畢敬。
“愛卿,你說說這是怎么一回事? 什么是Java 不支持動態(tài)性? ”國王拿出了奏章。
IO大臣心里明白了,原來是介個啊。
“啟奏陛下,其實這是刁民們羨慕Python 、Ruby 等語言的動態(tài)性,想讓我們Java 也支持,他們最想要的一個功能就是能在運行時對類進行修改,這樣可以用聲明的方式來編程?!?/p>
“你能不能說點朕能聽懂的話?” 國王低沉的聲音里隱藏著馬上就要噴薄而出的怨氣,老子想了一晚上都沒整明白,你還在這里給我文縐縐的!
“是這樣” IO大臣開始調(diào)用腦細胞遣詞造句,準備用通俗易懂的語言撲滅陛下的怒火。
“所謂運行時對類進行修改,打個比方來說,我寫了一個HelloWorld的類,其中有兩個方法:sayHello()和sayHelloToPHP(),陛下請看: ”
“這是帝國三歲小孩都能明白的代碼,說重點!”
“然后這個類運行起來了,刁民們希望在運行的時候可以修改這類, 譬如加一個新方法sayHelloToPython(), 或者對現(xiàn)在的sayHello()方法里加一點新東西, 甚至把sayHelloToPHP()這個方法刪除!”
“這些刁民太過分了, 難道他們不能寫個新的類來做這件事嗎?”
“陛下圣明, 臣也覺得可以新寫一個類比如HelloWorldNew來做這件事情,重新編譯一下不就行了嗎? 可是他們說的是在運行時修改,是運行時,運行時,運行時,重要的事情說三遍,不是編譯時?!?/p>
“運行時? 一個類一旦裝入到方法區(qū)還怎么修改 ” 國王還是很了解JVM這一套。 “你知道他們?yōu)槭裁从羞@個要求嗎?”
“他們說了想用聲明的方式來編程.....” IO大臣意識到大事不好。
“什么是聲明的方式” 國王窮追不舍
“這個臣還不太清楚......”
“快去徹查,限你三天回話?!?/p>
“遵旨”
2.明察暗訪
IO大臣冷汗都出來了, 他睡意全無,趕緊召集家丁幕僚準備上山下鄉(xiāng)、明察暗訪,限他們兩天把這個“以聲明的方式編程”搞清楚。
兩天內(nèi)不斷有快馬回報,各種各樣的信息如雪片般飛來。 IO大臣又花了一天時間整理,終于明白了這個“以聲明的方式編程”。
原來這幫刁民犯懶,寫完了代碼以后有這樣的需求:
在某些函數(shù)調(diào)用前后加上日志記錄
給某些函數(shù)加上事務(wù)的支持
給某些函數(shù)加上權(quán)限控制
......
這些需求挺通用的,如果在每個函數(shù)中都實現(xiàn)一遍,那重復(fù)代碼就太多了。 更要命的是有時候代碼是別人寫的,你只有class 文件,怎么修改? 怎么加上這些功能?
所以“刁民”們就想了一個損招,他們想在XML文件或者什么地方聲明一下, 比如對于添加日志的需求吧, 聲明的大意如下:
對于com.coderising這個package下所有以add開頭的方法,在執(zhí)行之前都要調(diào)用Logger.startLog()方法, 在執(zhí)行之后都要調(diào)用Logger.endLog()方法。
對于增加事務(wù)支持的需求,聲明的大意如下:
對于所有以DAO結(jié)尾的類,所有的方法執(zhí)行之前都要調(diào)用TransactionManager.begin(),執(zhí)行之后都要調(diào)用TransactionManager.commit(), 如果拋出異常的話調(diào)用TransactionManager.rollback()。
他們已經(jīng)充分發(fā)揮了自己的那點兒小聰明,號稱是開發(fā)了一個叫AOP的東西,能夠讀取這個XML中的聲明, 并且能夠找到那些需要插入日志的類和方法, 接下來就需要修改這些方法了。 但是Java帝國不允許修改一個已經(jīng)被加載或者正在運行的類, 于是他們就不干了,就要抗議、就要游行,就要暴動, 真是可惡。
IO大臣決定向國王做一次匯報,看看國王的反應(yīng)。
3.Java 動態(tài)代理
國王不愧是國王, IO大臣稍微一解釋, 就明白怎么回事了。
“愛卿,你覺得該怎么辦? ” 皮球又被踢到了IO大臣那里。
“臣覺得不能讓這些刁民突破帝國的底線, 我們的class在運行時是不能被修改的,如果也像Python,Ruby 那樣在運行時可以肆意修改,那就太混亂了!” IO大臣小心翼翼地揣摩圣意。
“言之有理, 愛卿有何辦法? ”
“臣想到了一個辦法,雖然不能修改現(xiàn)有的類,但是可以在運行時動態(tài)的創(chuàng)建新的類啊,比如有個類HelloWorld:
“這么簡單的類,怎么還得實現(xiàn)一個接口呢? ” 國王問道
“臣想給這些刁民們增加一點點障礙, 你不是想讓我動態(tài)地創(chuàng)建新的類嗎?你必須得有接口才行啊” IO大臣又得意又陰險地笑了。
國王臉上也露出了一絲不易覺察的微笑。
“現(xiàn)在他們的問題是要在sayHello()方法中調(diào)用Logger.startLog(), Logger.endLog()添加上日志, 但是這個sayHello()方法又不能修改了!”
“所以臣想了想, 可以動態(tài)地生成一個新類,讓這個類作為HelloWorld的代理去做事情(加上日志功能), 陛下請看,這個HelloWorld代理也實現(xiàn)了IHelloWorld接口。 所以在調(diào)用方看來,都是IHelloWorld接口, 并不會意識到其實底層其實已經(jīng)滄海滄田了?!?/p>
“朕能明白你這個綠色的HelloWorld代理,但是你這個類怎么可能知道把Logger的方法加到什么地方呢?” 國王一下子看出了關(guān)鍵。
“陛下天資聰慧,臣拜服,‘刁民’們需要寫一個類來告訴我們具體把Logger的代碼加到什么地方, 這個類必須實現(xiàn)帝國定義的InvocationHandler接口,該接口中有個叫做invoke的方法就是他們寫擴展代碼的地方。 比如這個LoggerHandler: ”
“ 看起來有些讓朕不舒服,不過朕大概明白了, 無非就是在調(diào)用真正的方法之前先調(diào)用Logger.startLog(), 在調(diào)用之后在調(diào)用Logger.end(), 這就是對方法進行攔截了,對不對?”
“正是如此! 其實這個LoggerHandler 充當(dāng)了一個中間層, 我們自動化生成的類$HelloWorld100會調(diào)用它,把sayHello這樣的方法調(diào)用傳遞給他 (上圖中的method變量),于是sayHello()方法就被添加上了Logger的startLog()和endLog()方法”
“此外,臣想提醒陛下的是,這個Handler不僅僅能作用于IHelloWorld 這個接口和 HelloWorld這個類,陛下請看,那個target 是個Object, 這就意味著任何類的實例都可以, 當(dāng)然我們會要求這些類必須得實現(xiàn)接口。 臣民們使用LoggerHandler的時候是這樣的:”
輸出:
Start Logging
Hello World
End Logging
“如果想對另外一個接口ICalculator和類Calcualtor做代理, 也可以復(fù)用這個LoggerHandler的類:”
“折騰了變天,原來魔法是在Proxy.newProxyInstance(....) 這里,就是動態(tài)地生成了一個類嘛, 這個類對臣民們來說是動態(tài)生成的, 也是看不到源碼的?!?/p>
“圣明無過陛下,我就是在運行時,在內(nèi)存中生成了一個新的類,這個類在調(diào)用sayHello() 或者add()方法的時候, 其實調(diào)用的是LoggerHanlder的invoke 方法, 而那個invoke就會攔截真正的方法調(diào)用,添加日志功能了! ”
“愛卿辛苦了,雖然有點繞,但是理解了還是挺簡單的。 朕明天就頒發(fā)圣旨, 全國推行,對了你打算叫它什么名字? ”
“既然是在運行時動態(tài)的生成類,并且作為一個真實對象的代理來做事情, 那就叫動態(tài)代理吧!”
動態(tài)代理技術(shù)發(fā)布了,臣民們得到了暫時的安撫,但是這個動態(tài)代理的缺陷就是必須有接口才能工作,帝國的臣民能忍受得了嗎?
【本文為專欄作者“劉欣”的原創(chuàng)稿件,轉(zhuǎn)載請通過作者微信公眾號coderising獲取授權(quán)】
戳這里,看該作者更多好文
網(wǎng)站欄目:Java帝國之動態(tài)代理
分享URL:http://fisionsoft.com.cn/article/coichji.html


咨詢
建站咨詢
