RMI筆記

RMI(remote method invoke)
一、基本原理
RMI通過代理來負責客戶和遠程對象之間通過socket進行通信的細節。
RMI分別爲遠程對象生成了客戶端代理和服務端代理。客戶端的叫stub,服務端的叫Skeleton。
Stub進行參數編組,將下列信息發給服務端:
1)要訪問的遠程對象的名字
2)被調用的方法的描述
3)編組後的參數的字節序列

服務端由skeleton來處理這一信息,進行下列動作
1)反編組參數
2)定位要訪問的對象
3)調用遠程對象相應的方法
4)對返回值或者異常進行相應的編組
5)將編組後的內容發給客戶端。

二、創建一個RMI應用
1、創建遠程類接口
        1)直接或間接繼承Remote接口
        2)接口中所有的方法拋出RemoteException異常
2、創建遠程類,實現遠程接口
        1)遠程類繼承UnicastRemoteObject,
        2)可以不繼承,直接在構造函數中調用UnicastRemoteObject.exportObject(this,0).
        3)遠程類的構造函數需要聲明拋出RemoteException
        4)遠程方法必須拋出RemoteException
3、創建服務器程序,
        通過 JNDI的javax.naming.Context在rmigegistry註冊表中註冊遠程對象。
        幾個方法bind,rebind,lookup,unbind
        創建遠程對象:
        HelloService service1 = new HelloServiceImpl("service1");
        Context namingContext = new InitialContext();
        namingContext.rebind("rmi:HelloService",service1);
4、創建客戶端程序。
        獲取遠程對象的存根對象
       String url = "rmi://localhost/";
       HelloService service1 = (HelloService) namingContext.lookup(url
                                        + "HelloService1");

三、遠程對象設計工廠模式
        就是創建一個工廠類和產品類,這個工廠類和產品類都是遠程對象,都要實現remote接口,遠程方法都要聲明RemoteException
        1)客戶端每次訪問一個遠程對象的時候,都會得到一個新的stub對象。
        2)stub對象重寫了equal方法,如果兩個stub對象都是對應一個遠程對象的代理,則equal返回true。equal不是遠程方法。
        3)stub對象操作遠程方法,會導致遠程對象的實現類進行相應的操作。

四、遠程方法中的參數與返回值的傳遞
        在服務器端和客戶端傳遞的方法或返回值,必須是遠程對象、可序列化對象,或者是基本類型數據,否則在進行遠程方法調用的時候會出現UnmarshalException.

五、回調客戶端的遠程對象

六、遠程對象的併發訪問

七、分佈式垃圾收集
        1、RMI框架採用分佈式垃圾收集機制。
        1)DGC回收規則:一個遠程對象不受到任何本地引用和遠程引用,這個對象可以被回收。
        2)租約通知:通知服務器遠程對象被引用了。
        3)租約期限:通過java.rmi.dgc.leaseValue來設置。
        4)通過實現java.rmi.server.Unreferenced接口,可以來釋放相關資源。
        5)強制服務端等待客戶端獲得該遠程對象的引用service.isAccessed()

八、遠程對象的equals()、hashCode()和clone()方法
        stub重寫了equal和hashcode方法,沒有重寫clone

九、使用安全管理器
1、客戶端使用安全管理器的兩個步驟
        1)創建安全策略文件,例如:
        grant{
          permission java.net.SocketPermission "*:1024-65535","connect";
        };
        2)爲客戶端設置安全策略文件和RMISecurityManager
        System.setProperty("java.security.policy", SimpleClient.class
                                        .getResource("client.policy").toString());
    System.setSecurityManager(new RMISecurityManager());//會從client.policy中讀取安全策略
2、通過命令進行設置
    java -D java.security.policy=c:\chapter11\client.policy SimpleClient
3、如果服務端需要從客戶端動態加載類,也要按照類似方式設置。

十、RMI應用部署以及類的動態加載
        java.rmi.server.codebase系統屬性,從指定的位置動態加載類文件

十一、遠程激活
        1、RMI框架提供了一種遠程激活機制,當有一個客戶去訪問遠程對象的時候,還去創建這個遠程對象。和延遲加載差不多的概念。
        rmid:激活系統。遠程對象由這個系統來管理生命週期。
       2、RMI類介紹
Activatable:可以被激活的遠程對象都是這個類的實例,ActivationID表示激活對象的唯一標識符。
       ActivationGroup:激活組,可以被激活的對象都放在這裏面。
       ActivationGroupDesc:描述激活組(屬性文件,啓動虛擬機的路徑)  
    一個激活組對應一個java虛擬機,rmid程序根據ActivationGroupDesc提供的信息來啓動一個java虛擬機,然後在這個虛擬機內創建並管理可以激活的遠程對象,每個激活組都有唯一的id,用ActivationGroupID來表示。        
    ActivationDesc用來描述一個可以激活的遠程對象。
ActivationDesc(ActivationGroupID groupID, String className, String location, MarshalledObject data)
3、一個遠程對象如果希望被激活,它的遠程類應該繼承java.rmi.activation.Activatable類。
4、rmid程序激活對象步驟

//1.創建一個激活組描述符ActivationGroupDesc對象
                        ActivationGroupDesc group = new ActivationGroupDesc(prop, null);
                        //2.向rmid程序註冊ActivationGroup,配置信息由group提供
                        ActivationGroupID id = ActivationGroup.getSystem().registerGroup(
                                        group);
                        String classURL = System.getProperty("java.rmi.server.codebase");
                        MarshalledObject param1 = new MarshalledObject("service1");
                        MarshalledObject param2 = new MarshalledObject("service2");
                        //3.創建激活對象描述符ActivationDesc
                        ActivationDesc desc1 = new ActivationDesc(id,
                                        "activate.HelloServiceImpl", classURL, param1);
                        ActivationDesc desc2 = new ActivationDesc(id,
                                        "activate.HelloServiceImpl", classURL, param2);
                        //4.向rmid註冊激活對象,配置信息由desc提供
                        HelloService s1 = (HelloService) Activatable.register(desc1);
                        HelloService s2 = (HelloService) Activatable.register(desc2);
                        System.out.println(s1.getClass().getName());

                        Context namingContext = new InitialContext();
                        //5.向rmiregistry註冊激活對象
                        namingContext.rebind("rmi:HelloService1", s1);
                        namingContext.rebind("rmi:HelloService2", s2);

 

 

 

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