开发基于JNDI的应用程序1

    Java命名和目录接口(Java Naming and Directory Interface JNDI)是用于从Java应用程序中访问名称和目录服务的一组API。命名服务即将名称与对象相关联,以便能通过相应名称访问这些对象。而目录服务即其对象具有属性及名称的命名服务。

命名或目录服务允许您集中管理共享信息的存储,这在网络应用程序中很重要,因为它可以使这类应用程序更加一致和易于管理。例如,可以将打印机配置存储在目录服务中,这样所有与打印机相关的应用程序都能够使用它。

本文是一份代码密集型的快速入门指南,让您开始了解和使用JNDI。它:

  • 提供对JNDI的综述。
  • 描述JNDI的特性。
  • 提供使用JNDI开发应用程序过程中的体验。
  • 说明如何使用JNDI访问 LDAP 服务器,比如Sun ONE Directory Server
  • 说明如何使用 JNDI 访问J2EE 服务。
  • 提供示例代码,您可以对其进行修改,以用于您自己的应用程序。

JNDI综述

我们所有人每天都在不自知的情况下使用命名服务。例如,当您在浏览器中输入URL http://java.sun.com 时,域名系统(Domain Name System DNS)将这个以符号表示的URL转换为一个通信标识符(IP地址)。在命名系统中,对象的范围可以从位于DNS记录中的名称变动到应用程序服务器中的企业JavaBeans组件(Enterprise JavaBeans Components EJBs),还可以到轻量级目录访问协议(Lightweight Directory Access Protocol LDAP)中的用户配置文件。

目录服务是命名服务的自然扩展。二者的关键区别在于,目录服务允许属性(比如用户的电子邮件地址)与对象相关联,而命名服务则不然。这样,使用目录服务时,您可以基于对象的属性来搜索它们。JNDI允许您访问文件系统中的文件,定位远程RMI注册表中的对象,访问诸如LDAP这样的目录服务,并定位网络上的EJB

很多应用程序选择使用JNDI都可以收到良好的效果,比如LDAP客户端、应用程序启动器、类浏览器、网络管理实用工具,或者甚至是地址簿。

JNDI架构

JNDI架构提供了一个标准的、与命名系统无关的API,这个API构建在特定于命名系统的驱动程序之上。这一层帮助把应用程序和实际的数据源隔离开来,因此无论应用程序是访问LDAPRMIDNS还是其他的目录服务,这都没有关系。换句话说,JNDI与任何特定的目录服务实现无关,您可以使用任何目录,只要您拥有相应的服务提供程序接口(或驱动程序)即可,如图1所示。


1: JNDI架构

注意,关于JNDI有一点很重要,即它同时提供应用程序编程接口(Application Programming Interface API)和服务提供程序接口(Service Provider Interface SPI)。这样做的实际意义在于,对于您的与命名或目录服务交互的应用程序来说,必须存在用于该服务的一个JNDI服务提供程序,这便是JNDI SPI发挥作用的舞台。一个服务提供程序基本上就是一组类,这些类针对特定的命名和目录服务实现了各种JNDI接口——这与JDBC驱动程序针对特定的数据系统实现各种JDBC接口极为相似。作为一名应用程序开发人员,您不需要担心JNDI SPI.。您只需确保,您为每个想使用的命名或目录服务提供了一个服务提供程序。

J2SEJNDI

JNDI被包含在Java 2 SDK 1.3 及其更新版本中。它还可以用作JDK 1.11.2的一个标准扩展。 Java 2 SDK 1.4.x的最新版本进行了改进,将以下命名/目录服务提供程序包括进来:

  • 轻量级目录访问协议Lightweight Directory Access ProtocolLDAP) 服务提供程序。
  • 公共对象请求代理架构(Common Object Request Broker Architecture CORBA)公共对象服务(Common Object Services COS)命名服务提供程序。
  • Java远程方法调用( Remote Method Invocation RMI)注册表服务提供程序。
  • 域名系统 Domain Name System DNS) 服务提供程序。

