設(shè)計(jì)模式 代理模式(靜態(tài)代理玷室、JDK動(dòng)態(tài)代理以及CGLIB動(dòng)態(tài)代理)

起因:在看架構(gòu)設(shè)計(jì)的時(shí)候零蓉,看到代理模式笤受,回想起來(lái)穷缤,做了這么幾年的java敌蜂,雖然知道代理模式,但是未曾深入了解過(guò)津肛,所以去打算研究一下代理模式章喉。


1 代理模式

代理模式的定義:
由于某些原因需要給某對(duì)象提供一個(gè)代理以控制對(duì)該對(duì)象的訪問(wèn)。
這時(shí)身坐,訪問(wèn)對(duì)象不適合或者不能直接引用目標(biāo)對(duì)象秸脱,代理對(duì)象作為訪問(wèn)對(duì)象和目標(biāo)對(duì)象之間的中介。

2 代理模式 概述

代理模式是java中最常用的設(shè)計(jì)模式之一部蛇,尤其是在spring框架中廣泛應(yīng)用摊唇。
對(duì)于java的代理模式,一般可分為:靜態(tài)代理涯鲁、動(dòng)態(tài)代理巷查、以及CGLIB實(shí)現(xiàn)動(dòng)態(tài)代理。

代理模式的主要優(yōu)點(diǎn)有:

  • 代理模式在客戶(hù)端與目標(biāo)對(duì)象之間起到一個(gè)中介作用和保護(hù)目標(biāo)對(duì)象的作用抹腿;
  • 代理對(duì)象可以擴(kuò)展目標(biāo)對(duì)象的功能岛请;
  • 代理模式能將客戶(hù)端與目標(biāo)對(duì)象分離,在一定程度上降低了系統(tǒng)的耦合度警绩,增加了程序的可擴(kuò)展性

其主要缺點(diǎn)是:

  • 代理模式會(huì)造成系統(tǒng)設(shè)計(jì)中類(lèi)的數(shù)量增加
  • 在客戶(hù)端和目標(biāo)對(duì)象之間增加一個(gè)代理對(duì)象崇败,會(huì)造成請(qǐng)求處理速度變慢;
  • 增加了系統(tǒng)的復(fù)雜度肩祥;

以上缺點(diǎn)可以使用動(dòng)態(tài)代理來(lái)解決


3 代理模式 模式結(jié)構(gòu)

代理模式的主要角色如下:

  • 抽象主題(Subject)類(lèi):通過(guò)接口或抽象類(lèi)聲明真實(shí)主題和代理對(duì)象實(shí)現(xiàn)的業(yè)務(wù)方法后室。
  • 真實(shí)主題(Real Subject)類(lèi):實(shí)現(xiàn)了抽象主題中的具體業(yè)務(wù),是代理對(duì)象所代表的真實(shí)對(duì)象混狠,是最終要引用的對(duì)象岸霹。
  • 代理(Proxy)類(lèi):提供了與真實(shí)主題相同的接口,其內(nèi)部含有對(duì)真實(shí)主題的引用檀蹋,它可以訪問(wèn)松申、控制或擴(kuò)展真實(shí)主題的功能。
4 靜態(tài)代理 代碼實(shí)現(xiàn)
package com.test.proxy;

public interface Target {

    public String execute();
}

package com.test.proxy;

public class TargetImpl implements Target {

    @Override
    public String execute() {
        System.out.println("TargetImpl execute俯逾!");
        return "execute";
    }
}
package com.test.proxy;

public class Proxy implements Target{

    private Target target;

    public Proxy(Target target) {
        this.target = target;
    }

    @Override
    public String execute() {
        System.out.println("perProcess");
        String result = this.target.execute();
        System.out.println("postProcess");
        return result;
    }
}


package com.test.proxy;

public class ProxyTest {
    public static void main(String[] args) {

        Target target = new TargetImpl();
        Proxy p = new Proxy(target);
        String result =  p.execute();
        System.out.println(result);
    }

}

總結(jié):由我們創(chuàng)建代理類(lèi)或特定工具自動(dòng)生成源代碼再對(duì)其編譯贸桶,在程序運(yùn)行前代理類(lèi)的 .class 文件就已經(jīng)存在了。

5 動(dòng)態(tài)代理 代碼實(shí)現(xiàn)
package com.agency.staticproxy;


import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class App {
    public static void main(String[] args) {
        // 目標(biāo)對(duì)象
//        IUserDao target = new UserDao();
        MemberServiceImpl target = new MemberServiceImpl();
        // 【原始的類(lèi)型 class cn.itcast.b_dynamic.UserDao】
        System.out.println(target.getClass());

        // 給目標(biāo)對(duì)象桌肴,創(chuàng)建代理對(duì)象
        MemberService memberService = (MemberService) new ProxyFactory(target).getProxyInstance();

        // class $Proxy0   內(nèi)存中動(dòng)態(tài)生成的代理對(duì)象
        System.out.println(memberService.getClass());

        // 執(zhí)行方法   【代理對(duì)象】
        memberService.getUserById();
    }
}

class ProxyFactory{

    //維護(hù)一個(gè)目標(biāo)對(duì)象
    private Object target;

    public ProxyFactory(Object target){
        this.target=target;
    }

    //給目標(biāo)對(duì)象生成代理對(duì)象
    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("12222");
                        //執(zhí)行目標(biāo)對(duì)象方法
                        Object returnValue = method.invoke(target, args);
                        String name = method.getName();
                        System.out.println("233333");
                        return returnValue;
                    }
                }
        );

    }

}

