最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

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

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

代理都知道吧,你去買東西就有很多的代理商,他們就是賣原廠的東西。比如,你天天要買肉,豬是農(nóng)民伯伯養(yǎng)的,但你是從屠夫手上買到肉的,這個屠夫就可以當成是代理。那為什么要代理呢,代理有什么用呢,當然是有事給他做了,對于屠夫這個代理就好理解了,因為你自己不可能去宰豬吧,所以代理就是去買活豬,然后宰掉再賣給你,當然屠夫有可能給肉注點水,關鍵看他壞不壞,所以屠夫的整個流程就是:

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

復制代碼 代碼如下:

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

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

復制代碼 代碼如下:

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.
    }
}

然你從屠夫手上買肉的代碼就變成這樣:

復制代碼 代碼如下:

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. 
    }
}

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

復制代碼 代碼如下:

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;
    }
}

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

不過這叫靜態(tài)代理,因為代理類(屠夫類)是你親手寫,動態(tài)代理就是Java在運行的時候,動態(tài)生成一個等價的代理類。雖然類是動態(tài)生成的,但是殺豬和注水的代碼還是要寫的,只是不要寫一個類了。寫到哪里呢,寫到下面這個接口里面:

復制代碼 代碼如下:

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

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

復制代碼 代碼如下:

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

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

復制代碼 代碼如下:

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.
    }
};

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

復制代碼 代碼如下:

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

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

復制代碼 代碼如下:

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類里生成一個代理類,在代理類的buyMeat被調(diào)用時,代碼就跟之前的靜態(tài)代理一樣的了。

相關文章

  • java清除u盤內(nèi)存卡里的垃圾文件示例

    java清除u盤內(nèi)存卡里的垃圾文件示例

    手機內(nèi)存卡空間被用光了,但又不知道哪個文件占用了太大,一個個文件夾去找又太麻煩,開發(fā)了個小程序把手機所有文件(包括路徑下所有層次子文件夾下的文件)進行一個排序,這樣你就可以找出哪個文件占用了內(nèi)存太大了
    2014-02-02
  • java弱口令檢測機制解析

    java弱口令檢測機制解析

    這篇文章主要介紹了java弱口令檢測機制,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-09-09
  • 解讀JVM的組成部分有什么

    解讀JVM的組成部分有什么

    JVM主要由類加載器子系統(tǒng)、運行時數(shù)據(jù)區(qū)、執(zhí)行引擎和本地庫接口等組成,類加載器負責加載類文件,運行時數(shù)據(jù)區(qū)管理內(nèi)存,執(zhí)行引擎執(zhí)行字節(jié)碼指令和垃圾回收,本地庫接口連接其他語言
    2025-03-03
  • java集合類源碼分析之Set詳解

    java集合類源碼分析之Set詳解

    下面小編就為大家?guī)硪黄猨ava集合類源碼分析之Set詳解。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-10-10
  • 詳解SpringBoot多跨域請求的支持(JSONP)

    詳解SpringBoot多跨域請求的支持(JSONP)

    跨域是很多項目需要遇到的文章,本篇文章主要介紹了詳解SpringBoot多跨域請求的支持(JSONP),具有一定的參考價值,有興趣的可以了解一下
    2017-04-04
  • Spring整合消息隊列RabbitMQ流程

    Spring整合消息隊列RabbitMQ流程

    Spring整合RabbitMQ很容易,但是整合的目的是為了使用,那要使用RabbitMQ就要對其有一定的了解,不然容易整成一團漿糊。因為說到底,Spring只是在封裝RabbitMQ的API,讓其更容易使用而已,廢話不多說,讓我們一起整它
    2023-03-03
  • 一文帶你搞懂java如何實現(xiàn)網(wǎng)絡NIO高并發(fā)編程

    一文帶你搞懂java如何實現(xiàn)網(wǎng)絡NIO高并發(fā)編程

    NIO是?Java?在?JDK?1.4?中引入的一套新的?I/O?API,旨在解決傳統(tǒng)?I/O高并發(fā)場景下的性能和擴展性不足的問題,下面就跟隨小編一起深入了解下NIO高并發(fā)編程吧
    2024-12-12
  • 劍指Offer之Java算法習題精講二叉樹與N叉樹

    劍指Offer之Java算法習題精講二叉樹與N叉樹

    跟著思路走,之后從簡單題入手,反復去看,做過之后可能會忘記,之后再做一次,記不住就反復做,反復尋求思路和規(guī)律,慢慢積累就會發(fā)現(xiàn)質(zhì)的變化
    2022-03-03
  • MyBatis 探秘之#{} 與 ${} 參傳差異解碼(數(shù)據(jù)庫連接池筑牢數(shù)據(jù)交互根基)

    MyBatis 探秘之#{} 與 ${} 參傳差異解碼(數(shù)據(jù)庫連接池筑牢數(shù)據(jù)交互

    本文詳細介紹了MyBatis中的`#{}`和`${}`的區(qū)別與使用場景,包括預編譯SQL和即時SQL的區(qū)別、安全性問題,以及如何正確使用數(shù)據(jù)庫連接池來提高性能,感興趣的朋友一起看看吧
    2024-12-12
  • Java調(diào)用Docx4j庫玩轉Word文檔處理

    Java調(diào)用Docx4j庫玩轉Word文檔處理

    在 Java 開發(fā)里處理 Word 文檔時,Docx4j 可是個超厲害的庫,它能讓咱輕松創(chuàng)建,讀取,修改和轉換 Word 文檔,下面我們就來看看具體是如何操作的吧
    2025-02-02

最新評論

藁城市| 紫云| 张掖市| 虞城县| 滦平县| 宝坻区| 桂阳县| 龙里县| 长阳| 墨玉县| 白河县| 响水县| 浮梁县| 汾阳市| 剑川县| 海宁市| 新河县| 甘谷县| 贡嘎县| 孟津县| 涿鹿县| 奎屯市| 汤阴县| 景泰县| 秭归县| 乌兰县| 峡江县| 禄丰县| 鄂托克旗| 西丰县| 阳新县| 松桃| 临清市| 买车| 淮滨县| 长宁县| 芷江| 阿合奇县| 新乡县| 济南市| 邵东县|