分佈式Web應用----Java動態代理技術實現原理分析

原文鏈接:http://www.zhaochao.net/index.php/2016/03/11/20/

寫在前面

這裏寫圖片描述
在企業開發中,最基本的開發架構可能就算是MVC框架,如 Struts+Spring+Hibernate 或者 SpringMVC+Spring+Mybatis ,這些框架也可能是JAVA學習者第一次接觸到的,運用這些框架基本上可以滿足小型項目的開發,但是當項目變的複雜,業務增長迅猛時,所有代碼打在一個war包,所有開發人員在同一個項目中開發,開發成本會大大提升,維護,發佈,編譯,測試將會是一件很頭疼的事。這時就需運用RPC(Remote Procedure Call Protocol)——遠程過程調用協議,框架來重構項目,將基礎服務層拆分開,部署成服務形式,運用生產者消費者模型,達到解耦作用。在RPC框架實現原理中,JAVA主要採用的動態代理技術,所以簡要介紹一下此技術,當作備忘錄。

動態代理技術實現原理

動態代理的目的就是在不污染類的情況下,將調用類的方法代理到別的類方法中。這是我自己總結的,感覺有點不好懂,我們來看一個實例

  1. 新建一個People接口
public interface People {
    public  String sayHello(String name);
}

這個接口很簡單,只有一個sayHello的方法,有一個String類型的參數

  1. 新建一個Man類,實現People接口
public class Man implements People {
    public String sayHello(String name) {
        System.out.println("call Man sayHello ");
        return "Hello "+name;
    }
}

這個Man類也非常簡單,它實現的People接口中的sayHello方法,返回 “Hello”+參數名,並且打印出 “call Man sayHello ” 表明這個方法被調用了。

  1. 新建一個PeopleProxyHandler 類
public class PeopleProxyHandler implements InvocationHandler {
    private Object object;
    public PeopleProxyHandler(Object object){
        this.object=object;
    }
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println(" call peopleProxyHandler invoke ");
        System.out.println("調用對象爲:"+object.getClass().getName());
        System.out.println("調用方法爲:"+method.getName());
        for (Object obj:args){
            System.out.println("參數爲:"+obj.toString());
        }
        Class cl=Class.forName(object.getClass().getName());
        return  method.invoke(cl.newInstance(),args);
    }
}

這個類是關鍵,它實現了InvocationHandler 接口,有一個構造函數,並且有一個invoke方法,這個類的主要作用就是在將調用類方法時將調用的方法名和參數代理到invoke方法中。在invoke 方法中,我們獲取到了方法method和調用參數列表args,並打印出了一些信息方便調試。如果在構造類時我們把調用對象傳過來,我們就可以通過反射來調用代理到的對象了。

  1. 編寫測試類
    public  static  void  main(String [] rags){
        People man=new Man();
        People people=(People) Proxy.newProxyInstance(Man.class.getClassLoader(),new Class [] {People.class},new PeopleProxyHandler(man));
        String res=people.sayHello("zhaochao");
        System.out.println(res);
        System.out.println(man.sayHello("zhaochao"));

    }

在這個測試方法中,我們先創建了一個對象,然後利用Proxy.newProxyInstance()獲得了一個man的代理對象people,最後調用了這個代理對象的sayHello方法。

  1. 查看結果
 call peopleProxyHandler invoke 
調用對象爲:com.zhaocaho.proxy.Man
調用方法爲:sayHello
參數爲:zhaochao
call Man sayHello 
Hello zhaochao
call Man sayHello 
Hello zhaochao

在結果中我們可以看到當調用people.sayHello時並沒有直接調用Man中的sayHello方法,而是調用了PeopleProxyHandler 中的invoke 方法,並且將方法和參數傳進去了,在invoke中我們通過反射調用了man中的sayHello方法,最後返回結果和直接調用man中的sayHello是完全一樣的。
總結
通過上面例子我們可以發現,如果在invoke方法中,我們將方法名,參數,對象名通過網絡傳送到遠程服務器上,在遠程服務器上接收到數據,然後通過反射調用該對象的方法,最後通過網絡返回結果,invoke通過網絡收到結果後將結果析封裝後返回,這樣對於people這個對象來說它並不知道,底層到底是通過什麼方式完成此次方法調用的,只要返回結果和它調用本地方法一樣就達到本次調用目的了。這就是RPC的基本原理,當然實現起來沒有這麼簡單,細節知識,未完待續!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章