RMI 通過 JNDI

此示例顯示 JNDI 如何在 RMI 中工作。它有兩個角色:

  • 向伺服器提供繫結/取消繫結/重新繫結 API 到 RMI 登錄檔
  • 向客戶端提供 RMI 登錄檔的查詢/列表 API。

RMI Registry 是 RMI 的一部分,而不是 JNDI。

為簡單起見,我們將使用 java.rmi.registry.CreateRegistry() 建立 RMI 登錄檔。

  1. Server.java(JNDI 伺服器)

    package com.neohope.jndi.test;
    
    import javax.naming.Context;
    import javax.naming.InitialContext;
    import javax.naming.NamingException;
    import java.io.IOException;
    import java.rmi.RemoteException;
    import java.rmi.registry.LocateRegistry;
    import java.util.Hashtable;
    
    /**
     * JNDI Server
     * 1.create a registry on port 1234
     * 2.bind JNDI
     * 3.wait for connection
     * 4.clean up and end
     */
    public class Server {
        private static Registry registry;
        private static InitialContext ctx;
    
        public static void initJNDI() {
            try {
                registry = LocateRegistry.createRegistry(1234);
                final Hashtable jndiProperties = new Hashtable();
                jndiProperties.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.rmi.registry.RegistryContextFactory");
                jndiProperties.put(Context.PROVIDER_URL, "rmi://localhost:1234");
                ctx = new InitialContext(jndiProperties);
            } catch (NamingException e) {
                e.printStackTrace();
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }
    
        public static void bindJNDI(String name, Object obj) throws NamingException {
            ctx.bind(name, obj);
        }
    
        public static void unbindJNDI(String name) throws NamingException {
            ctx.unbind(name);
        }
    
        public static void unInitJNDI() throws NamingException {
            ctx.close();
        }
    
        public static void main(String[] args) throws NamingException, IOException {
            initJNDI();
            NMessage msg = new NMessage("Just A Message");
            bindJNDI("/neohope/jndi/test01", msg);
            System.in.read();
            unbindJNDI("/neohope/jndi/test01");
            unInitJNDI();
        }
    }
    
  2. Client.java(JNDI 客戶端)

    package com.neohope.jndi.test;
    
    import javax.naming.Context;
    import javax.naming.InitialContext;
    import javax.naming.NamingException;
    import java.util.Hashtable;
    
    /**
     * 1.init context
     * 2.lookup registry for the service
     * 3.use the service
     * 4.end
     */
    public class Client {
        public static void main(String[] args) throws NamingException {
            final Hashtable jndiProperties = new Hashtable();
            jndiProperties.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.rmi.registry.RegistryContextFactory");
            jndiProperties.put(Context.PROVIDER_URL, "rmi://localhost:1234");
    
            InitialContext ctx = new InitialContext(jndiProperties);
            NMessage msg = (NeoMessage) ctx.lookup("/neohope/jndi/test01");
            System.out.println(msg.message);
            ctx.close();
        }
    }
    
  3. NMessage.java(RMI 伺服器類)

    package com.neohope.jndi.test;
    
    import java.io.Serializable;
    import java.rmi.Remote;
    
    /**
     * NMessage
     * RMI server class
     * must implements Remote and Serializable 
     */
    public class NMessage implements Remote, Serializable {
        public String message = "";
    
        public NMessage(String message)
        {
            this.message = message;
        }
    }
    

如何執行 eaxmple:

  1. 構建並啟動伺服器
  2. 構建並啟動客戶端

介紹

http://i.stack.imgur.com/pGG8z.jpg

Java 命名和目錄介面(JNDI) 是一個目錄服務,允許 Java 軟體客戶端發現,並通過名稱來查詢資料和物件的 Java API。它旨在獨立於任何特定的命名或目錄服務實現。

JNDI 體系結構由 API (應用程式程式設計介面)和 SPI (服務提供者介面)組成。Java 應用程式使用此 API 來訪問各種命名和目錄服務。SPI 允許透明地插入各種命名和目錄服務,允許使用 JNDI 技術 API 的 Java 應用程式訪問其服務。

從上面的圖片可以看出,JNDI 支援 LDAP,DNS,NIS,NDS,RMI 和 CORBA。當然,你可以擴充套件它。

這個怎麼運作

在此示例中,Java RMI 使用 JNDI API 查詢網路中的物件。如果要查詢物件,則至少需要兩條資訊:

  • 在哪裡找到物件

RMI 登錄檔管理名稱繫結,它告訴你在哪裡找到物件。

  • 物件的名稱

什麼是物件的名字?它通常是一個字串,它也可以是一個實現 Name 介面的物件。

一步步

  1. 首先,你需要一個管理名稱繫結的登錄檔。在這個例子中,我們使用 java.rmi.registry.LocateRegistry

    //This will start a registry on localhost, port 1234
    registry = LocateRegistry.createRegistry(1234);
    
  2. 客戶端和伺服器都需要 Context。伺服器使用 Context 來繫結名稱和物件。客戶端使用 Context 查詢名稱並獲取物件。

    //We use com.sun.jndi.rmi.registry.RegistryContextFactory as the InitialContextFactory
    final Hashtable jndiProperties = new Hashtable();
    jndiProperties.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.rmi.registry.RegistryContextFactory");
    //the registry usrl is "rmi://localhost:1234"
    jndiProperties.put(Context.PROVIDER_URL, "rmi://localhost:1234");
    InitialContext ctx = new InitialContext(jndiProperties);
    
  3. 伺服器繫結名稱和物件

    //The jndi name is "/neohope/jndi/test01"
    bindJNDI("/neohope/jndi/test01", msg);
    
  4. 客戶端通過名稱“/ neohope / jndi / test01”查詢物件

    //look up the object by name "java:com/neohope/jndi/test01"
    NeoMessage msg = (NeoMessage) ctx.lookup("/neohope/jndi/test01");
    
  5. 現在客戶端可以使用該物件

  6. 當伺服器結束時,需要清理。

    ctx.unbind("/neohope/jndi/test01");
    ctx.close();