JNDI 筆記(轉)

JNDI 筆記(轉)

JNDI 筆記(一) 概述html

JNDI,Java Naming Directory Interface,J2EE的標準之一,全部的J2EE容器都必須提供一個JNDI的服務,可是,我一直都沒用過,至少是沒有刻意地去用過。由於,我也曾經把數據源配置在Tomcat的JNDI服務中,但那時,我也只是剛剛涉足JAVA,有人告訴我應該這麼幹而已。後來,我開始使用自定義的數據庫鏈接配置文件,就再也沒有跟JNDI打過交道了,直到今天。

如今之因此又想看一下,只是由於以爲這是J2EE的重要標準之一,若是不懂得的話,彷佛有點說不過去。

JNDI的主要功能能夠這樣描述,它使用一張哈希表存儲對象(大多數的J2EE容器也的確是這樣作的),而後,開發人員可使用鍵值——也就是一個字符串——來獲取這個對象。這裏就包括取JNDI的兩個最主要操做,bind和lookup。bind操做負責往哈希表裏存對象,存對象的時候要定義好對象的鍵值字符串,lookup則根據這個鍵值字符串往外取對象。

JNDI的命稱可能會讓人產生混淆,彷佛以爲這是一個用來操做目錄的,事實上,我更願意把這個目錄理解成爲JNDI存放對象時使用的格式,也就是說,JNDI以目錄的方式存儲對象的屬性。例如,用戶經過JNDI存儲一個汽車對象,那麼,汽車就是根目錄,汽車的輪子、引擎之類的子對象就算是子目錄,而屬性,好比說汽車的牌子、重量之類,就算是汽車目錄下的文件。

JNDI的功能既然就是根據一個字符串鍵值就能夠取得一個想要獲得的對象,我一開始就以爲這不是跟COM或CORBA同樣嗎?SUN也是有野心的企業啊,JNDI應該就是它要努力推行的JAVA下的分佈式開發的標準吧。

JNDI的出現應該就是爲了分步式開發服務的,有人負責開發這種分佈式對象,有人只須要使用這些分佈式對象就能夠了,這兩組人沒必要屬於同一個公司,並且這種開發一般應該是不併行的,也沒必要是會了同一個項目服務。就若是數據源對象,它放在JNDI中,只要想要用的人,直接經過JNDI服務取來用就能夠了,至於當初是誰把它放進JNDI中的,仍是不用操這份心了吧。而我一直沒有使用JNDI,也就是這個緣由,項目中的全部對象都在我控制之下,我不去使用別人的對象,也沒打算把個人對象貢獻出來給別人使用,那天然也就不必去跟JNDI打交道。我以爲是否使用JNDI,這應該是關鍵緣由,至於什麼方便性、安全性之類的考慮,應該不是JNDI的主要目的,就如同你能夠用JAVA來作網站,但JAVA並非專門用來作網站的。

可能有人以爲這種功能跟IoC也很象,這個我倒不以爲,雖然對於對象的使用人員來講的確是這種感受,且不說IoC須要爲對象定義接口,而JNDI並沒有此限制,先說這裏有一個使用環境問題,我以爲IoC是用來解決並行開發問題的,也就是說IoC主要是用於明確設計人員與實現/使用人員的分工,不管是設計的,仍是使用的,一般是一個項目組裏的人,使用IoC,可使得設計人員專一於設計,加快設計速度。所以,IoC的用途要比JNDI普遍的多,如今大型系統中,不使用IoC的,幾稀矣。


JNDI 筆記(二) J2EE下使用JNDIjava

在J2EE環境下使用JNDI是很是簡單的事,由於全部的J2EE容器都要實現JNDI服務,因此,在J2EE環境下使用JNDI,與使用Hashtable也沒有什麼太大區別。只有一點限制,那就是綁定對象時,對象所屬的類必須實現java.io.Serializable接口,這一點也實在一點也不困難,幾乎全部用到的Java類都實現了這個接口,對於自定義的類,在接口實現列表裏把這個接口加進去也就是了。web

下面,我將演示一下如何在J2EE環境下使用JNDI,爲了保證代碼的通用性,我不使用struts之類的框架,而是直接使用標準JSP和Servlet實現。我將該項目的名稱定爲jndi_test數據庫

要使用JNDI,須要先到SUN的網站上去下載jndi.jar。安全

 2.1 JSP

