代理設(shè)計(jì)模式

代理模式

通過(guò)代理控制對(duì)象的訪問(wèn),可以詳細(xì)訪問(wèn)某個(gè)對(duì)象的方法,在這個(gè)方法調(diào)用處理,或調(diào)用后處理。既(AOP微實(shí)現(xiàn)) ,AOP核心技術(shù)面向切面編程。


代理模式.png

代理分類

靜態(tài)代理(靜態(tài)定義代理類)
動(dòng)態(tài)代理(動(dòng)態(tài)生成代理類)
Jdk自帶動(dòng)態(tài)代理
Cglib 叉信、javaassist(字節(jié)碼操作庫(kù))

靜態(tài)代理

由程序員創(chuàng)建或工具生成代理類的源碼,再編譯代理類艘希。所謂靜態(tài)也就是在程序運(yùn)行前就已經(jīng)存在代理類的字節(jié)碼文件硼身,代理類和委托類的關(guān)系在運(yùn)行前就確定了硅急。

public interface IUserDao {
    void save();
}

public class ImplUserDao implements  IUserDao {
    public void save() {
        System.out.println("保存用戶");
    }
}

public class UserProxy implements IUserDao {
    private ImplUserDao implUserDao;

    public UserProxy(ImplUserDao implUserDao) {
        this.implUserDao = implUserDao;
    }
    public void save() {
        System.out.println("開(kāi)始事務(wù)");
        implUserDao.save();
        System.out.println("提交事務(wù)");
    }
}

public class StaticProxy {
    public static void main(String[] args) {
        ImplUserDao implUserDao = new ImplUserDao();
        IUserDao userProxy = new UserProxy(implUserDao);
        userProxy.save();
    }
}
Connected to the target VM, address: '127.0.0.1:7226', transport: 'socket'
Disconnected from the target VM, address: '127.0.0.1:7226', transport: 'socket'
開(kāi)始事務(wù)
保存用戶
提交事務(wù)

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

1.代理對(duì)象,不需要實(shí)現(xiàn)接口
2.代理對(duì)象的生成,是利用JDK的API,動(dòng)態(tài)的在內(nèi)存中構(gòu)建代理對(duì)象(需要我們指定創(chuàng)建代理對(duì)象/目標(biāo)對(duì)象實(shí)現(xiàn)的接口的類型)
3.動(dòng)態(tài)代理也叫做:JDK代理,接口代理

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

1)原理:是根據(jù)類加載器和接口創(chuàng)建代理類(此代理類是接口的實(shí)現(xiàn)類,所以必須使用接口 面向接口生成代理佳遂,位于java.lang.reflect包下)
2)實(shí)現(xiàn)方式:

  1. 通過(guò)實(shí)現(xiàn)InvocationHandler接口創(chuàng)建自己的調(diào)用處理器 IvocationHandler handler = new InvocationHandlerImpl(…);
  2. 通過(guò)為Proxy類指定ClassLoader對(duì)象和一組interface創(chuàng)建動(dòng)態(tài)代理類Class clazz = Proxy.getProxyClass(classLoader,new Class[]{…});
  3. 通過(guò)反射機(jī)制獲取動(dòng)態(tài)代理類的構(gòu)造函數(shù)营袜,其參數(shù)類型是調(diào)用處理器接口類型Constructor constructor = clazz.getConstructor(new Class[]{InvocationHandler.class});
  4. 通過(guò)構(gòu)造函數(shù)創(chuàng)建代理類實(shí)例,此時(shí)需將調(diào)用處理器對(duì)象作為參數(shù)被傳入Interface Proxy = (Interface)constructor.newInstance(new Object[] (handler));
    缺點(diǎn):jdk動(dòng)態(tài)代理丑罪,必須是面向接口荚板,目標(biāo)業(yè)務(wù)類必須實(shí)現(xiàn)接口
/**
 * 每次生成動(dòng)態(tài)代理類對(duì)象時(shí),實(shí)現(xiàn)了InvocationHandler接口的調(diào)用處理器對(duì)象
 */
public class InvocationHandlerImpl implements InvocationHandler {
    /**
     * 這其實(shí)業(yè)務(wù)實(shí)現(xiàn)類對(duì)象,用來(lái)調(diào)用具體的業(yè)務(wù)方法
     */
    private Object target;
    public InvocationHandlerImpl(Object target) {
        this.target = target;
    }
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object result = null;
        System.out.println("jdk動(dòng)態(tài)代理開(kāi)始事務(wù)");
        result = method.invoke(target, args);
        System.out.println("jdk動(dòng)態(tài)代理結(jié)束事務(wù)");
        return result;
    }

    public static void main(String[] args) {
        //被代理對(duì)象
        IUserDao iUserDao = new ImplUserDao();
        InvocationHandlerImpl invocationHandler = new InvocationHandlerImpl(iUserDao);
        ClassLoader classLoader =iUserDao.getClass().getClassLoader();
        Class<?>[] interfaces = iUserDao.getClass().getInterfaces();
        IUserDao userDao = (IUserDao) 
    // 主要裝載器吩屹、一組接口及調(diào)用處理動(dòng)態(tài)代理實(shí)例Proxy.newProxyInstance(classLoader, interfaces, invocationHandler);
        userDao.save();
        System.out.println();
    }

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

原理:利用asm開(kāi)源包跪另,對(duì)代理對(duì)象類的class文件加載進(jìn)來(lái),通過(guò)修改其字節(jié)碼生成子類來(lái)處理

<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.1</version>
</dependency>

/**
 * cglib實(shí)現(xiàn)動(dòng)態(tài)代理
 */
