欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

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

 更新時(shí)間:2014年02月28日 15:02:04   作者:  
本文章要用很土的語(yǔ)言描述Java動(dòng)態(tài)代理,力求更易被理解。Java是JDK5中新加的機(jī)制,大家都知道Spring是用Java的動(dòng)態(tài)代理實(shí)現(xiàn)的,那這個(gè)動(dòng)態(tài)代理是什么東東呢,首先他肯定是個(gè)代理,我們先講代理,把代理弄明白了,動(dòng)態(tài)代理就好說(shuō)了

代理都知道吧,你去買(mǎi)東西就有很多的代理商,他們就是賣(mài)原廠的東西。比如,你天天要買(mǎi)肉,豬是農(nóng)民伯伯養(yǎng)的,但你是從屠夫手上買(mǎi)到肉的,這個(gè)屠夫就可以當(dāng)成是代理。那為什么要代理呢,代理有什么用呢,當(dāng)然是有事給他做了,對(duì)于屠夫這個(gè)代理就好理解了,因?yàn)槟阕约翰豢赡苋ピ棕i吧,所以代理就是去買(mǎi)活豬,然后宰掉再賣(mài)給你,當(dāng)然屠夫有可能給肉注點(diǎn)水,關(guān)鍵看他壞不壞,所以屠夫的整個(gè)流程就是:

這個(gè)流程用代碼怎么實(shí)現(xiàn)呢:我們應(yīng)該要用三個(gè)類You、Butcher、Farmer分別指你、屠夫、農(nóng)民伯伯。其中農(nóng)民伯伯又提供一個(gè)買(mǎi)肉的方法給屠夫調(diào)用,這個(gè)方法輸入是錢(qián)的數(shù)量,返回是肉的數(shù)量,都用int型,代碼如下:

復(fù)制代碼 代碼如下:

class Farmer {
    public int buyMeat(int money) {
        int meat = 0;
        // ... meat = ***;
        return meat;
    }
}

而屠夫則提供一個(gè)買(mǎi)肉的方法給你調(diào)用,同樣是輸入錢(qián),返回肉,但是會(huì)把肉加工一下(殺豬和刮豬毛在代碼中就省了,要不然還得為豬寫(xiě)個(gè)類),代碼如下:

復(fù)制代碼 代碼如下:

class Butcher {
    public int buyMeat(int money) {
        Farmer farmer = new Farmer();            // 1.find a farmer.
        int meat = farmer.buyMeat(money);        // 2.buy meat from the farmer.
        meat += 5;                               // 3.inject 5 pound water into the meat, so weight will increase.
        return meat;                             // 4.return to you.
    }
}

然你從屠夫手上買(mǎi)肉的代碼就變成這樣:

復(fù)制代碼 代碼如下:

class You {
    public void work() {
        int youMoney = 10;
        Butcher butcher = new Butcher();        // find a butcher.
        int meat = butcher.buyMeat(youMoney);
        System.out.println("Cook the meat, weight: " + meat);  // you cooked it. 
    }
}

這個(gè)程序我們還可以優(yōu)化一下,我們發(fā)現(xiàn)屠夫有農(nóng)民有一個(gè)相同的買(mǎi)肉方法,我們可以提取一個(gè)接口,叫為商販(pedlar)吧,以后你買(mǎi)肉就不用管他是屠夫還是農(nóng)民伯伯了,只要他有肉賣(mài)就可以了,我們提取一個(gè)接口后,代碼就變成這樣:

復(fù)制代碼 代碼如下:

class You {
    public void work() {
        int youMoney = 10;
        Peldar peldar= new Butcher();                               // find a peldar.
        int meat = peldar.buyMeat(youMoney);
        System.out.println("Cook the meat, weight: " + meat);        // you cooked it.   
    }
}
interface Peldar {
 int buyMeat(int money);
}
class Butcher implements Peldar {
    @Override
    public int buyMeat(int money) {
        Farmer farmer = new Farmer();            // 1.find a farmer.
        int meat = farmer.buyMeat(money);        // 2.buy meat from the farmer.
        meat += 5;                               // 3.inject 5 pound water into the meat, so weight will increase.
        return meat;                             // 4.return to you.
    }
}

class Farmer implements Peldar {
    @Override
    public int buyMeat(int money) {
        int meat = 0;
        // ... meat = ***;
        return meat;
    }
}

這就是代理,值得注意的是一般代理類和最終類會(huì)實(shí)現(xiàn)同一接口,這樣的好處是,調(diào)用者就不用關(guān)心當(dāng)前引用的到底是代理還是最終類。

