1. 概述
Java命名和目录接口(JNDI)是一个应用程序编程接口(API),为基于Java的应用程序提供命名和目录服务。我们可以利用这个接口来绑定对象/资源,查找或查询对象,并检测同一对象的变化。
在本教程中,我们将专门探讨在JNDI命名中使用“java:comp/env”标准前缀的背景。
2. Java命名和目录接口是什么?
简单来说,命名服务是一种将名称与对象关联起来的接口,通过名称帮助我们找到这些对象。因此,命名服务维护一组绑定,将名称映射到对象。
JNDI API使得应用组件和客户端能够查找分布式资源、服务和EJB。
3. 访问命名上下文
Context接口提供了访问命名环境的途径。使用这个对象,我们可以将名称绑定到对象,重命名对象,以及列出绑定。让我们看看如何获取上下文:
JndiTemplate jndiTemplate = new JndiTemplate();
context = (InitialContext) jndiTemplate.getContext();
一旦我们有了上下文,就可以绑定对象:
context.bind("java:comp/env/jdbc/datasource", ds);
然后,我们可以从上下文中检索对象:
context.lookup("java:comp/env/jdbc/datasource");
4. java:comp/env
是什么?
如上例所示,我们使用标准前缀“java:comp/env”绑定一个名称。例如,“java:comp/env/jdbc/datasource”,而不仅仅是“jdbc/datasource”。这个前缀是必需的吗?能否完全避免使用?接下来讨论这个问题。
4.1. 目录服务
正如其名,JNDI是一个命名和目录服务。相应地,目录服务将名称与对象关联,并允许对象具有属性。因此,我们不仅可以根据名称查找对象,还可以获取对象的属性,或者根据属性找到对象。一个生动的例子是电话簿服务,其中订阅者的姓名不仅映射到他的电话号码,还映射到他的地址。
目录通常以层次结构组织对象。在大多数情况下,目录对象存储在树形结构中。所以,第一个元素/节点可能包含组对象,这些组对象又可能包含特定的对象。
例如,在“java:comp/env”中,“comp”是第一个节点,下一层包含“env”节点。从这里,我们可以根据我们的约定存储或访问资源。例如,“jdbc/datasource”用于共享数据源对象。
4.2. 分割
让我们分解一下先前的命名示例:“java:comp/env/jdbc/datasource”。
- java 类似于JDBC连接字符串中的“*jdbc:*”,它充当协议。
- comp 是所有JNDI上下文的根,它绑定到保留给组件相关绑定的子树。名字“comp”代表组件。根上下文没有其他绑定。
- env 名字“env”绑定到一个子树,用于组件环境相关的绑定。env代表环境。
- jdbc 是用于 JDBC 资源的子上下文。还有其他类型,如连接工厂的子上下文。
- datasource 是我们 JDBC 资源的名称。
在这里,除了最后一个元素外,所有父级元素都是标准名称,因此不能更改。
此外,根上下文被预留用于未来扩展策略。特别是,这适用于那些不与组件本身关联但与其他类型的实体(如用户或部门)关联的命名资源。例如,未来的策略可能会允许我们使用诸如“java:user/Anne”和“java:org/finance”这样的名称来命名用户和组织/部门。
5. 相对路径与绝对路径
如果我们想使用JNDI查找的简短版本,可以通过子上下文的帮助来实现。这样,我们就不需要每次都提到命名的完整路径(绝对路径),而是子上下文的相对路径。
我们可以从InitialContext
对象派生出一个子上下文,以便在检索每个资源时不必重复“java:comp/env”:
Context subContext = (Context) context.lookup("java:comp/env");
DataSource ds = (DataSource) subContext.lookup("jdbc/datasource");
如图所示,我们创建了一个子上下文,其中包含了“java:comp/env”内的值,然后使用这个子上下文(相对路径)在其内部查找特定的命名。
6. 总结
在这篇文章中,我们快速了解了什么是JNDI及其用例。然后,我们看到了如何将JNDI名称绑定到上下文并查找相同的名称。
接着,我们讨论了标准前缀“java:comp/env”的拆分,以及在JNDI命名中使用此前缀的原因。我们还注意到,未来的策略可能会扩展根上下文“comp”和子上下文“env”。
一如既往,本文中使用的所有代码示例均可在GitHub上找到。