1. 程式人生 > >java總結(三)——jndi在j2ee和j2se中的應用

java總結(三)——jndi在j2ee和j2se中的應用

    JNDI,Java命名和目錄介面,允許應用程式通過公共介面訪問各種命名和目錄服務。下圖顯示了JNDI架構。如JDBC(Java資料庫連線),JNDI是不是服務,而是一組介面; 它允許應用程式使用一個標準化的API來訪問許多不同的目錄服務供應商。就像使用JDBC,那麼JDK包含了JNDI介面,但不包括JNDI服務提供者 - 儘管Sun Microsystems公司提供的介面卡,用於連線到現有的目錄服務供應商,如LDAP(輕量級目錄訪問協議),DNS(域名服務)和CORBA。但是,您可以使用多種免費或開源的JNDI供應商在你的J2SE(Java 2平臺標準版)的應用程式之一。


    JNDI是儲存在一起的J2EE(Java2平臺企業版)應用的膠水。JNDI被設計用來支援高動態應用程式組裝和部署,與元件不斷新增和更新,無需重建整個系統。命名服務有助於通過充當中央登記成分組織的企業應用程式。J2EE應用程式通常使用JNDI在幾個方面:

·        隨著儲存應用程式的配置資訊在一個集中,層次型資料庫的一種手段

·        作為應用程式元件之間共享的活動物件,它可以在不同的JVM或者在不同系統上執行的儲存庫

·        作為一個介面與現有的目錄服務,如LDAP(使用特定的提供給外部服務)

·        作為一個輕量級的,分層資料庫,用於儲存瞬態應用程式狀態

    像J2EE應用程式,更大或更動態的J2SE應用程式可以受益於鬆散耦合和動態繫結提供了一個積極的目錄服務。

一個簡單的JNDI例子

    從JNDI名稱空間儲存和檢索物件是相當簡單的; 你第一次得到一個JNDI 命名上下文,然後使用bind()方法和lookup()方法來儲存和檢索物件,如清單1所示:

    清單1。從JNDI名稱空間儲存和檢索物件

  importjavax.naming.*;
  public voidcreateName() throws NamingException {
    Context context= new InitialContext();
   context.bind("/config/applicationName", "MyApp");
  }
  public StringgetName() throws NamingException {
    Context context= new InitialContext();
    return (String)context.lookup("/config/applicationName");
  } 

    清單1演示了最常見的JNDI操作-建立一個JNDI上下文,在上下文繫結的物件,然後從上下文檢索物件。請注意,JNDI名稱空間和客戶端可能駐留在不同的JVM,並Bind()和lookup()的呼叫可能會同樣發生在不同的JVM。一個JNDI提供者使用了多種技術,包括系列化,以確保物件可以從JVM移動到JVM中,但仍然可以檢索到它的原始形式。

    清單1中的程式碼片段有幾個隱藏的假設:JNDI如何知道使用哪個提供商建立上下文時?對於需要身份驗證提供程式,憑據從何而來?一般情況下,您可以通過設定在系統屬性中的JNDI幾個特定的屬性指定供應商及其他連線引數,或通過設定他們在jndi.properties中的檔案。此外,任何給定的供應商可能無法繫結或檢索任意物件。例如,一些供應商,如DNS提供商,是隻讀的,而有些供應商可能會更靈活一些,他們可以繫結的物件的型別。大多數廠商提供的JNDI提供商可以儲存和檢索實現的java.io.Serializable,java.rmi.Remote的,或javax.naming.Referenceable的一個物件

隱藏的JNDI提供

    在上圖所示的JNDI供應商都有一個共同點 - 他們的請求委託給外部的目錄服務,如LDAP。然而,此圖沒有顯示JNDI提供者的一個重要型別:內置於所有J2EE容器,它儲存的目錄資訊在內部資料庫中的JNDI提供者。當我們談論在J2EE應用程式中使用JNDI,我們通常所說的這個容器提供的供應商。