本項目包括5個JSP,功能說明以下:服務器

  • index.jsp:首頁
  • bind.jsp:用於在JNDI中綁定對象
  • bind_result.jsp:綁定對象後的返回頁面
  • lookup.jsp:用於在JNDI中檢索對象
  • lookup_result.jsp:用於顯示檢索對象

本節中用到的JSP代碼以下,代碼都簡單地很,就很少作解釋了。app

2.1.1 index.jsp

<% @ page language="java" contentType="text/html; charset=GB18030"
    pageEncoding
="GB18030"
%>
<! DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd" >
< html >
< head >
< meta  http-equiv ="Content-Type"  content ="text/html; charset=GB18030" >
< title > JNDI Test </ title >
</ head >
< body >
< href ="bind.jsp"  target ="_blank" > bind.jsp </ a >
< br  />
< href ="lookup.jsp"  target ="_blank" > lookup.jsp </ a >
</ body >
</ html >

2.1.2 bind.jsp

<% @ page language="java" contentType="text/html; charset=GB18030"
    pageEncoding
="GB18030"
%>
<! DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd" >
< html >
< head >
< meta  http-equiv ="Content-Type"  content ="text/html; charset=GB18030" >
< title > JNDI Test - Bind </ title >
</ head >
< body >
< href ="bind.do" > bind an object </ a >
</ body >
</ html >

2.1.3 bind_result.jsp

<% @ page language="java" contentType="text/html; charset=GB18030"
    pageEncoding
="GB18030"
%>
<! DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd" >
< html >
< head >
< meta  http-equiv ="Content-Type"  content ="text/html; charset=GB18030" >
< title > JNDI Test - Bind result </ title >
</ head >
< body >
< p > Binded successfully! </ p >
</ body >
</ html >

2.1.4 lookup.jsp

<% @ page language="java" contentType="text/html; charset=GB18030"
    pageEncoding
="GB18030"
%>
<! DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd" >
< html >
< head >
< meta  http-equiv ="Content-Type"  content ="text/html; charset=GB18030" >
< title > JNDI Test - lookup </ title >
</ head >
< body >
< href ="lookup.do" > lookup the binded object </ a >
</ body >
</ html >

2.1.5 lookup_result.jsp

<% @ page language="java" contentType="text/html; charset=GB18030"
    pageEncoding
="GB18030"
%>
<! DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd" >
< html >
< head >
< meta  http-equiv ="Content-Type"  content ="text/html; charset=GB18030" >
< title > JNDI Test - Lookup result </ title >
</ head >
< body >
<%
    
Object o = request.getAttribute("found_jndi_obj");
    out.println(o);
%>
</ body >
</ html >

2.2 Servlet

本例包括兩個Servlet,功能說明以下:框架

  • BindServlet:用於在JNDI服務中綁定一個對象
  • LookupServlet:用於在JNDI服務中取出一個對象

2.2.1 BindServlet.java

package  lld.test.jndi;

import  java.io.IOException;
import  java.util.Date;

import  javax.naming.Context;
import  javax.naming.InitialContext;
import  javax.servlet.RequestDispatcher;
import  javax.servlet.ServletContext;
import  javax.servlet.ServletException;
import  javax.servlet.http. * ;

public   class  BindServlet  extends  HttpServlet
{

    
private static final long serialVersionUID = 5219969790998794367L;

    @Override
    
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
            
throws ServletException, IOException
    
{
        
this.doPost(req, resp);
    }


    @Override
    
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
            
throws ServletException, IOException
    
{
        
try
        
{
            Context jndi_ctx 
= new InitialContext();
            String key 
= "jndi_object";
            jndi_ctx.rebind(key, 
new Date());
        }
catch(Exception ex)
        
{
            ex.printStackTrace();
        }

        
        ServletContext context 
= this.getServletContext();
        RequestDispatcher dispatcher 
= context.getRequestDispatcher("/bind_result.jsp");
        dispatcher.forward(req, resp);
    }

    
}

使用rebind而不是bind綁定對象是由於,使用bind時,若是已經有對象綁定到該鍵值上,則會拋出異常。jsp

由於只是示例代碼,因此我只是綁定了一個最簡單的日期對象。分佈式

2.2.2 LookupServlet.java

package  lld.test.jndi;

import  java.io.IOException;

