代理模式

代理模式:有時睹耐,一個對象不適合或者不能直接引用另一個對象辐赞,而代理對象可以在客戶端和目標對象之間起到中介的作用。代理可以靜默的解決一些業(yè)務無關的問題硝训,比如遠程响委、安全、事務窖梁、日志赘风、資源關閉等,而開發(fā)者只關心他的業(yè)務實現(xiàn)纵刘。比如一個復雜的業(yè)務操作可能需要好幾個方法來完成邀窃,但是我們可以用一個總的方法來依次調(diào)用這幾個方法即可,這個方法代理了真正的實現(xiàn)假哎。

void sum(){
  int a = method1();
  String b = method2();
  ...
}

int method1(){
  // 執(zhí)行業(yè)務1
  return 10;
}

String method2(int a){
  // 執(zhí)行業(yè)務2
  return 'AA;
}

一般形式為一個類代表另一個類的功能瞬捕。

比如老板,秘書舵抹,員工肪虎。老板比較忙,平時員工是見不到的惧蛹,就把審批等請求給秘書笋轨,然后秘書再找老板處理秆剪,處理完畢后交給員工。

如新員工要轉(zhuǎn)正爵政,需要老板批準仅讽,但是老板很忙,只負責查看評語然后做出批復钾挟。但是老板的秘書可以去找新員工的直接領導了解員工表現(xiàn)洁灵,整理直接領導對員工的評語。然后加上評語和新員工轉(zhuǎn)正申請掺出,一起給老板徽千。老板同意之后,給予新員工答復汤锨,同時秘書會把轉(zhuǎn)正申請歸檔双抽。這就可以在老板批復的動作前后增加工作,增強這個事件闲礼。

實際工作中牍汹,真正的實現(xiàn)類,只負責處理核心業(yè)務邏輯柬泽,然后代理類就可以在核心方法調(diào)用前后慎菲,做增強工作。比如記錄日志锨并,監(jiān)控性能露该,安全檢查等。

image.jpeg
image.png

優(yōu)點:

  • 職責清晰
  • 代理對象作為中介第煮,保護了目標對象
  • 高擴展性

組成結構:

  • 抽象角色:通過接口或抽象類聲明真是角色實現(xiàn)的業(yè)務方法
  • 代理角色:實現(xiàn)抽象接口解幼,在自己的實現(xiàn)方法中調(diào)用真實角色對應的方法
  • 真實角色:實現(xiàn)抽象接口,真正業(yè)務邏輯

代理模式又分為靜態(tài)代理和動態(tài)代理
1)靜態(tài)代理 :就是普通的編碼包警,已經(jīng)寫好了书幕。
2)動態(tài)代理:在運行階段創(chuàng)建

在不改變原有實現(xiàn)的基礎上,實現(xiàn)如下的功能

  • 日志記錄
  • 權限控制
  • 事務處理

靜態(tài)代理

靜態(tài)代理就是我們平時寫的代碼揽趾,比如有一個真正實現(xiàn)的類A台汇,但是客戶端不去直接調(diào)用A,而是通過B這個類篱瞎,然后B再調(diào)用A苟呐。比如spring MVC中,要插入一條數(shù)據(jù)俐筋。首先是控制器調(diào)用服務層牵素,然后服務層再去調(diào)用DAO層,數(shù)據(jù)在DAO層真正插入數(shù)據(jù)庫澄者。服務層就是一個代理笆呆,并且可以在服務層做一些特殊處理请琳,比如數(shù)據(jù)轉(zhuǎn)換等。

public interface Subject {
    /**
     * 簡單測試
     */
    void visit();

    /**
     * 求和
     *
     * @param a
     * @param b
     * @return 求和后的值
     */
    int sum(int a, int b);


    /**
     * 返回當前名稱
     *
     * @return
     */
    String getName();

    /***
     * 問候
     * @param name
     */
    void greeting(String name);
}
public class RealSubject implements Subject {

    private String name = "真正的實現(xiàn)類";

    @Override
    public void visit() {
        System.out.println(name);
    }

    @Override
    public int sum(int a, int b) {
        return a + b;
    }

    @Override
    public String getName() {
        return "我是真正的實現(xiàn)";
    }

    @Override
    public void greeting(String name) {
        System.out.println("Hello " + name);
    }
}

public class ProxySubject implements Subject {

    private Subject subject;

    public ProxySubject(Subject subject) {
        this.subject = subject;
    }

    @Override
    public void visit() {
        this.subject.visit();
    }

    @Override
    public int sum(int a, int b) {
        return this.subject.sum(a, b);
    }

    @Override
    public String getName() {
        return this.subject.getName();
    }

    @Override
    public void greeting(String name) {
        this.subject.greeting(name);
    }
}

public class Client {

    public static void main(String[] args) {
        ProxySubject proxySubject = new ProxySubject(new RealSubject());
        proxySubject.visit();
        System.out.println(proxySubject.getName());
        proxySubject.greeting("詹姆斯");
        int result = proxySubject.sum(1, 2);
        System.out.println(result);
    }
}

動態(tài)代理

為什么要有動態(tài)代理赠幕?

  • 代理類需要有和真實實現(xiàn)類一樣有所有的方法實現(xiàn)俄精,當方法較多時,好多重復性的榕堰,機械的工作竖慧。代碼相似冗余,不易維護
  • 一般一個實現(xiàn)類需要關聯(lián)一個代理類逆屡。
  • 每當一個新的類實現(xiàn)接口圾旨,就需要創(chuàng)建對應的代理類

