<kbd id="5sdj3"></kbd>
<th id="5sdj3"></th>

  • <dd id="5sdj3"><form id="5sdj3"></form></dd>
    <td id="5sdj3"><form id="5sdj3"><big id="5sdj3"></big></form></td><del id="5sdj3"></del>

  • <dd id="5sdj3"></dd>
    <dfn id="5sdj3"></dfn>
  • <th id="5sdj3"></th>
    <tfoot id="5sdj3"><menuitem id="5sdj3"></menuitem></tfoot>

  • <td id="5sdj3"><form id="5sdj3"><menu id="5sdj3"></menu></form></td>
  • <kbd id="5sdj3"><form id="5sdj3"></form></kbd>

    代理模式,拿下?。?!

    共 9382字,需瀏覽 19分鐘

     ·

    2021-09-12 13:38

    代理模式是給一個(gè)對(duì)象提供一個(gè)代理對(duì)象,并由代理對(duì)象控制對(duì)原對(duì)象的引用。

    通俗來(lái)講,代理模式就是我們所熟知的中介。

    以我們熟知的商品代購(gòu)為例:

    商品代購(gòu)

    假如我們需要買一個(gè)物品,我們可以直接去工廠里購(gòu)買;也可以找代購(gòu)。

    如果直接去工廠購(gòu)買,我們?cè)谫?gòu)買前需要對(duì)自己要買的物品做一些調(diào)研,然后去工廠直接去提貨,這樣什么事情都需要自己親力親為。

    如果我們通過(guò)代購(gòu)購(gòu)買,我們只需要告訴代購(gòu)我們需要什么,剩下的事情代購(gòu)會(huì)幫我們處理(調(diào)研、拿貨),最終給我們需要的相應(yīng)的物品。

    因此,代理模式的目標(biāo)如下:

    (1)通過(guò)引用代理對(duì)象的方式來(lái)間接訪問(wèn)目標(biāo)對(duì)象,防止直接訪問(wèn)目標(biāo)對(duì)象給系統(tǒng)帶來(lái)不必要的復(fù)雜性。

    (2)通過(guò)代理對(duì)象對(duì)原有的業(yè)務(wù)進(jìn)行增強(qiáng)。

    通常情況下,按照代理的創(chuàng)建時(shí)期,一般可以分為兩種:

    • 靜態(tài)代理

    靜態(tài)代理是由程序員或者特定的工具自動(dòng)生成的源代碼,再對(duì)其編譯,在程序運(yùn)行之前,代理類編譯的生成的.class文件就已經(jīng)存在了

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

    動(dòng)態(tài)代理是在程序運(yùn)行時(shí),通過(guò)反射機(jī)制動(dòng)態(tài)創(chuàng)建而成。

    1、靜態(tài)代理模式

    靜態(tài)代理中的代理類和委托類的關(guān)系在運(yùn)行前就確定了,如圖所示:

    靜態(tài)代理

    特別注意幾個(gè)概念:

    • 抽象對(duì)象

    抽象對(duì)象聲明了真實(shí)對(duì)象和代理對(duì)象的公共接口。

    • 真實(shí)對(duì)象

    代理對(duì)象所代表的真實(shí)對(duì)象,最終被引用的對(duì)象

    • 代理對(duì)象

    包含真實(shí)對(duì)象進(jìn)而操作真實(shí)對(duì)象,相當(dāng)于訪問(wèn)者與真實(shí)對(duì)象直接的中介。

    下面,我們來(lái)舉個(gè)例子:

    (1)創(chuàng)建服務(wù)類接口

    public interface BuyCar {
        void buycar();
    }

    (2)服務(wù)實(shí)現(xiàn)類

    public class BuyCarImpl implements BuyCar{
        public void buycar() {
            System.out.println("買一輛奧迪");
        }
    }

    (3)創(chuàng)建代理類

    public class BuyCarProxy implements BuyCar{
        
        private BuyCar buyCar;

        public BuyCarProxy(BuyCar buyCar){
            this.buyCar = buyCar;
        }
        public void buycar() {
            System.out.println("買車前的調(diào)研......");
            buyCar.buycar();
            System.out.println("買車后的保養(yǎng)......");


        }
    }

    (4)編寫測(cè)試類

    public class ProxyTest {
        public static void main(String[] args) {
            BuyCarImpl buyCar = new BuyCarImpl();
            BuyCarProxy buyCarProxy = new BuyCarProxy(buyCar);
            buyCarProxy.buycar();
        }
    }

    優(yōu)點(diǎn):靜態(tài)代理在不修改目標(biāo)對(duì)象的前提下,可以通過(guò)代理對(duì)象對(duì)目標(biāo)對(duì)象進(jìn)行擴(kuò)展。

    代理類可以使得客戶端不需要知道具體的實(shí)現(xiàn)類是什么,怎么做的,客戶端只需知道代理即可(解耦合)

    缺點(diǎn):代理類和具體的實(shí)現(xiàn)類實(shí)現(xiàn)了相同的接口,代理類通過(guò)實(shí)現(xiàn)類實(shí)現(xiàn)了相同的方法。這樣就出現(xiàn)了大量的代碼重復(fù)。如果接口增加一個(gè)方法,除了所有實(shí)現(xiàn)類需要實(shí)現(xiàn)這個(gè)方法外,所有代理類也需要實(shí)現(xiàn)此方法。增加了代碼維護(hù)的復(fù)雜度。

    代理對(duì)象只服務(wù)于一種類型的對(duì)象,如果要服務(wù)多類型的對(duì)象。勢(shì)必要為每一種對(duì)象都進(jìn)行代理,靜態(tài)代理在程序規(guī)模稍大時(shí)就無(wú)法勝任了。

    2、動(dòng)態(tài)代理模式

    2.1 JDK自帶

    事實(shí)上,單一的代理是不存的,一個(gè)代理可以同時(shí)身兼數(shù)職。既可以代購(gòu)車,也可以代購(gòu)房。

    在動(dòng)態(tài)代理中我們不再需要手動(dòng)的創(chuàng)建代理類,我們只需要一個(gè)動(dòng)態(tài)處理器就可以了,而真正的代理對(duì)象由JDK運(yùn)行時(shí)動(dòng)態(tài)的創(chuàng)建。

    (1)創(chuàng)建服務(wù)類接口

    //買車接口
    public interface BuyCar {
        void buycar();
    }
    //買房接口
    public interface BuyHouse {
        void buyHouse();
    }

    (2)服務(wù)實(shí)現(xiàn)類

    //買車接口的實(shí)現(xiàn)類
    public class BuyCarImpl implements BuyCar {
        public void buycar() {
            System.out.println("買一輛奧迪");
        }
    }
    //買房接口的實(shí)現(xiàn)類
    public class BuyHouseImpl implements BuyHouse{
        public void buyHouse() {
            System.out.println("買一棟大別墅");
        }
    }

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

    //通過(guò)實(shí)現(xiàn) InvocationHandler 接口創(chuàng)建自己的調(diào)用處理器;
    public class ProxyHandler implements InvocationHandler {

        private Object object;
        //通過(guò)構(gòu)造函數(shù)創(chuàng)建動(dòng)態(tài)代理類實(shí)例,構(gòu)造時(shí)調(diào)用處理器對(duì)象作為參數(shù)被傳入。
        public ProxyHandler(Object object){
            this.object = object;
        }

        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("Before invoke "+method.getName());
            method.invoke(object,args);
            System.out.println("After invoke "+method.getName());
            return null;
        }
    }

    (4)測(cè)試類

    public class DynamicProxyTest {
        public static void main(String[] args){
            BuyHouse buyHouse = new BuyHouseImpl();
            BuyCar buyCar = new BuyCarImpl();

            InvocationHandler handler = new ProxyHandler(buyHouse);
            InvocationHandler handler1 = new ProxyHandler(buyCar);

            /**
             * 通過(guò)為 Proxy 類指定 ClassLoader 對(duì)象和一組 interface 來(lái)創(chuàng)建動(dòng)態(tài)代理類;
             */

            BuyHouse proxyHouse = (BuyHouse) Proxy.newProxyInstance(buyHouse.getClass().getClassLoader(), buyHouse.getClass().getInterfaces(),handler);
            BuyCar proxyCar = (BuyCar) Proxy.newProxyInstance(buyCar.getClass().getClassLoader(), buyCar.getClass().getInterfaces(),handler1);
            proxyHouse.buyHouse();
            proxyCar.buycar();
            
        }
    }

    注意Proxy.newProxyInstance()方法接受三個(gè)參數(shù):

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

    • ClassLoader loader:指定當(dāng)前目標(biāo)對(duì)象使用類加載器,獲取加載器的方法是固定的
    • Class<?>[] interfaces:指定目標(biāo)對(duì)象實(shí)現(xiàn)的接口的類型,使用泛型方式確認(rèn)類型
    • InvocationHandler h:指定動(dòng)態(tài)處理器,執(zhí)行目標(biāo)對(duì)象的方法時(shí),會(huì)觸發(fā)事件處理器的方法。

    2.2 CGLIB

    CGLIB相比于JDK動(dòng)態(tài)代理更加強(qiáng)大,JDK動(dòng)態(tài)代理雖然簡(jiǎn)單易用,但是其有一個(gè)致命缺陷是,只能對(duì)接口進(jìn)行代理。如果要代理的類為一個(gè)普通類、沒(méi)有接口,那么Java動(dòng)態(tài)代理就沒(méi)法使用了。

    在使用cglib前,需要先添加依賴。

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

    (1)目標(biāo)類

    • Dao
    public class Dao {
        public void update() {
            System.out.println("PeopleDao.update()");
        }
    }
    • Dao1
    public class Dao1 {
        public void select(){
            System.out.println("PeopleDao.select");
        }
    }

    (2)代理類

    public class DaoProxy implements MethodInterceptor {
        public Object intercept(Object object, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
            System.out.println("Befor Metod Invoke");
            methodProxy.invokeSuper(object,objects);
            System.out.println("After Method Invoke");
            return null;
        }
    }

    參數(shù)解釋:

    • Object表示要進(jìn)行增強(qiáng)的對(duì)象
    • Method表示攔截的方法
    • Object[]數(shù)組表示參數(shù)列表,基本數(shù)據(jù)類型需要傳入其包裝類型,如int-->Integer、long-Long、double-->Double
    • MethodProxy表示對(duì)方法的代理,invokeSuper方法表示對(duì)被代理對(duì)象方法的調(diào)用

    (3)測(cè)試

    public class CglibProxyTest {
        public static void main(String[] args) {
            DaoProxy daoProxy = new DaoProxy();
            Enhancer enhancer = new Enhancer();
            Enhancer enhancer1 = new Enhancer();
      //設(shè)置要繼承的父類
            enhancer.setSuperclass(Dao.class);
            enhancer1.setSuperclass(Dao1.class);
            //設(shè)置回調(diào)方法
            enhancer.setCallback(daoProxy);
            enhancer1.setCallback(daoProxy);

            //創(chuàng)建動(dòng)態(tài)代理類
            Dao dao = (Dao)enhancer.create();
            Dao1 dao1= (Dao1) enhancer1.create();
            dao.update();
            System.out.println("...................................");
            dao1.select();
        }
    }

    公眾號(hào)回復(fù)Java全套、Java架構(gòu)、大數(shù)據(jù)、電子書、算法和刷題筆記、面經(jīng),即可獲得對(duì)應(yīng)的學(xué)習(xí)資源。


    點(diǎn)個(gè)在看你最好看



    瀏覽 56
    點(diǎn)贊
    評(píng)論
    收藏
    分享

    手機(jī)掃一掃分享

    分享
    舉報(bào)
    評(píng)論
    圖片
    表情
    推薦
    點(diǎn)贊
    評(píng)論
    收藏
    分享

    手機(jī)掃一掃分享

    分享
    舉報(bào)

    <kbd id="5sdj3"></kbd>
    <th id="5sdj3"></th>

  • <dd id="5sdj3"><form id="5sdj3"></form></dd>
    <td id="5sdj3"><form id="5sdj3"><big id="5sdj3"></big></form></td><del id="5sdj3"></del>

  • <dd id="5sdj3"></dd>
    <dfn id="5sdj3"></dfn>
  • <th id="5sdj3"></th>
    <tfoot id="5sdj3"><menuitem id="5sdj3"></menuitem></tfoot>

  • <td id="5sdj3"><form id="5sdj3"><menu id="5sdj3"></menu></form></td>
  • <kbd id="5sdj3"><form id="5sdj3"></form></kbd>
    亚洲久久成人 | 亚洲无码三级 | 亚洲人成人无码网www国产 | 99在线视频播放 | 五月天久久激情 |