import  javax.naming.Context;
import  javax.naming.InitialContext;
import  javax.servlet.RequestDispatcher;
import  javax.servlet.ServletContext;
import  javax.servlet.ServletException;
import  javax.servlet.http.HttpServlet;
import  javax.servlet.http.HttpServletRequest;
import  javax.servlet.http.HttpServletResponse;

public   class  LookupServlet  extends  HttpServlet
{
    
private static final long serialVersionUID = 6677219828267184673L;

    @Override
    
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
            
throws ServletException, IOException
    
{
        
this.doPost(req, resp);
    }


    @Override
    
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
            
throws ServletException, IOException
    
{
        
try
        
{
            Context jndi_ctx 
= new InitialContext();
            String key 
= "jndi_object";
            Object o 
= jndi_ctx.lookup(key);
            req.setAttribute(
"found_jndi_obj", o);
        }
catch(Exception ex)
        
{
            ex.printStackTrace();
        }

        
        ServletContext context 
= this.getServletContext();
        RequestDispatcher dispatcher 
= context.getRequestDispatcher("/lookup_result.jsp");
        dispatcher.forward(req, resp);
    }

    
}

2.3 web.xml

在web.xml中,加入了servlet映射

<? xml version="1.0" encoding="UTF-8" ?>
< web-app  id ="WebApp_ID"  version ="2.4"  xmlns ="http://java.sun.com/xml/ns/j2ee"  xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance"  xsi:schemaLocation ="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd" >
    
< display-name > jndi_test </ display-name >
    
    
< servlet >
        
< servlet-name > BindServlet </ servlet-name >
        
< servlet-class > lld.test.jndi.BindServlet </ servlet-class >
    
</ servlet >
    
< servlet-mapping >
        
< servlet-name > BindServlet </ servlet-name >
        
< url-pattern > /bind.do </ url-pattern >
    
</ servlet-mapping >
    
    
< servlet >
        
< servlet-name > LookupServlet </ servlet-name >
        
< servlet-class > lld.test.jndi.LookupServlet </ servlet-class >
    
</ servlet >
    
    
< servlet-mapping >
        
< servlet-name > LookupServlet </ servlet-name >
        
< url-pattern > /lookup.do </ url-pattern >
    
</ servlet-mapping >
    
    
< welcome-file-list >
        
< welcome-file > index.jsp </ welcome-file >
    
</ welcome-file-list >
</ web-app >

OK,全部的代碼都在這裏了,部署到Tomcat下運行便可。


JNDI 筆記(三) J2SE下使用JNDI

在J2SE下使用JNDI下就顯得困難一些,首先,咱們沒有單獨的JNDI服務器能夠用,JBoss提供了一個免費的JNP服務,經過配置能夠做爲單獨的JNDI服務器啓用。不過這裏就不這麼麻煩了,如何使用JBOSS做爲JNDI服務器,之後將單獨撰文講述,這裏我使用sun提供的com.sun.jndi.fscontext.RefFSContextFactory做爲JNDI服務器,其實這是使用文件系統來存儲JNDI對象。至於如何存儲後文還將專門描述。

爲了在J2SE下使用JNDI,咱們首先獲得sun的網站上下載3個包,jndi.jar、fscontext.jar和providerutil.jar,前者提供了JNDI服務的接口,後二者是咱們要使用的文件系統做爲JNDI服務器的支持包。

使用RefFSContextFactory,要求綁定的對象必須實現javax.naming.Referencable接口,不然在綁定時將報以下錯誤:

Can only bind References or Referenceable objects

各個JDBC驅動提供商提供的DataSource類都實現了Referencable接口,能夠直接使用。不過本着學習的態度,我仍是在這裏演示一下如何實現Referencable接口。

這個如何實現將在後文結合代碼詳細介紹。本例包括4個類,說明以下:

  • BindedClass:自定義的實現Referenceable接口的類
  • BindedClassFactory:工廠類,可以把一個Reference對象轉換爲BindedClass對象
  • Bind:測試類,用於在JNDI中綁定對象
  • Loopup:測試類,用於從JNDI中獲取對象

3.1 BindedClass和BindedClassFactory

3.1.1 BindedClass

package  lld.test.jndi;

import  javax.naming.NamingException;
import  javax.naming.Reference;
import  javax.naming.Referenceable;
import  javax.naming.StringRefAddr;