不過(guò)這叫靜態(tài)代理,因?yàn)榇眍悾ㄍ婪蝾悾┦悄阌H手寫(xiě),動(dòng)態(tài)代理就是Java在運(yùn)行的時(shí)候,動(dòng)態(tài)生成一個(gè)等價(jià)的代理類。雖然類是動(dòng)態(tài)生成的,但是殺豬和注水的代碼還是要寫(xiě)的,只是不要寫(xiě)一個(gè)類了。寫(xiě)到哪里呢,寫(xiě)到下面這個(gè)接口里面:

復(fù)制代碼 代碼如下:

public interface InvocationHandler {
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
}

參數(shù)是什么意思呢,我寫(xiě)成這樣,可能你就明白了:

復(fù)制代碼 代碼如下:

public interface InvocationHandler {
    public Object invoke(Object butcher, Method buyMeat, Object[] money) throws Throwable;
}

第一個(gè)參數(shù)是自動(dòng)生成的代理類的一個(gè)對(duì)象(自動(dòng)生成的屠夫類的對(duì)象),第二個(gè)參數(shù)是正前正在被調(diào)用的方法的對(duì)象(方法怎么還有對(duì)象呢,參見(jiàn)Java反射機(jī)制),我們這里只有一個(gè)方法叫buyMeat,所以這個(gè)參數(shù)代表的肯定就是它了,第三個(gè)參數(shù)是傳給前面那個(gè)方法的參數(shù)數(shù)組,buyMeat只有一個(gè)參數(shù),所以這個(gè)數(shù)組只會(huì)有一個(gè)元素。于是殺豬注水的代碼寫(xiě)進(jìn)來(lái)就變成這樣了:

復(fù)制代碼 代碼如下:

InvocationHandler mInvocationHandler = new InvocationHandler() {  
    @Override
    public Object invoke(Object butcher, Method buyMeat, Object[] args) throws Throwable {
        Farmer farmer = new Farmer();              // 1.find a farmer.
        int meat = (Integer) buyMeat.invoke(farmer, args);      // 2.buy meat from the farmer.
        meat += 5;                                 // 3.inject 5 pound water into the meat, so weight will increase.
        return meat;                               // 4.return to you.
    }
};

這個(gè)里調(diào)用農(nóng)民伯伯的買(mǎi)肉方法有點(diǎn)不符常規(guī),這里是反射機(jī)制調(diào)用法,意思是這樣的,以farmer對(duì)象為接受者來(lái)調(diào)用buyMeat方法,跟直接調(diào)用farmer的方法是一樣的,你可能會(huì)問(wèn)那為什么不直接調(diào)用呢,你可能沒(méi)注意,invoke的第一個(gè)參數(shù)類型是Object,所以你可以向任何對(duì)象發(fā)布調(diào)用命令(但不一定會(huì)成功,什么時(shí)候會(huì)成功等下說(shuō)),如果你有很多farmer對(duì)象,甚至不是farmer對(duì)象,只要某接口的實(shí)例就可以(哪個(gè)接口等下說(shuō)明,我們先命名為A接口),就可以當(dāng)成參數(shù)傳進(jìn)來(lái),然后對(duì)其進(jìn)行方法調(diào)用。現(xiàn)在我們來(lái)看看如何生成代理類吧,很簡(jiǎn)單,可以調(diào)用Proxy的工廠方法,如下:

復(fù)制代碼 代碼如下:

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

解釋參數(shù),第一個(gè)ClassLoader是用來(lái)加載代理類的(關(guān)于ClassLoader,本文暫不講解),你暫不了解也沒(méi)關(guān)系,第二個(gè)是一個(gè)數(shù)組,每個(gè)元數(shù)都是一個(gè)接口,新生成的代理都會(huì)實(shí)現(xiàn)所有這些接口,傳給InvocationHandler.invoke第二個(gè)參數(shù)的方法,必定屬于所有這些接口中的方法,上一段落說(shuō)的那個(gè)A接口必須是數(shù)組中的一個(gè)元素,上一段落說(shuō)的那個(gè)調(diào)用成失敗問(wèn)題也明了了。第三個(gè)參數(shù)InvocationHandler更好理解了,就是只要代理類中的任何方法被調(diào)用,就會(huì)通知這個(gè)InvocationHandler。下面寫(xiě)出完整代碼:

復(fù)制代碼 代碼如下:

class You {
    public void work() {
        int youMoney = 10;

        Peldar peldarProxy = (Peldar) Proxy.newProxyInstance(getClass().getClassLoader(), new Class[]{Peldar.class}, mInvocationHandler);
        int meat = peldarProxy.buyMeat(youMoney);

        System.out.println("Cook the meat, weight: " + meat);   
    }

    InvocationHandler mInvocationHandler = new InvocationHandler() {       
        @Override
        public Object invoke(Object butcher, Method buyMeat, Object[] args)
                throws Throwable {
            Farmer farmer = new Farmer();                           // 1.find a farmer.
            int meat = (Integer) buyMeat.invoke(farmer, args);      // 2.buy meat from the farmer.
            meat += 5;                                              // 3.inject 5 pound water into the meat, so weight will increase.
            return meat;                                            // 4.return to you.
        }
    };

}
interface Peldar {
    int buyMeat(int money);
}

class Farmer implements Peldar {
    @Override
    public int buyMeat(int money) {
        int meat = 0;
        // ... meat = ***;
        return meat;
    }
}

這里You類里生成一個(gè)代理類,在代理類的buyMeat被調(diào)用時(shí),代碼就跟之前的靜態(tài)代理一樣的了。

相關(guān)文章

  • Java中方法的重載與重寫(xiě)舉例比較

    Java中方法的重載與重寫(xiě)舉例比較

    這篇文章主要給大家介紹了關(guān)于Java中方法的重載與重寫(xiě)的相關(guān)資料,Java中的方法重載和重寫(xiě)是面向?qū)ο缶幊讨械膬蓚€(gè)重要概念,文中介紹的非常詳細(xì),需要的朋友可以參考下
    2023-07-07
  • Spring Boot整合Spring Security的示例代碼

    Spring Boot整合Spring Security的示例代碼

    這篇文章主要介紹了Spring Boot整合Spring Security的示例代碼,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-04-04
  • java中continue和break區(qū)別詳細(xì)解析

    java中continue和break區(qū)別詳細(xì)解析

    break和continue都是跳轉(zhuǎn)語(yǔ)句,它們將程序的控制權(quán)轉(zhuǎn)移到程序的另一部分,下面這篇文章主要給大家介紹了關(guān)于java中continue和break區(qū)別的相關(guān)資料,需要的朋友可以參考下
    2022-11-11
  • SpringMVC中controller返回json數(shù)據(jù)的方法

    SpringMVC中controller返回json數(shù)據(jù)的方法

    這篇文章主要為大家詳細(xì)介紹了SpringMVC中controller返回json數(shù)據(jù)的方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-09-09
  • Java用三元運(yùn)算符判斷奇數(shù)和偶數(shù)的簡(jiǎn)單實(shí)現(xiàn)

    Java用三元運(yùn)算符判斷奇數(shù)和偶數(shù)的簡(jiǎn)單實(shí)現(xiàn)

    這篇文章主要介紹了Java用三元運(yùn)算符判斷奇數(shù)和偶數(shù)的簡(jiǎn)單實(shí)現(xiàn),需要的朋友可以參考下
    2014-02-02
  • Spring從入門(mén)到源碼之IOC基本用法

    Spring從入門(mén)到源碼之IOC基本用法

    這篇文章給大家介紹了Spring從入門(mén)到源碼之IOC基本用法,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧
    2022-01-01
  • Java list.remove( )方法注意事項(xiàng)

    Java list.remove( )方法注意事項(xiàng)

    這篇文章主要介紹了Java list.remove( )方法注意事項(xiàng),非常簡(jiǎn)單易懂,需要的朋友可以參考下
    2018-08-08
  • 解析JPA的視圖查詢問(wèn)題

    解析JPA的視圖查詢問(wèn)題

    這篇文章主要是對(duì)JPA的視圖查詢問(wèn)題進(jìn)行了詳細(xì)的分析介紹,需要的朋友可以過(guò)來(lái)參考下,希望對(duì)大家有所幫助
    2013-12-12
  • Java無(wú)法獲取真實(shí)IP解決方案

    Java無(wú)法獲取真實(shí)IP解決方案

    這篇文章主要介紹了Java無(wú)法獲取真實(shí)IP解決方案,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-12-12
  • Java開(kāi)源診斷工具Arthas使用方法詳解

    Java開(kāi)源診斷工具Arthas使用方法詳解

    這篇文章主要介紹了Java開(kāi)源診斷工具Arthas使用方法詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-06-06

最新評(píng)論