如何J2EE使用JNDI?

    J2EE應用程式是組裝出來的元件。該方法的元件的配置和相互連線是在部署時指定的;大部分資訊都儲存在JNDI名稱空間。J2EE應用程式使用JNDI來儲存配置資訊(如字串和數值常量),無狀態的物件(包括物件工廠),和EJB(E​​nterprise JavaBean元件)home介面。

    JNDI是,它允許您構建J2EE應用瞭如servlet,JSP頁面(JavaServer頁面),和EJB元件的膠水。在J2EE應用程式中,每個元件發現其他元件無法通過靜態連線,而是通過JNDI查詢。J2EE應用程式允許部署時間,同時保持型和鏈路安全通過讓每個元件出口的外部元件和資源,它需要一個列表繫結。部署者確保每個進口都有正確型別的應用程式中的相應部分。J2EE容器包括工具,以幫助您正確做到這一點。

如何J2SE應用程式使用JNDI?

     像J2EE應用程式,J2SE應用程式可以使用JNDI作為命名的配置引數,物件和物件工廠的共享儲存庫。工廠建立模式中使用JNDI非常合適,因為你可以儲存你的工廠在JNDI名稱空間。J2SE應用程式也可以使用JNDI作為一個更強大,功能豐富,並集中更換為RMI(遠端方法呼叫)。

    大多數J2SE應用程式的配置檔案,這些檔案儲存無論是作為屬性檔案或XML文件載入其配置資訊。這些配置檔案中指定的各種配置資訊; 一些更復雜的應用程式儲存資訊的例項化物件,如類名和建構函式的引數,在配置檔案中。

    使用JNDI來儲存常量,物件和物件工廠相對於傳統的配置機制有些優勢。由於大多數的JNDI提供者是網路訪問的,你不需要保持一個組配置檔案一致的每個主機在分散式應用程式。此外,使用反射來例項化一個物件時,需要更多的程式碼(尤其是更多的錯誤恢復程式碼)不能簡單地檢索出該物件JNDI名稱空間中。雖然使用JNDI一般無須從配置資訊例項化一個物件(當你填入的名稱空間,一般在應用程式啟動時),這種複雜性被分解遠離大多數的應用程式程式碼,它可以簡單地從JNDI名稱空間檢索所需的物件。

    另一個原因在分散式應用程式使用JNDI而不是配置檔案是因為一個配置檔案的資訊可能是敏感的,例如用於資料庫訪問的密碼。通過儲存資料來源的JNDI名稱空間,你可以提供給整個應用程式的資料庫連線,而不會使密碼提供給整個應用程式。(例如,PoolMan包,一種廣泛使用的開源連線池包,儲存一個數據源物件中的JNDI名稱空間(如果有)。)

    使用JNDI與J2SE應用程式,您首先需要一個JNDI提供者,因為JDK中不包括的。如果你只是想使用JNDI來訪問外部的目錄,例如LDAP,則可以使用Sun提供的供應商之一。但通常情況下,你會希望有一個獨立的供應商,有幾個你可以使用。

一個獨立的JNDI提供

    JBoss的開源J2EE伺服器包括一個JNDI供應商(JNP),可以作為一個獨立的服務執行; 它提供了一個極好的輕量級網路訪問的JNDI服務。JNP採用記憶體資料庫來儲存物件,所以名稱空間的內容並不在服務重新啟動仍然存在。您可以輕鬆地自行執行JNP或配置JBoss容器,開始只有JNP服務。

選項​​1配置JNP伺服器JBoss的服務

    JBoss應用伺服器是建立在JMX(Java管理擴充套件)框架; 該框架允許應用程式服務進行模組化為JMX MBean的,它可以啟動和管理獨立。該檔案jboss.jcml包含的mbeans容器啟動時,將載入的列表。JBoss的預設配置包括50多個MBean的,但如果你指定jboss.jcml應該只包含清單2中所示的單報關,然後啟動JBoss伺服器,伺服器將只加載了JNDI提供者,沒有其他的J2EE應用服務:

清單2。JNDI只jboss.jcml檔案

<?xml version="1.0"encoding="UTF-8"?>
<server>
  <mbeancode="org.jboss.naming.NamingService"
        name="DefaultDomain:service=Naming">
    <attributename="Port">1099</attribute>
  </mbean>
</server>