public class CglibProxy implements MethodInterceptor {
    private Object targetObject;
    // 這里的目標(biāo)類型為Object煤搜,則可以接受任意一種參數(shù)作為被代理類免绿,實(shí)現(xiàn)了動(dòng)態(tài)代理
    public Object getInstance(Object target) {
        // 設(shè)置需要?jiǎng)?chuàng)建子9類的類
        this.targetObject = target;
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(target.getClass());
        enhancer.setCallback(this);
        return enhancer.create();
    }
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("cglib動(dòng)態(tài)代理開(kāi)始事務(wù)");
        Object result = methodProxy.invoke(targetObject, objects);
        System.out.println("cglb提交事物");
        // 返回代理對(duì)象
        return result;
    }
    public static void main(String[] args) {
        CglibProxy cglibProxy = new CglibProxy();
        ImplUserDao userDao = (ImplUserDao) cglibProxy.getInstance(new ImplUserDao());
        userDao.save();
    }
}

CGLIB動(dòng)態(tài)代理與JDK動(dòng)態(tài)代理區(qū)別

java動(dòng)態(tài)代理是利用反射機(jī)制來(lái)實(shí)現(xiàn)接口的匿名類,在調(diào)用具體方法前調(diào)用InvokeHandler 來(lái)處理擦盾。而cglib動(dòng)態(tài)代理是利用asm開(kāi)源包嘲驾,對(duì)代理類對(duì)象的class文件加載進(jìn)來(lái),通過(guò)修改其字節(jié)碼生成子類來(lái)處理迹卢。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末辽故,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子腐碱,更是在濱河造成了極大的恐慌誊垢,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,378評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件症见,死亡現(xiàn)場(chǎng)離奇詭異彤枢,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)筒饰,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)壁晒,“玉大人瓷们,你說(shuō)我怎么就攤上這事∶敫溃” “怎么了谬晕?”我有些...
    開(kāi)封第一講書人閱讀 152,702評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)携取。 經(jīng)常有香客問(wèn)我攒钳,道長(zhǎng),這世上最難降的妖魔是什么雷滋? 我笑而不...
    開(kāi)封第一講書人閱讀 55,259評(píng)論 1 279
  • 正文 為了忘掉前任不撑,我火速辦了婚禮文兢,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘焕檬。我一直安慰自己姆坚,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,263評(píng)論 5 371
  • 文/花漫 我一把揭開(kāi)白布实愚。 她就那樣靜靜地躺著兼呵,像睡著了一般。 火紅的嫁衣襯著肌膚如雪腊敲。 梳的紋絲不亂的頭發(fā)上击喂,一...
    開(kāi)封第一講書人閱讀 49,036評(píng)論 1 285
  • 那天,我揣著相機(jī)與錄音碰辅,去河邊找鬼懂昂。 笑死,一個(gè)胖子當(dāng)著我的面吹牛乎赴,可吹牛的內(nèi)容都是我干的忍法。 我是一名探鬼主播,決...
    沈念sama閱讀 38,349評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼榕吼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼饿序!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起羹蚣,我...
    開(kāi)封第一講書人閱讀 36,979評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤原探,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后顽素,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體咽弦,經(jīng)...
    沈念sama閱讀 43,469評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,938評(píng)論 2 323
  • 正文 我和宋清朗相戀三年胁出,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了型型。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,059評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡全蝶,死狀恐怖闹蒜,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情抑淫,我是刑警寧澤绷落,帶...
    沈念sama閱讀 33,703評(píng)論 4 323
  • 正文 年R本政府宣布,位于F島的核電站始苇,受9級(jí)特大地震影響砌烁,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜催式,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,257評(píng)論 3 307
  • 文/蒙蒙 一函喉、第九天 我趴在偏房一處隱蔽的房頂上張望避归。 院中可真熱鬧,春花似錦函似、人聲如沸槐脏。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 30,262評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)顿天。三九已至,卻和暖如春蔑担,著一層夾襖步出監(jiān)牢的瞬間牌废,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工啤握, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留鸟缕,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,501評(píng)論 2 354
  • 正文 我出身青樓排抬,卻偏偏與公主長(zhǎng)得像懂从,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子蹲蒲,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,792評(píng)論 2 345

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

  • 整體Retrofit內(nèi)容如下: 1番甩、Retrofit解析1之前哨站——理解RESTful 2、Retrofit解析...
    隔壁老李頭閱讀 3,220評(píng)論 2 10
  • 1届搁、 什么是代理設(shè)計(jì)模式 即Proxy Pattern缘薛,23種常用的面向?qū)ο筌浖脑O(shè)計(jì)模式之一。為其他對(duì)象提供一種...
    YYOmomo閱讀 383評(píng)論 0 4
  • 動(dòng)態(tài)代理是Java語(yǔ)言中非常經(jīng)典的一種設(shè)計(jì)模式卡睦,也是所有設(shè)計(jì)模式中最難理解的一種宴胧。本文將通過(guò)一個(gè)簡(jiǎn)單的例子模擬JD...
    歐陽(yáng)鋒閱讀 25,811評(píng)論 47 267
  • 大人,又來(lái)了一批脂肪表锻,上次的氨基酸和葡萄糖還沒(méi)處理呢恕齐?現(xiàn)在我們的工廠已經(jīng)超負(fù)荷了,有好多都被脂肪塞滿瞬逊,沒(méi)法工作檐迟,血...
    雪花_ada1閱讀 292評(píng)論 0 0
  • 本來(lái)打算將寫作視為一種興趣愛(ài)好,聽(tīng)了課后溶其,卻有種浮躁的心理骚腥。說(shuō)實(shí)話,受到了課程的影響瓶逃,也有種通過(guò)寫作賺錢的渴望束铭。因...
    德飛商學(xué)院閱讀 412評(píng)論 0 2