什么是JNDI

JNDI (Java Naming and Directory Interface) 即Java命名和目录接口。它是使用Java编写的为应用程序提供命名和目录服务的接口,独立于任何特定的目录服务实现。

命名服务

名字和对象(Name and Object)

命名服务就是将名字(Name)和对象(Object)联系起来,并通过名字查询对象。

命名服务在计算机系统中非常广泛,例如DNS(Internet Domain Name Systm)中通过域名查找IP地址;在文件系统中通过文件名查找文件并访问文件内容。

上下文(Context)

命名服务中,上下文(Context)表示名字到对象绑定的集合。每个上下文都有对应的命名规范。上下文提供了查找、绑定、解绑对象的接口。一个上下文对象可以绑定到另一个上下文,那么它就是另一个上下文的子上下文(SubContext)。

命名系统和命名空间

命名系统包含一组具有相同命名规范的命名上下文,并提供了统一的操作接口进行相关的操作。例如,实现了DNS的命名系统,实现了LDAP的命名系统。
命名空间是指命名系统中所有可能的名字。

目录服务

目录服务是命名服务的扩展,在目录服务中,不仅提供了名字到对象的绑定,每个对象还可以关联多个属性。
也就是说:目录服务=命名服务+对象包含一组属性。同时目录服务还提供了一组操作属性的接口。

目录服务与命名服务的区别另一个区别是,目录服务通常将对象保存在层次结构中。

JNDI的作用

  • JNDI可以帮助代码实现解藕,比如隐藏数据库连接信息。
  • JNDI在迁移应用到不同环境时非常有用,比如从开发环境迁移到测试环境,再到生产环境,虽然使用的时同一个name,但是获取到的数据却回根据环境的不同而改变。这样就不需要因为切换环境而修改代码。
  • 远程调用

JNDI实践

JNDI架构及API

JNDI体系结构由API和服务提供者接口(SPI)组成。Java应用程序使用JNDI API来访问各种命名和目录服务。SPI允许透明地插入各种命名和目录服务,从而允许使用JNDI API的Java应用程序访问其服务。

JNDI包含在Java SE平台中。要使用JNDI,您必须具有JNDI类和一个或多个服务提供者。JDK包括以下命名/目录服务的服务提供者:

  • 轻量级目录访问协议(LDAP)
  • 公共对象请求代理体系结构(CORBA)公共对象服务(COS)名称服务
  • Java远程方法调用(RMI)注册表
  • 域名服务(DNS)


JNDI的接口在5个包下:

  • javax.naming: 命名服务API。
  • javax.naming.directory: 目录服务API。
  • javax.naming.spi: 服务提供者要提供JNDI服务时需要使用的类。
  • javax.naming.ldap: 提供了对LDAP 版本3扩充的操作和控制的支持。
  • javax.naming.event: 命名和目录服务支持事件通知的类和接口。


javax.naming.Context表示一个命名上下文,由一组名称到对象的绑定组成。Context是命名服务的核心接口,包含一组查询、绑定/解绑、重命名对象的方法创建和销毁子命名上下文的方法。例如:

  • Context#lookup(Name name): 查询指定名称的对象。
  • Context#bind(Name name, Object obj): 将名称绑定到对象。
  • Context#unbind(Name name): 取消对指定对象的绑定。
  • Context#rename(Name oldName, Name newName): 重命名对象。
  • Context#createSubcontext(Name name): 创建并绑定子上下文。
  • Context#destroySubcontext(Name name): 销毁子上下文。

在JNDI中,所有的命名和目录服务操作都是在相关的某个上下文中进行的。JNDI定义了一个Context接口的实现类javax.naming. InitialContext作为服务的起点。

JNDI代码范例

选择一个JNDI服务提供者

要使用JNDI就需要至少有一个服务提供者。以LDAP为例,那就需要先搭建一个LDAP服务器。有多种免费的LDAP服务器可供选择:

这里是一篇Apache Directory Studio的使用

配置Context

有了LDAP服务器之后就可以在客户端使用服务了,首先要配置Context,三个步骤:

  1. 选择想要访问的服务对应的服务提供者
    Hashtable<String, Object> env = new Hashtable<>();
    env.put(Context.INITIAL_CONTEXT_FACTORY,"com.sun.jndi.ldap.LdapCtxFactory");
    
  2. 指定InitialContext需要的配置
    //服务提供者地址
    env.put(Context.PROVIDER_URL,"ldap://ldap.openldap.org");
    //认证信息
    env.put(Context.SECURITY_PRINCIPAL,"userName");
    env.put(Context.SECURITY_CREDENTIALS,"password");
    
  3. 构造InitialContext
    Context context = new InitialContext(env);
    

之后就可以使用 context进行响应的操作。

参考链接