02.Java代理模式--靜態(tài)代理画畅,動態(tài)代理,CGLib代理

代理(Proxy)是一種設(shè)計模式宋距,通俗的講就是通過別人達到自己不可告人的目的(玩笑)轴踱。

舉個例子如下圖:

代理模式的關(guān)鍵點是:代理對象與目標(biāo)對象.代理對象是對目標(biāo)對象的擴展,并會調(diào)用目標(biāo)對象

這三個代理模式,就像是更新?lián)Q代谚赎,越來越先進淫僻。動態(tài)代理解決了靜態(tài)代理必須同目標(biāo)對象繼承

同一個接口或類,CGlib解決了動態(tài)代理目標(biāo)對象必須繼承一個接口的問題沸版。

一.靜態(tài)代理

條件:代理對象必須和目標(biāo)對象繼承同一個接口或者類

代碼如下:

/**

* 接口

*/public interface IUserDao {

? ? void save();

}

/**

* 接口實現(xiàn)

* 目標(biāo)對象

*/public class UserDao implements IUserDao {

? ? public void save() {

? ? ? ? System.out.println("----已經(jīng)保存數(shù)據(jù)!----");

? ? }

}

/**

* 代理對象,靜態(tài)代理

*/public class UserDaoProxy implements IUserDao{

? ? //接收保存目標(biāo)對象? ? private IUserDao target;

? ? public UserDaoProxy(IUserDao target){

? ? ? ? this.target=target;

? ? }

? ? public void save() {

? ? ? ? System.out.println("開始事務(wù)...");

? ? ? ? target.save();//執(zhí)行目標(biāo)對象的方法? ? ? ? System.out.println("提交事務(wù)...");

? ? }

}

/**

* 測試類

*/public class App {

? ? public static void main(String[] args) {

? ? ? ? //目標(biāo)對象? ? ? ? UserDao target = new UserDao();

? ? ? ? //代理對象,把目標(biāo)對象傳給代理對象,建立代理關(guān)系? ? ? ? UserDaoProxy proxy = new UserDaoProxy(target);

? ? ? ? proxy.save();//執(zhí)行的是代理的方法? ? }

}

靜態(tài)代理總結(jié):

1.可以做到在不修改目標(biāo)對象的情況下嘁傀,為目標(biāo)對象條件功能兴蒸。

2.缺點:必須同目標(biāo)對象繼承同一接口或類

二.動態(tài)代理(JDK代理)

不需要實現(xiàn)接口视粮,代理對象的生成是利用JDK的API,在內(nèi)存中生存代理對象橙凳。但是目標(biāo)對象必須繼承一個接口

代理對象的包:java.lang.reflect.Proxy

JDK實現(xiàn)代理只需要使用newProxyInstance方法,但是該方法需要接收三個參數(shù),完整的寫法是:

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

三個參數(shù)分別表示:

ClassLoader loader,:指定當(dāng)前目標(biāo)對象使用類加載器,獲取加載器的方法是固定的

Class<?>[] interfaces,:目標(biāo)對象實現(xiàn)的接口的類型,使用泛型方式確認(rèn)類型

InvocationHandler h:事件處理,執(zhí)行目標(biāo)對象的方法時,會觸發(fā)事件處理器的方法,會把當(dāng)前執(zhí)行目標(biāo)對象的方法作為參數(shù)傳入

代碼示例如下:

代理工廠類 ProxyFactory.java

/**

* 創(chuàng)建動態(tài)代理對象

* 動態(tài)代理不需要實現(xiàn)接口,但是需要指定接口類型

*/public class ProxyFactory{

? ? //維護一個目標(biāo)對象? ? private Object target;

? ? public ProxyFactory(Object target){

? ? ? ? this.target=target;

? ? }

? //給目標(biāo)對象生成代理對象? ? public Object getProxyInstance(){

? ? ? ? return Proxy.newProxyInstance(

? ? ? ? ? ? ? ? target.getClass().getClassLoader(),

? ? ? ? ? ? ? ? target.getClass().getInterfaces(),

? ? ? ? ? ? ? ? new InvocationHandler() {

? ? ? ? ? ? ? ? ? ? @Override? ? ? ? ? ? ? ? ? ? public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

? ? ? ? ? ? ? ? ? ? ? ? System.out.println("開始事務(wù)2");

? ? ? ? ? ? ? ? ? ? ? ? //執(zhí)行目標(biāo)對象方法? ? ? ? ? ? ? ? ? ? ? ? Object returnValue = method.invoke(target, args);

? ? ? ? ? ? ? ? ? ? ? ? System.out.println("提交事務(wù)2");

? ? ? ? ? ? ? ? ? ? ? ? return returnValue;

? ? ? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? }

? ? ? ? );

? ? }

}

