2 JNDI的体系结构
nEE.2.6.9 Java Naming and Directory Interface™
(JNDI)The JNDI API is the standard API for naming and directory access. The JNDI API has two parts: an application-level interface used by the application components to access naming and directory services and a service provider interface to attach a provider of a naming and directory service.
nJNDI包含一组API和一组SPI(Service Provider Interface)。
JDBC对每个数据库有独立的驱动程序,JNDI的思想是提供一个通用的接口。底层的名字服务实现可以是各种类型,JNDI通过SPI实现代码屏蔽了各种名字和目录服务实现的区别。
nJava 程序通过JNDI API 存取各种naming和 directory服务。
3 JNDI的包和类
nJNDI 由若干个独立的包组成
n基础包—javax.naming
从中获得JNDI核心概念的定义。
n服务提供程序包—javax.naming.spi
n特定服务提供程序的实际实现存放在独立的包中
javax.naming.directory、 javax.naming.event和javax.naming.ldap 。
n基础包javax.naming包含命名服务的类 (classes)和存取接口(interfaces for accessing)
n其中 Context接口让用户定义对象在名称空间中的「相对位置」。 naming服务以context为接口,提供查看、绑定、对象更名(renaming objects)等功能。
n InitialContext提供naming或 directory服务的一个起始位置。因为在JNDI的世界中没有绝对的root观念,所有的动作都建立在context上;有了起始位置,使用者才能借助它对其 context上的对象进行存取。
nNamingExceptionapi则为JNDI定义的一组类,负责捕获 (catch)所有发生在 naming或directory 服务里的异常 (exceptions)。
njavax.naming.directory 包由 javax.naming扩充而来,提供存取 directory服务的功能——建立在naming 服务之上,增加对directory中的对象检索其属性( retrieve attributes)和通过指定属性为条件来搜寻(search)等功能。其中
n DirContext api提供对象在directory内context的接口,与 Context api的运作方式类似,但更进一步定义了查询和更新directory中对象属性的方法( methods)。
njavax.naming.spi 让系统开发者为特定的naming或 directory系统来撰写使用JNDI的应用程式,例如在 Plug-ins、Java Object Support及 Multiple Naming Systems(Federation)等方面的应用。
3命名服务的应用编程
n命名服务的应用编程
类似于数据库编程,需要在用户代码和数据库之间建立连接。
命名的例子
n要求:
n命令行参数作为名字来查找一个对象;
n使用文件系统的服务提供者,用户向程序提供的名字必须是一个文件名;
n用户不了解服务提供者的细节。
n步骤
1.引入JNDI类 Context、InitialContext、NamingException
2.创建初始上下文空间
3.通过上下文查找对象 Object obj=ctx.lookup();
3.捕获异常
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import java.util.Hashtable;
public class Lookup {
public static void main(String[] args) {
if(args.length!=1)
{
System.err.println("usage: ");
System.exit(-1); }
String name=args[0];
Hashtable env=new Hashtable(11);
env.put(Context.INITIAL_CONTEXT_FACTORY,"com.sun.jndi.fscontext.RefFSContextFactory");
//指明Service provider是文件系统.
try {
Context ctx = new InitialContext(env);
Object obj=ctx.lookup(name);
System.out.println(name+ " is bound to: "+obj);
ctx.close();
} catch (NamingException e) { System.err.println("problem look "+":"+e);
}
}
}
String name=args[0];
Hashtable env=new Hashtable(11);
env.put(Context.INITIAL_CONTEXT_FACTORY,
"com.sun.jndi.fscontext.RefFSContextFactory");
//指明Service provider是文件系统.
try {
Context ctx = new InitialContext(env);
Object obj=ctx.lookup(name);
System.out.println(name+“ is bound to: "+obj);
ctx.close();
}
使用系统属性
nJNDI使用大量的系统属性定义自身的行为。比如属性名javax.naming.factory.initial是服务提供程序提供的InitialContext实现工厂。
n为了方便,属性中的一些以在Context接口中的常量方式存在。例如,使用代码(不是命令行)初始化工厂,使用下列语句将服务提供程序设置为Sun的文件系统实现(传统方法):
System.setProperty(Context.INITIAL_CONTEXT_FACTORY,
"com.sun.jndi.fscontext.RefFSContextFactory");
在一些情况下,可能希望JNDI有几个不同的服务提供程序。企业级的安全环境不允许到处任意设置系统属性。
为了克服系统属性限制,需要使用一套新的InitialContext对象的构造函数。修订后的构造函数使用Hashtable做参数。
n C:/j2sdk1.4.0/bin/jndi_example>java Lookup /temp
n/temp is bound to:com.sun.jndi.fscontext.RefFSContext@87816d
运行条件
为了运行程序你要到[url]http://java.sun.com/products/jndi/downloads/index.html[/url]下载JNDI的相关包,然后把两个jar:fscontext.jar和providerutil.jar加入到CLASSPATH中。
Context ctx = new InitialContext();是以文件系统为初始上下文,这样一来你可以把String name = "C:/aaa.txt“;换成你系统中的任意目录和文件的路径名.
命名操作
n命名操作
n1.查找一个对象
n2.列出命名空间的内容
n3.增加、改写和删除一个绑定
n4.重命名一个对象
n5.创建并析构一个子命名空间
n1.查找一个对象
n通过命名服务查找一个对象,用context.lookup()函数。参数为对象的名字,返回对象,其类型由底层命名系统和对象本身关联的数据共同决定。一个命名系统中可能包含多种类型的对象。
import javax.naming.NamingException;
import java.io.File;
import java.util.Hashtable;
import javax.naming.Context;
import javax.naming.InitialContext;
public class Lookup {
public static void main(String[] args) {
Hashtable env=new Hashtable(11); env.put(Context.INITIAL_CONTEXT_FACTORY,"com.sun.jndi.fscontext.RefFSContextFactory");
env.put(Context.PROVIDER_URL,"file:/temp/tutorial");
try {
Context ctx = new InitialContext(env);
File f=(File)ctx.lookup("abc.txt");
System.out.println(f);
ctx.close();
} catch (NamingException e) { System.err.println("Lookup failed: "+e);
}
}
}
查找一个对象
n运行环境与结果
n环境 C:/temp/tutorial/abc.txt
n结果
执行语句System.out.println(f); C:/temp/tutorial/abc.txt
2.列出命名空间的内容
n使用context.lookup()函数,可以查找单一对象,也可以列举整个上下文。
n例中使用Context.list(),返回NameClassPair的一个枚举类型的集合。每个NameClassPair由对象的名字和它的类名组成。
import java.util.Hashtable;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.naming.NamingEnumeration;
import javax.naming.NameClassPair;
public class List {
public static void main(String[] args) {
Hashtable env=new Hashtable(11);
env.put(Context.INITIAL_CONTEXT_FACTORY,"com.sun.jndi.fscontext.RefFSContextFactory");
env.put(Context.PROVIDER_URL,“file:/”); //操作相对程序运行的盘的根目录
try {
Context ctx = new InitialContext(env);
NamingEnumeration list =ctx.list("temp");
while(list.hasMore()) {
NameClassPair ne=(NameClassPair)list.next();
System.out.println(ne);
}
ctx.close();
} catch (NamingException e) { System.err.println("List failed: "+e);
}
}
}
C:/j2sdk1.4.0/bin/jndi_example>java List
ext42338: javax.naming.Context
lpt$vpn.zip: java.io.File
sysclean_1053_p167.com: java.io.File
sysclean.log: java.io.File
tutorial: javax.naming.Context
3.增加、改写和删除一个绑定
n上下文空间接口中,包含了增加、改写和删除一个绑定的方法。
n绑定的对象必须是引用对象和可引用的对象。如果下例中的Car是普通类,则不能运行,而抛出如下异常。
Lookup failed: javax.naming.OperationNotSupportedException: Can only bind References or Referenceable objects
相应技术 see
http://java.sun.com/products/jndi/tutorial/basics/naming/bind.html
import javax.naming.NamingException;
import java.io.File;
import java.util.Hashtable;
import javax.naming.Context;
import javax.naming.InitialContext;
public class Bind{
public static void main(String[] args) {
Hashtable env=new Hashtable(11); env.put(Context.INITIAL_CONTEXT_FACTORY,"com.sun.jndi.fscontext.RefFSContextFactory");
env.put(Context.PROVIDER_URL,"file:/temp/tutorial");
try {
Context ctx = new InitialContext(env);
Car car=new Car("taxi");
ctx.bind("favorite",car);
Object obj=ctx.lookup("favorite");
System.out.println(obj);
ctx.close();
} catch (NamingException e) { System.err.println("Lookup failed: "+e);
}
}
}
正确例子
n创建可引用的类 Car.class;
n之前,通过实现接口ObjectFactory 创建CarFactory 。
import javax.naming.*;
import javax.naming.spi.ObjectFactory;
import java.util.Hashtable;
/**
* This is an object factory that when given a reference for a Car
* object, will create an instance of the corresponding Car.
*/
public class CarFactory implements ObjectFactory {
public CarFactory() { }
public Object getObjectInstance(Object obj, Name name, Context ctx,
Hashtable env) throws Exception {
if (obj instanceof Reference) {
Reference ref = (Reference)obj;
if (ref.getClassName().equals(Car.class.getName())) {
RefAddr addr = ref.get("car");
if (addr != null) {
return new Car((String)addr.getContent());
}
}
}
return null;
}
import javax.naming.*;
public class Car implements Referenceable {
String car;
public Car(String c) {car=c;}
public Reference getReference() throws NamingException {
return new Reference(
Car.class.getName(),new StringRefAddr("car",car),CarFactory.class.getName(),null);
}
public String toString() {
return car;
}
}
4.创建并析构一个子命名空间
n在上下文空间的接口中,包含了创建并析构子空间(在file system中相当于子文件夹)的方法。语句为:
Context result=ctx.createSubcontext(“”);
和
ctx.destroySubcontext(“”);
import java.util.Hashtable;
import java.io.File;
import javax.naming.*;
public class Create {
public static void main(String[] args) {
Hashtable env=new Hashtable(11); env.put(Context.INITIAL_CONTEXT_FACTORY,"com.sun.jndi.fscontext.RefFSContextFactory");
env.put(Context.PROVIDER_URL,"file:/temp/tutorial");
try {
Context ctx = new InitialContext(env);
Context result=ctx.createSubcontext("new");
NamingEnumeration list =ctx.list("");
while(list.hasMore()) {
NameClassPair ne=(NameClassPair)list.next();
System.out.println(ne);
}
ctx.close();
} catch (NamingException e) { System.err.println("List failed: "+e);
}
}
}
运行结果
在C:/temp/tutorial中新建文件夹new。
import java.util.Hashtable;
import java.io.File;
import javax.naming.*;
public class Destroy {
public static void main(String[] args) {
Hashtable env=new Hashtable(11);
env.put(Context.INITIAL_CONTEXT_FACTORY,"com.sun.jndi.fscontext.RefFSContextFactory");
env.put(Context.PROVIDER_URL,"file:/temp/tutorial");
try {
Context ctx = new InitialContext(env);
ctx.destroySubcontext("new");
NamingEnumeration list =ctx.list("");
while(list.hasMore()) {
NameClassPair ne=(NameClassPair)list.next();
System.out.println(ne);
}
ctx.close();
} catch (NamingException e) { System.err.println("List failed: "+e);
}
}
}