在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();
}
}