代理模式(靜態(tài)代理模式與JDK自帶的動態(tài)代理模式)

介紹

在代理模式(Proxy Pattern)中,一個類代表另一個類的功能。這種類型的設(shè)計模式屬于結(jié)構(gòu)型模式簸呈。

在代理模式中,我們創(chuàng)建具有現(xiàn)有對象的對象店茶,以便向外界提供功能接口蜕便。

意圖

為其他對象提供一種代理以控制對這個對象的訪問
在直接訪問對象時帶來的問題,比如說:要訪問的對象在遠程的機器上忽妒。在面向?qū)ο笙到y(tǒng)中玩裙,有些對象由于某些原因(比如對象創(chuàng)建開銷很大,或者某些操作需要安全控制段直,或者需要進程外的訪問),直接訪問會給使用者或者系統(tǒng)結(jié)構(gòu)帶來很多麻煩溶诞,我們可以在訪問此對象時加上一個對此對象的訪問層鸯檬。

主要角色

  • 委托類:實現(xiàn)抽象角色,定義真實角色所要實現(xiàn)的業(yè)務(wù)邏輯螺垢,供代理角色調(diào)用喧务。
  • 代理類:實現(xiàn)抽象角色,是真實角色的代理枉圃,通過真實角色的業(yè)務(wù)邏輯方法來實現(xiàn)抽象方法功茴,并可以附加自己的操作。
  • 抽象角色:通過接口或抽象類聲明真實角色實現(xiàn)的業(yè)務(wù)方法孽亲。

優(yōu)點

1.職責清晰2.易擴展

缺點

1.由于在客戶端和真實主題之間增加了代理對象坎穿,因此有些類型的代理模式可能會造成請求的處理速度變慢。 2.實現(xiàn)代理模式需要額外的工作返劲,有些代理模式的實現(xiàn)非常復(fù)雜玲昧。


image.png

代碼示例

抽象角色:OrderService接口,規(guī)范了委托類實現(xiàn)的業(yè)務(wù)方法

public interface OrderService {
    
    /*
     * 創(chuàng)建訂單
     */
    boolean createOrder();
    
    /*
     * 查找訂單
     */
    List listOrder();
    
    /*
     * 刪除訂單
     */
    boolean removeOrder();
}

委托類:OrderServiceImpl類,訂單業(yè)務(wù)實現(xiàn)類

package com.apesource.service.impl;

import java.util.Arrays;
import java.util.List;
import java.util.logging.Logger;

import com.apesource.service.OrderService;

/*
 * 訂單業(yè)務(wù)服務(wù)類
 */
public class OrderServiceImpl implements OrderService{

    //
    @Override
    public boolean createOrder() {

        System.out.println("A.創(chuàng)建訂單業(yè)務(wù)步驟1");
        System.out.println("B.創(chuàng)建訂單業(yè)務(wù)步驟2");
        System.out.println("C.創(chuàng)建訂單業(yè)務(wù)步驟3");
        System.out.println("D.創(chuàng)建訂單業(yè)務(wù)步驟4");
        System.out.println("E.創(chuàng)建訂單業(yè)務(wù)步驟5");
        
        return true;
        
    }

    @Override
    public List listOrder() {
        System.out.println("A.查找訂單業(yè)務(wù)步驟1");
        System.out.println("B.查找訂單業(yè)務(wù)步驟2");
        System.out.println("C.查找訂單業(yè)務(wù)步驟3");
        return Arrays.asList();
    }

    @Override
    public boolean removeOrder() {
        System.out.println("A.刪除訂單業(yè)務(wù)步驟1");
        System.out.println("B.刪除訂單業(yè)務(wù)步驟2");
        System.out.println("C.刪除訂單業(yè)務(wù)步驟3");
        return true;
    }
    
}

代理類:添加程序日志,調(diào)用委托類中的方法

package com.apesource.service.proxy;

import java.util.List;
import java.util.logging.Logger;
import com.apesource.service.OrderService;
import com.apesource.service.impl.OrderServiceImpl;

/*
 * 代理類
 */
public class OrderSercviceImplProxy implements OrderService {
    // 添加日志
    private static Logger log = Logger.getLogger(OrderServiceImpl.class.getName());
    // 關(guān)聯(lián)目標類
    private OrderService orderServiceImpl;

