Java 技术专题——帮你彻底搞懂 JNDI(附详细实例)

本贴最后更新于 2525 天前,其中的信息可能已经时移俗易

1. 什么是 JNDI?

JNDI(Java Naming and Directory Interface,Java 命名和目录接口)是 SUN 公司提供的一种标准的 Java 命名系统接口,JNDI 提供统一的客户端 API,通过不同的访问提供者接口 JNDI 服务供应接口(SPI)的实现,由管理者将 JNDI API 映射为特定的命名服务和目录系统,使得 Java 应用程序可以和这些命名服务和目录服务之间进行交互。

对于 JNDI 的概念不少同学表示,一看就觉得头疼,根本没有想耐下心看的兴趣。为此,博主将上面复杂的概念拆分成一些简单的概念要点,帮助大家更好地理解 JNDI 的概念:

  1. JNDI 本质上是一系列通用的标准的用来操作命名服务和目录服务的接口: 换句话说,这一系列的接口就是对操作所有命名服务和目录服务的一种超级抽象,有了这些接口我们就可以用通用的接口操作各式各样的命名服务或者是目录服务,而不需要每次与一种服务交互就写一次操作该服务的代码,始终记住一个宗旨,以抽象应对改变。
  2. JNDI 的这些通用接口需要依靠服务供应接口(SPI)的实现来将通用的接口映射为特定的命名或目录服务,使客户端能够和指定的服务进行交互:这句话的意思就是尽管虽然提供了一系列超级抽象版的通用接口 API 供客户端使用,但是使用这些接口的人该怎么知道用这些接口是在访问一个文件目录服务还是一个 DNS 命名服务呢?因此 JNDI 又提供了一系列的服务提供者接口(SPI),所有的服务供应商只要根据这些 SPI 去提供自己服务的实现,客户在使用通用接口时引入这些 SPI 的实现类,就可以操作指定的服务了。

2. 命名服务与目录服务

JNDI 的目的就是对命名服务(Naming Service)与目录服务(Directory)中的资源进行查找或者管理,那么什么是命名服务,什么又是目录服务呢?

命名服务的概念其实很好理解,在生活中也有很多的例子,最典型的就是 DNS(Domain Naming Service)了。众所周知,DNS 是用来对人类更便于记忆的域名和计算机更便于记忆的 IP 地址进行映射的。因此命名服务的核心就在于映射,讲一个值映射成另一个值。

至于目录服务呢,它其实是命名服务的一种自然扩展,两者之间的关键差别是目录服务中对象可以有属性,而命名服务中对象没有属性。举个简单的例子吧,我们手机中的电话簿就是一个典型的目录服务。它将一个电话号码映射成了拥有这个号码的人,但是人这个对象不仅仅会有姓名(尽管姓名最重要),这也就是为什么电话簿中还可以增加这个人的家庭住址,公司,电子邮件,电话铃声等等。

3. JNDI 架构

e7a6008a18a547a8a38b310e689a0221-JNDI.jpg

JNDI 架构提供了一组标准的独立于命名系统的 API,这些 API 构建在与命名系统有关的驱动之上。这一层有助于将应用与实际数据源分离,因此不管应用访问的是 LDAP、RMI、DNS、还是其他的目录服务。换句话说,JNDI 独立于目录服务的具体实现,只要有目录的服务提供接口(或驱动),就可以使用目录。

关于 JNDI 要注意的重要一点是,它提供了应用编程接口(application programming interface,API)和服务提供者接口(service provider interface,SPI)。这一点的真正含义是,要让应用与命名服务或目录服务交互,必须有这个服务的 JNDI 服务提供者,这正是 JNDI SPI 发挥作用的地方。服务提供者基本上是一组类,这些类为各种具体的命名和目录服务实现了 JNDI 接口—很像 JDBC 驱动为各种具体的数据库系统实现了 JDBC 接口一样。作为一个应用开发者,我们不必操心 JNDI SPI 的具体实现。只需要确认要使用的某一个命名或目录服务都有服务提供者。

JNDI 提供了如下几个程序包:

  1. Javax.naming:包含了访问命名服务的类和接口。例如,它定义了 Context 接口,这是命名服务执行查询的入口。

  2. Javax.naming.directory:对命名包的扩充,提供了访问目录服务的类和接口。例如,它为属性增加了新的类,提供了表示目录上下文的 DirContext 接口,定义了检查和更新目录对象的属性的方法。

  3. Javax.naming.event:提供了对访问命名和目录服务时的事件通知的支持。例如,定义了 NamingEvent 类,这个类用来表示命名/目录服务产生的事件,定义了侦听 NamingEvents 的 NamingListener 接口。

  4. Javax.naming.ldap:这个包提供了对 LDAP 版本 3 扩充的操作和控制的支持,通用包 javax.naming.directory 没有包含这些操作和控制。

  5. Javax.naming.spi:这个包提供了一个方法,通过 javax.naming 和有关包动态增加对访问命名和目录服务的支持。这个包是为有兴趣创建服务提供者的开发者提供的。

4. JNDI 实例

正所谓光说不练假把式,下面楼主就和大家一起写一个 JNDI 的例子,来巩固一下上面的知识。

正如博主上面所讲,要使用 JNDI,必须有服务供应商按照 SPI 所提供的服务实现,为了省下我们的大量时间,我们采用 SUN 公司官方提供的文件系统服务提供者(File System Service Provider, FSSP),这个服务提供者是用来帮助用户操作文件系统的。

首先我们需要下载 FSSP 的官方资源包

4f0144a25cfc435a872cd71c120598bb-FSSP.png

当然,大家也可以直接使用我的项目,但是官方包中会有一些官方的帮助文档对初次使用的朋友们还是比较有帮助的。

下面是我为大家写的一个连接了本地的文件系统的例子,当然我们需要将 fscontext.jar 和 providerutil.jar 加载到 classpath 下:

public class FSSPTest {

	public static void main(String[] args) throws NamingException {
		// TODO Auto-generated method stub
		Hashtable<String,String> env = new Hashtable<>();
		//指明初始化的factory是我们下载的jar包中的RefFSContextFactory
		env.put(Context.INITIAL_CONTEXT_FACTORY, 
			    "com.sun.jndi.fscontext.RefFSContextFactory");
		//指明Context的初始URL,这里我们的是C盘
		env.put(Context.PROVIDER_URL,"file:///c:/");
		
		Context ctx = new InitialContext(env);
		
		//在C盘下创建要给文件夹名为JesminDir
		ctx.createSubcontext("JesminDir");
		
		//在C盘下定位myFile文件
		File f =  (File) ctx.lookup("myFile");
		System.out.println(f);
	
		//列出当前context下的所有元素的名称和类型(包括文件夹和文件)
		NamingEnumeration list = ctx.list("/"); 
		while (list.hasMore()) { 
		    NameClassPair nc = (NameClassPair)list.next(); 
		    System.out.println(nc); 
		}
	}
}
  • B3log

    B3log 是一个开源组织,名字来源于“Bulletin Board Blog”缩写,目标是将独立博客与论坛结合,形成一种新的网络社区体验,详细请看 B3log 构思。目前 B3log 已经开源了多款产品:SymSoloVditor思源笔记

    1063 引用 • 3453 回帖 • 203 关注
  • Java

    Java 是一种可以撰写跨平台应用软件的面向对象的程序设计语言,是由 Sun Microsystems 公司于 1995 年 5 月推出的。Java 技术具有卓越的通用性、高效性、平台移植性和安全性。

    3187 引用 • 8213 回帖

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...