public   class  BindedClass  implements  Referenceable 
{
    
public String value; 
    
    
public BindedClass()
    
{
    }

    
    @Override
    
public Reference getReference() throws NamingException
    
{
        Reference r 
= new Reference(this.getClass().getName(), BindedClassFactory.class.getName(), null);
        r.add(
new StringRefAddr("value"this.getValue()));
        
return r;
    }


    
public String getValue()
    
{
        
return value;
    }


    
public void setValue(String value)
    
{
        
this.value = value;
    }


}

3.1.2 BindedClassFactory

package  lld.test.jndi;

import  java.util.Hashtable;

import  javax.naming. * ;
import  javax.naming.spi. * ;

public   class  BindedClassFactory  implements  ObjectFactory
{
    @Override
    
public Object getObjectInstance(Object obj, Name name, Context nameCtx,
            Hashtable
<??> environment) throws Exception
    
{
        
if(obj instanceof Reference)
        
{
            Reference ref 
= (Reference)obj;
            String val 
= (String)ref.get("value").getContent();
            BindedClass o 
= new BindedClass();
            o.setValue(val);
            
return o;
            
        }

        
return null;
    }

}

3.1.3 代碼解釋

Referenable接口只有一個方法,就是getReference(),返回一個Reference對象,BindedClass只設了一個示例成員變量Value,存儲一個字符串值,在建立Refernce對象時,要指定它引用的類名以及建立該類的工廠對象,JNDI Context在綁定該對象時就會將這些信息都存到文件中,未來從JNDI中取對象時可就全靠工廠對象根據文件中的內容重建BindedClass對象了。我這裏提早把綁定後生成的文件內容說一下,你們會更有一個直觀的印象,其內容以下所示:

bind1/RefAddr/0/Type=value
bind1/ClassName=lld.test.jndi.BindedClass
bind1/RefAddr/0/Encoding=String
bind1/FactoryName=lld.test.jndi.BindedClassFactory
bind1/RefAddr/0/Content=abcdefg

你們看到了,前面在BindedClass.getReference()方法中使用了以下語句:

r.add(new StringRefAddr("value", this.getValue()));

就是定義要將這些信息存儲到JNDI中呢,至於最後的「bind1/RefAddr/0/Content=abcdefg」,那是由於我在後面的示例Bind.java中將其值設成了「abcdefg」而已,呵呵。而BindedClassFactory.getObjectInstance()方法中

String val = (String)ref.get("value").getContent();

就是用來取到存儲的值呢。

3.2 Bind.java

本例用來綁定一個BindedClass對象
package  lld.test.jndi;

import  java.util.Properties;

import  javax.naming.Context;
import  javax.naming.directory.DirContext;
import  javax.naming.directory.InitialDirContext;

public   class  Bind
{
    
public static void main(String[] args) throws Exception
    
{
        Properties ps 
= new Properties();
        ps.setProperty(Context.INITIAL_CONTEXT_FACTORY, 
"com.sun.jndi.fscontext.RefFSContextFactory");
        ps.setProperty(Context.PROVIDER_URL, 
"file:JNDI_REF");
        DirContext ctx 
= new InitialDirContext(ps);
        String key 
= "bind1";

        BindedClass b 
= new BindedClass();
        b.setValue(
"abcdefg");
        ctx.rebind(key, b);

        System.out.println(
"Binded successfully!");
        ctx.close();
    }

}

3.3 Lookup.java

本例用來從JNDI中獲取綁定的BindedClass對象

package  lld.test.jndi;

import  java.util.Properties;

import  javax.naming.Context;
import  javax.naming.directory.DirContext;
import  javax.naming.directory.InitialDirContext;

public   class  Lookup
{
    
public static void main(String[] args) throws Exception
    
{
        Properties ps 
= new Properties();
        ps.setProperty(Context.INITIAL_CONTEXT_FACTORY, 
"com.sun.jndi.fscontext.RefFSContextFactory");
        ps.setProperty(Context.PROVIDER_URL, 
"file:JNDI_REF");
        DirContext ctx 
= new InitialDirContext(ps);
        String key 
= "bind1";
        BindedClass o 
= (BindedClass)ctx.lookup(key);
        System.out.println(o.getValue());    
        
        ctx.close();
    }


}



相關文章
相關標籤/搜索