class MemberServiceImpl implements MemberService {

    @Override
    public void getUserById() {
        System.out.println(123);
    }
}

interface MemberService {
    void getUserById();
}

總結(jié):在程序運(yùn)行時(shí)皇筛,運(yùn)用反射機(jī)制動(dòng)態(tài)創(chuàng)建而成。

0.根據(jù)所傳入的參數(shù)生成一個(gè)代理類(lèi)
1.代理類(lèi)實(shí)現(xiàn)了相關(guān)接口坠七,繼承了Proxy水醋,其構(gòu)造函數(shù)是有參構(gòu)造旗笔,傳入一個(gè)InvocationHandler。
2.所以拄踪,其使用代理類(lèi)蝇恶,調(diào)用方法,都會(huì)先調(diào)用InvocationHandler中的invoke方法惶桐,
3.至于要不要調(diào)用代理類(lèi)的方法撮弧,需要看,在invoke中是否調(diào)用了method.invoke(target, args)姚糊。

6 CGLIB代理 代碼實(shí)現(xiàn)
package com.agency.cglib;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

public class CglibTest {

    public static void main(String[] args) {
        System.out.println("***************");
        Target target = new Target();
        CglibTest test = new CglibTest();
        Target proxyTarget = (Target) test.createProxy(Target.class);
        String res = proxyTarget.execute();
        System.out.println(res);
    }

    public Object createProxy(Class targetClass) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(targetClass);
        enhancer.setCallback(new MyMethodInterceptor());
        return enhancer.create();
    }

}

class MyMethodInterceptor implements MethodInterceptor {

    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        System.out.println(">>>>MethodInterceptor start...");
        Object result = proxy.invokeSuper(obj,args);
        System.out.println(">>>>MethodInterceptor ending...");
        return "result";
    }
}

class Target {

    public String execute() {
        String message = "-----------test------------";
        System.out.println(message);
        return message;
    }
}

總結(jié):CGLib采用了非常底層的字節(jié)碼技術(shù)贿衍,其原理是通過(guò)字節(jié)碼技術(shù)為一個(gè)類(lèi)創(chuàng)建子類(lèi),
并在子類(lèi)中采用方法攔截的技術(shù)攔截所有父類(lèi)方法的調(diào)用救恨,
順勢(shì)織入橫切邏輯贸辈。JDK動(dòng)態(tài)代理與CGLib動(dòng)態(tài)代理均是實(shí)現(xiàn)Spring AOP的基礎(chǔ)。


不要以為每天把功能完成了就行了肠槽,這種思想是要不得的擎淤,互勉~!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末署浩,一起剝皮案震驚了整個(gè)濱河市揉燃,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌筋栋,老刑警劉巖炊汤,帶你破解...
    沈念sama閱讀 210,978評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異弊攘,居然都是意外死亡抢腐,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,954評(píng)論 2 384
  • 文/潘曉璐 我一進(jìn)店門(mén)襟交,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)迈倍,“玉大人,你說(shuō)我怎么就攤上這事捣域√淙荆” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 156,623評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵焕梅,是天一觀的道長(zhǎng)迹鹅。 經(jīng)常有香客問(wèn)我,道長(zhǎng)贞言,這世上最難降的妖魔是什么斜棚? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,324評(píng)論 1 282
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上弟蚀,老公的妹妹穿的比我還像新娘蚤霞。我一直安慰自己,他們只是感情好义钉,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,390評(píng)論 5 384
  • 文/花漫 我一把揭開(kāi)白布昧绣。 她就那樣靜靜地躺著,像睡著了一般断医。 火紅的嫁衣襯著肌膚如雪滞乙。 梳的紋絲不亂的頭發(fā)上奏纪,一...
    開(kāi)封第一講書(shū)人閱讀 49,741評(píng)論 1 289
  • 那天鉴嗤,我揣著相機(jī)與錄音,去河邊找鬼序调。 笑死醉锅,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的发绢。 我是一名探鬼主播硬耍,決...
    沈念sama閱讀 38,892評(píng)論 3 405
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼边酒!你這毒婦竟也來(lái)了经柴?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,655評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤墩朦,失蹤者是張志新(化名)和其女友劉穎坯认,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體氓涣,經(jīng)...
    沈念sama閱讀 44,104評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡牛哺,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,451評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了劳吠。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片引润。...
    茶點(diǎn)故事閱讀 38,569評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖痒玩,靈堂內(nèi)的尸體忽然破棺而出淳附,到底是詐尸還是另有隱情,我是刑警寧澤蠢古,帶...
    沈念sama閱讀 34,254評(píng)論 4 328
  • 正文 年R本政府宣布奴曙,位于F島的核電站,受9級(jí)特大地震影響便瑟,放射性物質(zhì)發(fā)生泄漏缆毁。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,834評(píng)論 3 312
  • 文/蒙蒙 一到涂、第九天 我趴在偏房一處隱蔽的房頂上張望脊框。 院中可真熱鬧颁督,春花似錦、人聲如沸浇雹。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,725評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)昭灵。三九已至吠裆,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間烂完,已是汗流浹背试疙。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,950評(píng)論 1 264
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留抠蚣,地道東北人祝旷。 一個(gè)月前我還...
    沈念sama閱讀 46,260評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像嘶窄,于是被迫代替她去往敵國(guó)和親怀跛。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,446評(píng)論 2 348