有关服务提供程序的更多内容

这里可以下载一系列服务提供程序。Windows注册表JNDI 提供程序(来自cogentlogic.com)可能会引起您特别的兴趣,因为它允许您访问Windows XP/2000/NT/Me/9x上的注册表。

此外,还可以下载JNDI/LDAP Bootster Pack。这个增强补丁包含对流行的LDAP控件和扩展的支持。它代替了与LDAP 1.2.1服务提供程序捆绑在一起的增强补丁。参见 Controls and Extensions 以获得更多信息。

另一个要考察的有趣的服务提供程序是SunDirectory Services Markup Language (DSML) v2.0提供程序。 DSML的目标是将目录服务与XML连接起来

JNDI API

JNDI API 包括5个包:

  • javax.naming: 包含用于访问命名服务的类和接口。例如,它定义了Context接口,该接口是执行查找时命名服务的入口点。
  • javax.naming.directory:扩展命名包以提供用于访问目录服务的类和接口。例如,它增加了新的属性类,提供代表一个目录上下文的DirContext 接口,并且定义了用于检查和更新与目录对象相关的属性的方法。
  • javax.naming.event: 当访问命名和目录服务时,为事件通知提供支持。例如,它定义了一个NamingEvent类,用于表示由命名/目录服务生成的事件,以及一个监视NamingEvents 类的, NamingListener 接口。
  • javax.naming.ldap: 这个包为LDAP 版本 3 扩展操作和空间提供特定的支持,而普通的javax.naming.directory 包没有提供这些支持。
  • javax.naming.spi: 这个包提供方法以动态插入对通过javax.naming及其相关包访问命名和目录服务的支持。只有那些对创建服务提供程序有着浓厚兴趣的开发人员才应该对这个包感兴趣。

JNDI 上下文

承前所述,命名服务是将名称与对象相关联。这种关联被称为绑定。一组这样的绑定被称为上下文,它提供返回对象的分解或查找操作。其他操作还可能包括绑定与解除绑定名称,以及列出被绑定的名称。注意,可以将一个上下文对象中的名称绑定到具有同样命名惯例的另一个上下文对象上。这被称为子上下文。例如,如果UNIX目录/home 是一个上下文,那么名称与其相关的目录便是子上下文。例如,/home/guests.,这里的guests 便是 home个子上下文。

JNDI中,上下文是使用javax.naming.Context 接口来表示的,而这个接口也正是与命名服务进行交互的主要接口。Context (或稍后将要讨论的DirContext)接口中的每个命名方法都有两种重载的形式:

  • lookup(String name): 接受一个字符串名称。
  • lookup(javax.naming.Name): 接受一个结构化的名称,比如CompositeName (一个跨越多个命名系统的名称) CompondName (一个位于单个命名系统中的名称);二者均实现了Name 接口。下面是一个复合名称的例子: cn=mydir,cn=Q Mahmoud,ou=People,还有一个组合名称的例子: cn=mydir,cn=Q Mahmoud,ou=People/myfiles/max.txt (这里的myfiles/max.txt 是代表第二部分的一个文件名)

javax.naming.InitialContext 是一个实现了 Context接口的类。使用这个类作为您到命名服务的入口点。要创建一个InitialContext 对象,构造器需要采用一组属性,形式为java.util.Hashtable 或其子类之一,比如Properties.。下面是一个例子:

Hashtable env = new Hashtable();

// select a service provider factory

env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.fscontext.RefFSContext");

// create the initial context

Context contxt = new InitialContext(env);

INITIAL_CONTEXT_FACTORY 指定JNDI服务提供程序中工厂类的名称。该工厂负责为其服务创建一个合适的InitialContext 对象。在上面的代码片断中,指定了用于文件系统服务提供程序的一个工厂类。表1列出了用于所支持的服务提供程序的工厂类。注意,用于文件系统服务提供程序的工厂类需要Sun Microsystems单独下载,它并没有与J2SE 1.4.x一起发行。