    public OrderSercviceImplProxy() {
        // 實例化目標列對象
        orderServiceImpl = new OrderServiceImpl();
    }

    @Override
    public boolean createOrder() {
        // 添加日志
        log.info("開始執(zhí)行創(chuàng)建訂單業(yè)務(wù)");
        // 調(diào)用目標類的方法
        boolean bool = orderServiceImpl.createOrder();
        // 添加日志
        log.info("結(jié)束執(zhí)行創(chuàng)建訂單業(yè)務(wù)");
        return bool;

    }

    @Override
    public List listOrder() {
        // 添加日志
        log.info("開始執(zhí)行返回訂單業(yè)務(wù)");
        List list = orderServiceImpl.listOrder();
        // 添加日志
        log.info("結(jié)束執(zhí)行返回訂單業(yè)務(wù)");
        return list;
    }

    @Override
    public boolean removeOrder() {
        // 添加日志
        log.info("開始執(zhí)行刪除訂單業(yè)務(wù)");
        Boolean bool = orderServiceImpl.removeOrder();
        // 添加日志
        log.info("結(jié)束執(zhí)行刪除訂單業(yè)務(wù)");
        return bool;
    }

}

JDK自帶的動態(tài)代理

無論是動態(tài)代理還是靜態(tài)代理都需要三個角色:目標對象,接口篮绿,代理類孵延。動態(tài)代理主要使用了反射中的知識。
JDK中:

  • java.lang.reflect.InvocationHandler(處理器接口):可以通過invoke方法實現(xiàn)對真實角色的代理訪問亲配。

創(chuàng)建一個類并實現(xiàn)InvocationHandler接口尘应,在invoke方法中實現(xiàn)代理類的操作以及調(diào)用目標對象的方法惶凝。因此要先關(guān)聯(lián)目標對象并通過構(gòu)造方法注入目標對象

//與目標對象關(guān)聯(lián)
    private Object target;
    // 通過構(gòu)造方法得到目標對象
    public LogInvocationHander(Object target) {
        this.target = target;
    }

InvocationHandler接口中的invoke方法

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

Object proxy:Proxy創(chuàng)建的代理對象
Method method: 將執(zhí)行的方法方法對象
Object[] args:將執(zhí)行方法的參數(shù)列表

  • java.lang.reflect.Proxy類,通過newProxyInstance方法生成動態(tài)代理類和對象犬钢;它的類型是com.sun.proxy.$Proxy
    Proxy.newProxyInstance(類加載器梨睁,目標對象實現(xiàn)的所有接口,實現(xiàn)InvocationHander接口類的對象)
    通過反射方式獲取類加載器娜饵,目標對象Class獲取所有接口對象Class
Proxy.newProxyInstance(
                orderServiceTarget.getClass().getClassLoader(), orderServiceTarget.getClass().getInterfaces(),
                logInvocationHander1);
代碼示例

實現(xiàn)InvocationHandler的 LogInvocationHander類坡贺,添加日志并調(diào)用目標類中的方法。

package com.apesource.service.proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.logging.Logger;

/*
 * *代理類的執(zhí)行過程
 * *需要得到目標對象
 */
public class LogInvocationHander implements InvocationHandler {
    //與目標對象關(guān)聯(lián)
    private Object target;
    private static Logger logger = Logger.getLogger(LogInvocationHander.class.getName());
    // 通過構(gòu)造方法得到目標對象
    public LogInvocationHander(Object target) {
        this.target = target;
    }