選項​​2。配置JNP伺服器獨立

    JNP也可以作為一個獨立的伺服器應用程式執行。要配置它是這樣,你需要兩個jar檔案:

·        jnpserver.jar -從JBoss分佈,在lib / ext目錄目錄

·        log4j.jar -廣泛使用的日誌工具,來自Apache Jakarta專案;你還會發現它在JBoss分佈在lib / ext目錄

此外,你需要一個log4j.properties檔案;清單3顯示了一個簡單的問題。這個檔案應該通過類路徑是可訪問:

清單3。簡單的log4j.properties檔案

 # Use aConsoleAppender -- write log data to standard out
log4j.rootLogger=DEBUG, A1
log4j.appender.A1=org.apache.log4j.ConsoleAppender
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern=%-4r [%t] %-5p%c %x - %m%n

    要執行JNP伺服器在獨立模式下,確保log4j.jar檔案時,jnpserver.jar檔案,包含目錄log4j.properties都在你的classpath中。然後,啟動JNP伺服器,如下所示:

                                            javaorg.jnp.server.Main

您還可以使用org.jnp.server物件到應用程式的JVM中啟動JNDI服務。

使用JNDI服務

    一旦JNP伺服器正在執行,你可以配置你的應用程式使用JNP通過包括JNP-client.jar的檔案在classpath和指定java.naming.provider.urljava.naming.factory.initial無論是在系統屬性屬性或的jndi.properties檔案。清單4顯示了一個示例的jndi.properties檔案:

清單4。的jndi.properties檔案

 java.naming.provider.url=jnphost.mycompany.com:1099
java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
java.naming.factory.url.pkgs=org.jboss.naming

    下面的示例顯示瞭如何你可以用字串,整數,並在屬性中指定的物件值引數檔案填充一個JNDI名稱空間在應用程式啟動時間,以及應用程式元件如何能找回這些屬性。為了簡便起見,清單5A假設方法的存在解析XML配置檔案,省略了錯誤處理程式碼:

清單5A。從配置檔案中載入一個JNDI名稱空間

 public voidloadJNDI() {
    Context context= new InitialContext();
    ConfigItem[]items = getConfigItems();
    for (int i=0;i<items.length; i++) {
      Objecto=null;
      if(items[i].getType().equals("Integer"))
        o = Integer.decode(items[i].getValue());
      else if(items[i].getType().equals("String"))
        o =items[i].getValue();
      else if(items[i].getType().equals("Object"))
        o =Class.forName(items[i].getValue()).newInstance();
     context.bind(items[i].getName(), o);
    }
  }

清單5b所示。示例XML配置檔案

  <config>
    <itemname="config/screen/resolutionX" type="Integer"
         value="1024" />
    <itemname="config/screen/resolutionY" type="Integer"
         value="768" />
    <itemname="converters/html" type="Object"
         value="com.mycompany.converters.HtmlRenderer" />
    <itemname="converters/pdf" type="Object"
         value="com.pdfmonger.PdfRenderer" />
  </config>

清單5C。從JNDI檢索和使用物件

public void convert(InputStream in, OutputStream out) {
    // Retrieve the converter object fromJNDI
    Context context = newInitialContext();
    Renderer renderer = (Renderer)context.lookup("converters/html");
    // Use the converter object
    renderer.convert(in, out);
  }

    正如你可以看到,從JNDI中檢索物件是相當方便,簡單。通過使用JNDI來儲存配置資訊,無狀態物件或物件的工廠,你可以輕鬆地構建靈活的應用程式包含了配置的複雜性在一個地方,同時,即使是分散式應用程式。(如果您的元件從JNDI名稱空間訪問物件,在元件的Javadoc中記錄這些依賴關係。)

JNDI是不是隻是用於J2EE

    儘管JNDI客戶端介面是J2SE發行版的一部分,大多數的J2SE應用程式不使用JNDI。那些做一般只使用JNDI來訪問外部的目錄服務(如LDAP)。然而,J2SE應用程式也可以使用部署時繫結,只有J2EE應用程式通常都使用迄今為止功能。有了這樣JNP可自由檢視的JNDI提供者的實現,需要一個命名服務的任何應用程式可以擁有一個。