1: Context.INITIAL_CONTEXT_FACTORY的值

名称

服务提供程序工厂

文件系统

com.sun.jndi.fscontext.RefFSContextFactory

LDAP

com.sun.jndi.ldap.LdapCtxFactory

RMI

com.sun.jndi.rmi.registry.RegistryContextFactory

CORBA

com.sun.jndi.cosnaming.CNCtxFactory

DNS

com.sun.jndi.dns.DnsContextFactory

要通过来自命名或目录服务的名称检索或解析(查找)一个对象,使用Context: Object obj = contxt.lookup(name)lookup方法。lookup 方法返回一个对象,该对象代表您想要查找的上下文的子上下文。

一个命名的例子

现在,让我们看一看一个使用命名服务的例子。在这个例子中,我们编写了一个简单的程序,用于查找一个其名称被当作命令行参数传入的对象。在这里,我们将使用一个用于文件系统的服务提供程序,而且因此,我们提供作为参数的名称必须是一个文件名。示例代码1中给出了相应代码。

示例代码 1: Resolve.java

import javax.naming.Context;

import javax.naming.InitialContext;

import javax.naming.NamingException;

import java.util.Hashtable;

public class Resolve {

   public static void main(String argv[]) {

      // The user should provide a file to lookup

      if (argv.length != 1) {

         System.err.println("Usage: java Resolve ");

         System.exit(-1);

      }

      String name = argv[0];

      // Here we use the file system service provider

      Hashtable env = new Hashtable();

      env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.fscontext.RefFSContextFactory");

      try {

         // Create the initial context

         Context ctx = new InitialContext(env);

         // Look up an object

         Object obj = ctx.lookup(name);

         // Print it out

         System.out.println(name + " is bound to: " + obj);

         // Close the context

         ctx.close();

      } catch (NamingException e) {

         System.err.println("Problem looking up " + name + ": " + e);

      }

   }

}

在这里,我假定您使用的是Java 2SDK 1.4.x,它附带有几个服务提供程序(上面已经列出)。这个应用程序要使用文件系统服务提供程序 ,而在默认情况下,文件系统服务提供程序并未安装。因此,您需要下载并安装它。另一方面,如果您运行这个程序,而服务提供程序却还没有被安装,您将得到一个NoInitialContextException,意指无法找到服务提供程序工厂类,因此不能初始化这个类。接着,您需要在您的classpath中包括fscontext.jar providerutil.jar——或者像我一样,您可以简单地将这两个文件拷贝至JAVA_HOME\jre\lib\ext,这里的 JAVA_HOME 是指您的Java 2SDK安装的根目录。

要测试这个应用程序:

1.         确保您已经下载并安装了文件系统服务提供程序(正如上一段所讲的那样),因为这个服务提供程序并没有与J2SE 1.4.x一起提供。

2.         拷贝代码并将其粘贴到文件中,并将文件命名为Resolve.java

3.         使用javac 编译 Resolve.java

4.         使用java 解释器运行应用程序。

下面是一次示范运行:

prompt> java Resolve \classes

\classes is bound to: com.sun.jndi.fscontext.FSContext@f62373

如果您提供的名称是一个文件名,您将看到如下结果:

prompt> java Resolve \classes\Resolve.java

\classes\Resolve.java is bound to: C:\classes\Resolve.java

列出文件目录的内容

现在,让我们看一看如何使用其他JNDI API列出一个文件目录的内容。我们假定,您想让用户能够使用file:///这样的URL 来指定命令行参数。在这种情况下,您要设置一个新的属性PROVIDER_URL,如示例代码2所示。Context listBindings 方法返回一个 NamingEnumeration对象,可以通过使用一个while 循环来迭代这个对象,如示例代码 2所示。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值