    /*
     * *運行時得到代理對象,方法對象
     */
    /*
     * *參數(shù)1:代理的對象 *參數(shù)2:運行期要執(zhí)行的方法的對象,代理和目標的方法名相同 *參數(shù)3:該方法的參數(shù)
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //添加日志
        logger.info("代理"+proxy.getClass().getName());
        logger.info("方法開始");
        Object object = method.invoke(target, args);
        logger.info("方法結(jié)束");
        return object;
    
    }

}

主函數(shù)中創(chuàng)建LogInvocationHander類的對象箱舞,創(chuàng)建Proxy對象遍坟。

package com.apesource.test;

import java.lang.reflect.Proxy;

import com.apesource.service.OrderService;
import com.apesource.service.PaymentService;
import com.apesource.service.impl.OrderServiceImpl;
import com.apesource.service.impl.PaymentServiceImpl;
import com.apesource.service.proxy.LogInvocationHander;

public class Test01 {
    public static void main(String[] args) {
        // 創(chuàng)建目標對象
        // 訂單的目標對象
        OrderService orderServiceTarget = new OrderServiceImpl();
        // 支付的目標對象
        PaymentService paymentServiceTarget = new PaymentServiceImpl();
        // 將目標對象傳入LogInvocationHander,LogInvocationHander是代理真正執(zhí)行的邏輯
        LogInvocationHander logInvocationHander1 = new LogInvocationHander(orderServiceTarget);
        LogInvocationHander logInvocationHander2 = new LogInvocationHander(paymentServiceTarget);
        // 創(chuàng)建代理
        /*
         * 參數(shù)1:類加載器 參數(shù)2:代理要實現(xiàn)的所有接口,也就是目標對象實現(xiàn)的接口 參數(shù)3:LogInvocationHander,真正執(zhí)行的邏輯
         */
        // 通過傳入的類加載器,通過反射的方式,獲取目標類接口數(shù)組,創(chuàng)建出代理對象,通過類型轉(zhuǎn)換為OrderService
        OrderService orderServiceProxy = (OrderService) Proxy.newProxyInstance(
                orderServiceTarget.getClass().getClassLoader(), orderServiceTarget.getClass().getInterfaces(),
                logInvocationHander1);
        //調(diào)用的方法,其實調(diào)用了invoke方法晴股,logInvocationHander1中的Method對象
        orderServiceProxy.createOrder();
        PaymentService paymentServiceproxy = (PaymentService) Proxy.newProxyInstance(
                paymentServiceTarget.getClass().getClassLoader(), paymentServiceTarget.getClass().getInterfaces(),
                logInvocationHander2);
        paymentServiceproxy.aliPay();

    }
}


最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末愿伴,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子电湘,更是在濱河造成了極大的恐慌隔节,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,265評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件寂呛,死亡現(xiàn)場離奇詭異怎诫,居然都是意外死亡,警方通過查閱死者的電腦和手機贷痪,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,078評論 2 385
  • 文/潘曉璐 我一進店門幻妓,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人劫拢,你說我怎么就攤上這事肉津。” “怎么了舱沧?”我有些...
    開封第一講書人閱讀 156,852評論 0 347
  • 文/不壞的土叔 我叫張陵妹沙,是天一觀的道長。 經(jīng)常有香客問我熟吏,道長距糖,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,408評論 1 283
  • 正文 為了忘掉前任分俯,我火速辦了婚禮肾筐,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘缸剪。我一直安慰自己吗铐,他們只是感情好,可當我...
    茶點故事閱讀 65,445評論 5 384
  • 文/花漫 我一把揭開白布杏节。 她就那樣靜靜地躺著唬渗,像睡著了一般典阵。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上镊逝,一...
    開封第一講書人閱讀 49,772評論 1 290
  • 那天壮啊,我揣著相機與錄音,去河邊找鬼撑蒜。 笑死歹啼,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的座菠。 我是一名探鬼主播狸眼,決...
    沈念sama閱讀 38,921評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼浴滴!你這毒婦竟也來了拓萌?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,688評論 0 266
  • 序言:老撾萬榮一對情侶失蹤升略,失蹤者是張志新(化名)和其女友劉穎微王,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體品嚣,經(jīng)...
    沈念sama閱讀 44,130評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡炕倘,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,467評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了腰根。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片激才。...
    茶點故事閱讀 38,617評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖额嘿,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情劣挫,我是刑警寧澤册养,帶...
    沈念sama閱讀 34,276評論 4 329
  • 正文 年R本政府宣布,位于F島的核電站压固,受9級特大地震影響球拦,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜帐我,卻給世界環(huán)境...
    茶點故事閱讀 39,882評論 3 312
  • 文/蒙蒙 一坎炼、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧拦键,春花似錦谣光、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,740評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽蟀悦。三九已至,卻和暖如春氧敢,著一層夾襖步出監(jiān)牢的瞬間日戈,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,967評論 1 265
  • 我被黑心中介騙來泰國打工孙乖, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留浙炼,地道東北人。 一個月前我還...
    沈念sama閱讀 46,315評論 2 360
  • 正文 我出身青樓唯袄,卻偏偏與公主長得像弯屈,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子越妈,可洞房花燭夜當晚...
    茶點故事閱讀 43,486評論 2 348