測試類 App.java

/**

* 測試類

*/public class App {

? ? public static void main(String[] args) {

? ? ? ? // 目標(biāo)對象? ? ? ? IUserDao target = new UserDao();

? ? ? ? // 【原始的類型 class cn.itcast.b_dynamic.UserDao】? ? ? ? System.out.println(target.getClass());

? ? ? ? // 給目標(biāo)對象蕾殴,創(chuàng)建代理對象? ? ? ? IUserDao proxy = (IUserDao) new ProxyFactory(target).getProxyInstance();

? ? ? ? // class $Proxy0? 內(nèi)存中動態(tài)生成的代理對象? ? ? ? System.out.println(proxy.getClass());

? ? ? ? // 執(zhí)行方法? 【代理對象】? ? ? ? proxy.save();

? ? }

}

3.Cglib代理

Cglib代理,目標(biāo)對象不需要繼承一個接口岛啸,它是已目標(biāo)子類的方式實現(xiàn)代理的钓觉,所以Cglib代理也叫子類代理

Cglib子類代理的實現(xiàn)方法:

1.導(dǎo)包maven地址:

<dependency>

? ? <groupId>cglib</groupId>

? ? <artifactId>cglib</artifactId>

? ? <version>3.2.10</version>

</dependency>

或者引入pring-core-3.2.5.jar 包

2.在內(nèi)存中動態(tài)構(gòu)建子類

注意:代理類不能為 final,否則報錯坚踩,目標(biāo)方法不能為final或static荡灾,否則不會執(zhí)行目標(biāo)方法額外的

方法。Cglib是如何實現(xiàn)代理的,還仔細沒研究批幌,有興趣的可以去看看源碼础锐。

代碼示例:

/**

* 目標(biāo)對象,沒有實現(xiàn)任何接口

*/public class UserDao {

? ? public void save() {

? ? ? ? System.out.println("----已經(jīng)保存數(shù)據(jù)!----");

? ? }

}

/**

* Cglib子類代理工廠

* 對UserDao在內(nèi)存中動態(tài)構(gòu)建一個子類對象

*/public class ProxyFactory implements MethodInterceptor{

? ? //維護目標(biāo)對象? ? private Object target;

? ? public ProxyFactory(Object target) {

? ? ? ? this.target = target;

? ? }

? ? //給目標(biāo)對象創(chuàng)建一個代理對象? ? public Object getProxyInstance(){

? ? ? ? //1.工具類? ? ? ? Enhancer en = new Enhancer();

? ? ? ? //2.設(shè)置父類? ? ? ? en.setSuperclass(target.getClass());

? ? ? ? //3.設(shè)置回調(diào)函數(shù)? ? ? ? en.setCallback(this);

? ? ? ? //4.創(chuàng)建子類(代理對象)? ? ? ? return en.create();

? ? }

? ? @Override? ? public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {

? ? ? ? System.out.println("開始事務(wù)...");

? ? ? ? //執(zhí)行目標(biāo)對象的方法? ? ? ? Object returnValue = method.invoke(target, args);

? ? ? ? System.out.println("提交事務(wù)...");

? ? ? ? return returnValue;

? ? }

}

測試類:

/**

* 測試類

*/public class App {

? ? @Test? ? public void test(){

? ? ? ? //目標(biāo)對象? ? ? ? UserDao target = new UserDao();

? ? ? ? //代理對象? ? ? ? UserDao proxy = (UserDao)new ProxyFactory(target).getProxyInstance();

? ? ? ? //執(zhí)行代理對象的方法? ? ? ? proxy.save();

? ? }

}