動態(tài)代理的本質(zhì)就是在運行時 動態(tài) 的生成一個新類。前提是需要有一個接口魏蔗。為什么呢砍的?因為這個新生成的類要有和目標類一樣的功能。通過接口可以保證目標類必須包含那些方法莺治。

具體實現(xiàn)手段是反射廓鞠,通過Method的調(diào)用和InvocationHandler

目前實現(xiàn)動態(tài)代理的方式有jdk Proxy和cglib,其中jdk自身實現(xiàn)有如下優(yōu)點:

  • 親兒子产雹,本身就支持诫惭,不存在依賴問題和第三方版本問題
  • 代碼實現(xiàn)簡單

這二種的本質(zhì)區(qū)別是翁锡,jdk需要一個接口蔓挖,然后根據(jù)這個接口來在運行時-運行時-運行時動態(tài)-動態(tài)-動態(tài)的生成一個代理類出來,而cglib是創(chuàng)建一個目標類的子類馆衔,因此目標類的關鍵方法不能聲明為final瘟判。

組成結構:

  • 接口對象
  • 具體實現(xiàn)類
  • 實現(xiàn)InvocationHandler的通用類
public class AnimalJdkDynamicProxy implements InvocationHandler {

    /**
     *  01.我們不確定委托類是誰?委托類的類型 是Object
     *   和委托類建立關聯(lián)關系
     */
    private Object target;


    /**
     * 02.給我一個委托類角溃,我返回一個代理類對象
     */
    public Object createProxy(Object target){
        //根據(jù)傳遞的參數(shù) 進行對象的關聯(lián)
        this.target=target;
        return Proxy.newProxyInstance(target.getClass().getClassLoader(),
                target.getClass().getInterfaces(), this);
    }

    /**
     *
     * @param proxy :代理對象
     * @param method :方法名
     * @param args : 參數(shù)列表
     * @return
     */
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("主人在召喚"); //系統(tǒng)級業(yè)務   開始事務
        Object result= method.invoke(target,args);  // 主業(yè)務
        System.out.println("主人離開"); //系統(tǒng)級業(yè)務     日志處理  關閉事務
        return result;
    }


    //創(chuàng)建測試方法
    public static void main(String[] args) {
        AnimalJdkDynamicProxy proxy=new AnimalJdkDynamicProxy();
        Animal dog= (Animal) proxy.createProxy(new Dog());
        dog.eat();
        System.out.println("**************************");
        dog.sleep();

    }
}

動態(tài)代理一般用在什么地方拷获?主要用于各種通用框架中,平時實際項目中用到的可能不多减细。

?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末匆瓜,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子未蝌,更是在濱河造成了極大的恐慌驮吱,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,386評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件萧吠,死亡現(xiàn)場離奇詭異左冬,居然都是意外死亡,警方通過查閱死者的電腦和手機纸型,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,142評論 3 394
  • 文/潘曉璐 我一進店門拇砰,熙熙樓的掌柜王于貴愁眉苦臉地迎上來梅忌,“玉大人,你說我怎么就攤上這事除破∧恋” “怎么了?”我有些...
    開封第一講書人閱讀 164,704評論 0 353
  • 文/不壞的土叔 我叫張陵皂岔,是天一觀的道長蹋笼。 經(jīng)常有香客問我,道長躁垛,這世上最難降的妖魔是什么剖毯? 我笑而不...
    開封第一講書人閱讀 58,702評論 1 294
  • 正文 為了忘掉前任,我火速辦了婚禮教馆,結果婚禮上逊谋,老公的妹妹穿的比我還像新娘。我一直安慰自己土铺,他們只是感情好胶滋,可當我...
    茶點故事閱讀 67,716評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著悲敷,像睡著了一般究恤。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上后德,一...
    開封第一講書人閱讀 51,573評論 1 305
  • 那天部宿,我揣著相機與錄音,去河邊找鬼瓢湃。 笑死理张,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的绵患。 我是一名探鬼主播雾叭,決...
    沈念sama閱讀 40,314評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼落蝙!你這毒婦竟也來了织狐?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,230評論 0 276
  • 序言:老撾萬榮一對情侶失蹤筏勒,失蹤者是張志新(化名)和其女友劉穎移迫,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體奏寨,經(jīng)...
    沈念sama閱讀 45,680評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡起意,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,873評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了病瞳。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片揽咕。...
    茶點故事閱讀 39,991評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡悲酷,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出亲善,到底是詐尸還是另有隱情设易,我是刑警寧澤,帶...
    沈念sama閱讀 35,706評論 5 346
  • 正文 年R本政府宣布蛹头,位于F島的核電站顿肺,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏渣蜗。R本人自食惡果不足惜屠尊,卻給世界環(huán)境...
    茶點故事閱讀 41,329評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望耕拷。 院中可真熱鬧讼昆,春花似錦、人聲如沸骚烧。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,910評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽赃绊。三九已至既峡,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間碧查,已是汗流浹背运敢。 一陣腳步聲響...
    開封第一講書人閱讀 33,038評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留么夫,地道東北人者冤。 一個月前我還...
    沈念sama閱讀 48,158評論 3 370
  • 正文 我出身青樓肤视,卻偏偏與公主長得像档痪,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子邢滑,可洞房花燭夜當晚...
    茶點故事閱讀 44,941評論 2 355

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