1. 程式人生 > >Java技術專題——幫你徹底搞懂JNDI(附詳細例項)

Java技術專題——幫你徹底搞懂JNDI(附詳細例項)

1. 什麼是JNDI?

JNDI(Java Naming and Directory Interface,Java命名和目錄介面)是SUN公司提供的一種標準的Java命名系統介面,JNDI提供統一的客戶端API,通過不同的訪問提供者介面JNDI服務供應介面(SPI)的實現,由管理者將JNDI API對映為特定的命名服務和目錄系統,使得Java應用程式可以和這些命名服務和目錄服務之間進行互動。

對於JNDI的概念不少同學表示,一看就覺得頭疼,根本沒有想耐下心看的興趣。為此,博主將上面複雜的概念拆分成一些簡單的概念要點,幫助大家更好地理解JNDI的概念:

  1. JNDI本質上是一系列通用的標準的
    用來操作命名服務和目錄服務的介面: 換句話說,這一系列的介面就是對操作所有命名服務和目錄服務的一種超級抽象,有了這些介面我們就可以用通用的介面操作各式各樣的命名服務或者是目錄服務,而不需要每次與一種服務互動就寫一次操作該服務的程式碼,始終記住一個宗旨,以抽象應對改變。
  2. JNDI的這些通用介面需要依靠服務供應介面(SPI)的實現來將通用的介面對映為特定的命名或目錄服務,使客戶端能夠和指定的服務進行互動:這句話的意思就是儘管雖然提供了一系列超級抽象版的通用介面API供客戶端使用,但是使用這些介面的人該怎麼知道用這些介面是在訪問一個檔案目錄服務還是一個DNS命名服務呢?因此JNDI又提供了一系列的服務提供者介面(SPI),所有的服務供應商只要根據這些SPI去提供自己服務的實現,客戶在使用通用介面時引入這些SPI的實現類,就可以操作指定的服務了。

2. 命名服務與目錄服務

JNDI的目的就是對命名服務(Naming Service)與目錄服務(Directory)中的資源進行查詢或者管理,那麼什麼是命名服務,什麼又是目錄服務呢?

命名服務的概念其實很好理解,在生活中也有很多的例子,最典型的就是DNS(Domain Naming Service)了。眾所周知,DNS是用來對人類更便於記憶的域名和計算機更便於記憶的IP地址進行對映的。因此命名服務的核心就在於對映,講一個值對映成另一個值。

至於目錄服務呢,它其實是命名服務的一種自然擴充套件,兩者之間的關鍵差別是目錄服務中物件可以有屬性,而命名服務中物件沒有屬性。舉個簡單的例子吧,我們手機中的電話簿就是一個典型的目錄服務。它將一個電話號碼對映成了擁有這個號碼的人,但是人這個物件不僅僅會有姓名(儘管姓名最重要),這也就是為什麼電話簿中還可以增加這個人的家庭住址,公司,電子郵件,電話鈴聲等等。

3. JNDI架構

e7a6008a18a547a8a38b310e689a0221-JNDI.jpg

JNDI架構提供了一組標準的獨立於命名系統的API,這些API構建在與命名系統有關的驅動之上。這一層有助於將應用與實際資料來源分離,因此不管應用訪問的是LDAP、RMI、DNS、還是其他的目錄服務。換句話說,JNDI獨立於目錄服務的具體實現,只要有目錄的服務提供介面(或驅動),就可以使用目錄。

關於JNDI要注意的重要一點是,它提供了應用程式設計介面(application programming interface,API)和服務提供者介面(service provider interface,SPI)。這一點的真正含義是,要讓應用與命名服務或目錄服務互動,必須有這個服務的JNDI服務提供者,這正是JNDI SPI發揮作用的地方。服務提供者基本上是一組類,這些類為各種具體的命名和目錄服務實現了JNDI介面—很像JDBC驅動為各種具體的資料庫系統實現了JDBC介面一樣。作為一個應用開發者,我們不必操心JNDI SPI的具體實現。只需要確認要使用的某一個命名或目錄服務都有服務提供者。

JNDI提供瞭如下幾個程式包:

  1. Javax.naming:包含了訪問命名服務的類和介面。例如,它定義了Context介面,這是命名服務執行查詢的入口。

  2. Javax.naming.directory:對命名包的擴充,提供了訪問目錄服務的類和介面。例如,它為屬性增加了新的類,提供了表示目錄上下文的DirContext介面,定義了檢查和更新目錄物件的屬性的方法。

  3. Javax.naming.event:提供了對訪問命名和目錄服務時的事件通知的支援。例如,定義了NamingEvent類,這個類用來表示命名/目錄服務產生的事件,定義了偵聽NamingEvents的NamingListener介面。

  4. Javax.naming.ldap:這個包提供了對LDAP 版本3擴充的操作和控制的支援,通用包javax.naming.directory沒有包含這些操作和控制。

  5. Javax.naming.spi:這個包提供了一個方法,通過javax.naming和有關包動態增加對訪問命名和目錄服務的支援。這個包是為有興趣建立服務提供者的開發者提供的。

4. JNDI例項

正所謂光說不練假把式,下面樓主就和大家一起寫一個JNDI的例子,來鞏固一下上面的知識。

正如博主上面所講,要使用JNDI,必須有服務供應商按照SPI所提供的服務實現,為了省下我們的大量時間,我們採用SUN公司官方提供的檔案系統服務提供者(File System Service Provider, FSSP),這個服務提供者是用來幫助使用者操作檔案系統的。

首先我們需要下載FSSP的官方資源包

4f0144a25cfc435a872cd71c120598bb-FSSP.png

當然,大家也可以直接使用我的專案,但是官方包中會有一些官方的幫助文件對初次使用的朋友們還是比較有幫助的。

下面是我為大家寫的一個連線了本地的檔案系統的例子,當然我們需要將fscontext.jar和providerutil.jar載入到classpath下:

public class FSSPTest {

    public static void main(String[] args) throws NamingException {
        // TODO Auto-generated method stub
        Hashtable<String,String> env = new Hashtable<>();
        //指明初始化的factory是我們下載的jar包中的RefFSContextFactory
        env.put(Context.INITIAL_CONTEXT_FACTORY, 
                "com.sun.jndi.fscontext.RefFSContextFactory");
        //指明Context的初始URL,這裡我們的是C盤
        env.put(Context.PROVIDER_URL,"file:///c:/");

        Context ctx = new InitialContext(env);

        //在C盤下建立要給資料夾名為JesminDir
        ctx.createSubcontext("JesminDir");

        //在C盤下定位myFile檔案
        File f =  (File) ctx.lookup("myFile");
        System.out.println(f);

        //列出當前context下的所有元素的名稱和型別(包括資料夾和檔案)
        NamingEnumeration list = ctx.list("/"); 
        while (list.hasMore()) { 
            NameClassPair nc = (NameClassPair)list.next(); 
            System.out.println(nc); 
        }
    }
}