在Spring的AOP編程中,如果加入容器的目標(biāo)對象有實現(xiàn)的接口荧缘,用JDK代理皆警,如果沒有實現(xiàn)接口用Cglib代理

后面會介紹Spring內(nèi)容,掌握動態(tài)代理會更容易理解Spring的AOP編程

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子讶凉,更是在濱河造成了極大的恐慌汛骂,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,290評論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件场绿,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機左痢,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,107評論 2 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來系洛,“玉大人俊性,你說我怎么就攤上這事∶璩叮” “怎么了定页?”我有些...
    開封第一講書人閱讀 156,872評論 0 347
  • 文/不壞的土叔 我叫張陵,是天一觀的道長绽诚。 經(jīng)常有香客問我典徊,道長,這世上最難降的妖魔是什么恩够? 我笑而不...
    開封第一講書人閱讀 56,415評論 1 283
  • 正文 為了忘掉前任卒落,我火速辦了婚禮,結(jié)果婚禮上蜂桶,老公的妹妹穿的比我還像新娘儡毕。我一直安慰自己,他們只是感情好扑媚,可當(dāng)我...
    茶點故事閱讀 65,453評論 6 385
  • 文/花漫 我一把揭開白布腰湾。 她就那樣靜靜地躺著,像睡著了一般疆股。 火紅的嫁衣襯著肌膚如雪费坊。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,784評論 1 290
  • 那天旬痹,我揣著相機與錄音附井,去河邊找鬼讨越。 笑死,一個胖子當(dāng)著我的面吹牛永毅,可吹牛的內(nèi)容都是我干的谎痢。 我是一名探鬼主播,決...
    沈念sama閱讀 38,927評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼卷雕,長吁一口氣:“原來是場噩夢啊……” “哼节猿!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起漫雕,我...
    開封第一講書人閱讀 37,691評論 0 266
  • 序言:老撾萬榮一對情侶失蹤滨嘱,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后浸间,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體太雨,經(jīng)...
    沈念sama閱讀 44,137評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,472評論 2 326
  • 正文 我和宋清朗相戀三年魁蒜,在試婚紗的時候發(fā)現(xiàn)自己被綠了囊扳。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,622評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡兜看,死狀恐怖锥咸,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情细移,我是刑警寧澤搏予,帶...
    沈念sama閱讀 34,289評論 4 329
  • 正文 年R本政府宣布,位于F島的核電站弧轧,受9級特大地震影響雪侥,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜精绎,卻給世界環(huán)境...
    茶點故事閱讀 39,887評論 3 312
  • 文/蒙蒙 一速缨、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧代乃,春花似錦旬牲、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,741評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽牍陌。三九已至擎浴,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間毒涧,已是汗流浹背贮预。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評論 1 265
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人仿吞。 一個月前我還...
    沈念sama閱讀 46,316評論 2 360
  • 正文 我出身青樓滑频,卻偏偏與公主長得像,于是被迫代替她去往敵國和親唤冈。 傳聞我的和親對象是個殘疾皇子峡迷,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,490評論 2 348

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

  • 0.前言 本文主要想闡述的問題如下:什么動態(tài)代理(AOP)以及如何用JDK的Proxy和InvocationHan...
    SYFHEHE閱讀 2,262評論 1 7
  • 1.靜態(tài)代理 靜態(tài)代理是由代理類使用目標(biāo)接口的實現(xiàn)類的引用實現(xiàn)的一種代理模式,比如新建目標(biāo)接口IUserDao...
    安徒生閱讀 458評論 0 0
  • 1. 代理模式 1.1你虹、代理模式簡單介紹 代理模式定義:給某一個對象提供一個代理绘搞,并由代理對象控制對原對象的引用。...
    問天036閱讀 273評論 0 0
  • 1.代理模式 代理(Proxy)是一種設(shè)計模式傅物, 提供了對目標(biāo)對象另外的訪問方式夯辖;即通過代理訪問目標(biāo)對象。 這樣好...
    yangliangliang閱讀 279評論 0 0
  • 前言 從好久之前就打算開始拾起“筆”,重新開始記錄生活中最真摯的情感,沒有任何目的卒暂,不想受任何限制啄栓,只是想說...
    大_林子閱讀 253評論 2 1