5.4 Tomcat JNDI


文档摘要

5.4 Tomcat JNDI (Java Naming and Directory Interface) 第五章:Tomcat 高级特性 5.4 Tomcat JNDI (Java Naming and Directory Interface) Java 命名和目录接口 (Java Naming and Directory Interface, JNDI) 是一个Java API,用于访问不同的命名和目录服务。它允许Java应用程序通过名称来查找和访问资源,而无需知道资源的具体位置或实现细节。在Tomcat服务器中,JNDI被广泛用于管理和访问各种资源,例如数据源、邮件会话、环境条目等。

5.4 Tomcat JNDI (Java Naming and Directory Interface)

第五章:Tomcat 高级特性

5.4 Tomcat JNDI (Java Naming and Directory Interface)

Java 命名和目录接口 (Java Naming and Directory Interface, JNDI) 是一个Java API,用于访问不同的命名和目录服务。它允许Java应用程序通过名称来查找和访问资源,而无需知道资源的具体位置或实现细节。在Tomcat服务器中,JNDI被广泛用于管理和访问各种资源,例如数据源、邮件会话、环境条目等。Tomcat的JNDI实现为Web应用程序提供了一个标准化的方式来获取配置信息和外部资源,从而提高了应用程序的灵活性、可移植性和可维护性。

5.4.1 什么是 JNDI?

JNDI 是一种用于访问命名和目录服务的Java API。它允许应用程序通过一个逻辑名称来查找和访问资源,而无需硬编码资源的物理位置或配置细节。可以将 JNDI 视为一个“黄页”或“目录服务”,应用程序可以通过名称查询到所需的资源,并获取资源的引用。

JNDI 的核心概念包括:

  • 命名服务 (Naming Service): 提供将名称映射到对象的能力。例如,可以将一个数据源绑定到一个特定的名称,应用程序可以通过该名称来查找数据源。

  • 目录服务 (Directory Service): 命名服务的扩展,允许对象具有属性,并且可以根据属性来搜索对象。虽然 Tomcat JNDI 主要侧重于命名服务,但也具备一定的目录服务能力。

  • 上下文 (Context): JNDI 操作的起点。上下文定义了一个命名空间,在这个命名空间中可以查找和绑定对象。JNDI 上下文是分层结构的,类似于文件系统目录结构。

  • 绑定 (Binding): 将名称与对象关联的过程。在 JNDI 中,资源通过绑定操作注册到上下文中。

  • 查找 (Lookup): 通过名称检索绑定到该名称的对象。应用程序使用查找操作来获取所需的资源。

JNDI 的优势:

  • 解耦性 (Decoupling): 应用程序代码与资源的具体实现和配置解耦。应用程序只需要知道资源的 JNDI 名称,而不需要关心资源的物理位置、类型或配置细节。这提高了应用程序的灵活性和可维护性。

  • 配置集中化 (Centralized Configuration): 资源配置集中在 JNDI 服务中管理,而不是分散在应用程序代码或配置文件中。这使得配置管理更加方便和一致。

  • 可移植性 (Portability): JNDI 是一个标准的 Java API,使用 JNDI 的应用程序可以更容易地在不同的 JNDI 提供者和环境中移植。

  • 资源共享和管理 (Resource Sharing and Management): JNDI 允许在多个应用程序之间共享资源,例如数据库连接池。JNDI 服务可以管理资源的生命周期,例如连接池的创建、销毁和维护。

5.4.2 Tomcat 中的 JNDI

Tomcat 内置了一个 JNDI 实现,为部署在 Tomcat 中的 Web 应用程序提供 JNDI 服务。Tomcat JNDI 服务允许 Web 应用程序访问各种资源,例如数据源 (DataSource)、邮件会话 (Mail Session)、环境条目 (Environment Entry) 等。

Tomcat JNDI 的主要特点:

  • 基于命名上下文 (Naming Context): Tomcat JNDI 基于命名上下文的层次结构。每个 Web 应用程序都有自己的 JNDI 命名上下文,并且可以访问服务器级别的全局 JNDI 命名上下文。

  • 资源配置 (Resource Configuration): Tomcat 允许在不同的配置文件中配置 JNDI 资源,例如 server.xml (全局资源) 和 context.xml (Web 应用程序级别资源)。

  • 标准 JNDI API 支持 (Standard JNDI API Support): Tomcat JNDI 实现了标准的 JNDI API,Web 应用程序可以使用标准的 JNDI 代码来查找和访问资源。

  • 与 Tomcat 组件集成 (Integration with Tomcat Components): Tomcat JNDI 与 Tomcat 的其他组件紧密集成,例如连接器 (Connector)、Realm 和生命周期管理。

Tomcat JNDI 命名上下文层次结构:

Tomcat JNDI 命名上下文是分层结构的,主要包括以下几个层次:

  • java: 上下文 (Java Context): JNDI 命名空间的根上下文。所有 JNDI 操作都从 java: 上下文开始。

  • java:comp 上下文 (Java Component Environment Context): 表示当前 Web 应用程序组件的上下文。Web 应用程序通常在这个上下文中查找资源。

  • java:comp/env 上下文 (Environment Naming Context): 用于存储 Web 应用程序的环境条目,例如简单的配置参数。

  • java:comp/resource 上下文 (Resource Manager Context): 用于存储 Web 应用程序的资源引用,例如数据源、邮件会话等。

  • java:comp/mail 上下文 (Mail Session Context): 用于存储邮件会话资源。

  • java:comp/ejb 上下文 (EJB Context): 用于存储企业级 JavaBeans (EJB) 组件的引用 (在完整的 Java EE 环境中)。

除了 Web 应用程序级别的上下文,Tomcat 还提供服务器级别的全局 JNDI 命名上下文,通常通过 <GlobalNamingResources> 元素在 server.xml 中配置。全局资源可以被所有 Web 应用程序共享。

5.4.3 Tomcat JNDI 结构图

以下 Mermaid 图表展示了 Tomcat JNDI 的命名上下文层次结构:

图表解释:

  • java 是 JNDI 命名空间的根上下文。

  • java:comp 代表当前 Web 应用程序组件的上下文,是访问 Web 应用程序级别资源的主要入口点。

  • java:comp/env 用于存储环境条目,例如配置参数。

  • java:comp/resource 用于存储资源引用,例如数据源。

  • java:comp/mail 用于存储邮件会话资源。

  • java:comp/ejb 用于存储 EJB 组件引用 (在 Java EE 环境中)。

  • Global Naming Resources (server.xml) 表示在 server.xml 中配置的全局 JNDI 资源,可以被所有 Web 应用程序访问。

  • Shared Resources 表示全局共享资源。

  • Environment Entries, Resource References, Mail Sessions, EJB References 分别表示在各自上下文中绑定的资源类型。

5.4.4 配置 Tomcat JNDI 资源

Tomcat 允许在多个配置文件中配置 JNDI 资源,主要包括 server.xmlcontext.xml

1. 全局 JNDI 资源配置 (server.xml):

全局 JNDI 资源在 $CATALINA_BASE/conf/server.xml 文件中的 <GlobalNamingResources> 元素下配置。全局资源对所有部署在 Tomcat 中的 Web 应用程序可见。

<Server ...> ... <GlobalNamingResources> <Resource name="jdbc/globalDB" auth="Container" type="javax.sql.DataSource" factory="org.apache.tomcat.jdbc.pool.DataSourceFactory" driverClassName="com.mysql.cj.jdbc.Driver" url="jdbc:mysql://localhost:3306/global_db" username="global_user" password="global_password" maxActive="20" maxIdle="10"/> <Environment name="appGlobalName" value="Global Value" type="java.lang.String"/> </GlobalNamingResources> ... </Server>

配置元素说明:

  • <GlobalNamingResources>: 根元素,用于包含全局 JNDI 资源的配置。

  • <Resource>: 用于配置资源引用,例如数据源、邮件会话等。

    • name: 资源的 JNDI 名称,通常以 jdbc/, mail/ 等前缀开头。在应用程序中通过此名称查找资源。

    • auth: 认证类型,通常设置为 Container,表示由容器管理认证。

    • type: 资源的 Java 类型,例如 javax.sql.DataSource, javax.mail.Session

    • factory: 资源工厂类,用于创建资源实例。对于 Tomcat 内置的数据源和邮件会话,通常使用 Tomcat 提供的工厂类。

    • 其他属性: 资源特定的配置属性,例如数据源的 driverClassName, url, username, password 等。

  • <Environment>: 用于配置环境条目 (简单的配置参数)。

    • name: 环境条目的 JNDI 名称。

    • value: 环境条目的值。

    • type: 环境条目的 Java 类型,例如 java.lang.String, java.lang.Integer

2. Web 应用程序级别 JNDI 资源配置 (context.xml 或 Web 应用的 context.xml):

Web 应用程序级别的 JNDI 资源可以在以下两个位置配置:

  • $CATALINA_BASE/conf/context.xml: 默认的 Web 应用程序上下文配置文件。在这个文件中配置的资源将应用于所有部署的 Web 应用程序,除非在 Web 应用程序自身的 context.xml 中覆盖。

  • $CATALINA_BASE/webapps/your-webapp/META-INF/context.xml: Web 应用程序自身的上下文配置文件。在这个文件中配置的资源只应用于当前的 Web 应用程序。如果 Web 应用程序自身的 context.xml 文件存在,它将覆盖 $CATALINA_BASE/conf/context.xml 中的配置。

Web 应用程序级别 JNDI 资源的配置方式与全局资源类似,也是使用 <Resource><Environment> 元素,但它们放置在 <Context> 元素内部。

<Context ...> ... <Resource name="jdbc/appDB" auth="Container" type="javax.sql.DataSource" factory="org.apache.tomcat.jdbc.pool.DataSourceFactory" driverClassName="com.mysql.cj.jdbc.Driver" url="jdbc:mysql://localhost:3306/app_db" username="app_user" password="app_password" maxActive="20" maxIdle="10"/> <Environment name="appName" value="WebApp Value" type="java.lang.String"/> ... </Context>

资源类型示例:

  • DataSource (数据源): 用于数据库连接池。type="javax.sql.DataSource", factory="org.apache.tomcat.jdbc.pool.DataSourceFactory" (Tomcat JDBC 连接池), 或其他连接池工厂类。

  • Mail Session (邮件会话): 用于发送电子邮件。type="javax.mail.Session", factory="org.apache.naming.factory.MailSessionFactory".

  • URL (统一资源定位符): 用于访问 URL 资源。type="java.net.URL", factory="org.apache.naming.factory.URLFactory".

  • UserTransaction (用户事务): 用于 JTA 事务管理。type="javax.transaction.UserTransaction", factory="org.apache.naming.factory.UserTransactionFactory".

  • Environment Entry (环境条目): 用于简单的配置参数。type="java.lang.String", type="java.lang.Integer" 等,无需 factory 属性。

注意:

  • 资源的 JNDI 名称在配置时需要仔细选择,并在应用程序代码中使用相同的名称进行查找。

  • 资源配置属性需要根据资源类型和工厂类的要求进行设置。请参考 Tomcat 文档和相关资源工厂类的文档获取详细信息。

  • 修改 server.xmlcontext.xml 文件后,通常需要重启 Tomcat 服务器或 Web 应用程序才能使配置生效。

5.4.5 在 Web 应用程序中使用 JNDI 资源

Web 应用程序可以使用标准的 JNDI API 来查找和访问在 Tomcat 中配置的 JNDI 资源。通常的步骤如下:

  1. 获取 InitialContext: 创建 javax.naming.InitialContext 实例,作为 JNDI 操作的入口点。

  2. 查找资源: 使用 InitialContextlookup() 方法,根据资源的 JNDI 名称查找资源。通常从 java:comp/envjava:comp/resource 上下文开始查找。

  3. 使用资源: 将查找到的资源对象转换为相应的 Java 类型,并进行使用。

  4. 关闭资源 (如果需要): 对于某些资源,例如数据库连接,需要在使用完毕后显式关闭以释放资源。

代码示例 1: 访问数据源 (DataSource)

假设在 context.xml 中配置了一个名为 jdbc/appDB 的数据源:

<Resource name="jdbc/appDB" auth="Container" type="javax.sql.DataSource" factory="org.apache.tomcat.jdbc.pool.DataSourceFactory" driverClassName="com.mysql.cj.jdbc.Driver" url="jdbc:mysql://localhost:3306/app_db" username="app_user" password="app_password" maxActive="20" maxIdle="10"/>

在 Servlet 或 JSP 中访问数据源的代码示例:

import javax.naming.InitialContext; import javax.naming.Context; import javax.sql.DataSource; import java.sql.Connection; import java.sql.SQLException; public class JndiDataSourceExample { public void accessDatabase() { Connection connection = null; try { // 1. 获取 InitialContext InitialContext initCtx = new InitialContext(); // 2. 查找 java:comp/env 上下文 Context envCtx = (Context) initCtx.lookup("java:comp/env"); // 3. 查找数据源 DataSource ds = (DataSource) envCtx.lookup("jdbc/appDB"); // 4. 获取数据库连接 connection = ds.getConnection(); // 5. 使用数据库连接进行操作 (例如执行 SQL 查询) // ... System.out.println("Successfully connected to database using JNDI DataSource."); } catch (NamingException e) { System.err.println("JNDI NamingException: " + e.getMessage()); e.printStackTrace(); } catch (SQLException e) { System.err.println("SQLException: " + e.getMessage()); e.printStackTrace(); } finally { // 6. 关闭数据库连接 if (connection != null) { try { connection.close(); } catch (SQLException e) { System.err.println("Error closing connection: " + e.getMessage()); } } } } }

代码解释:

  • InitialContext initCtx = new InitialContext(); 创建 InitialContext 实例。

  • Context envCtx = (Context) initCtx.lookup("java:comp/env"); 查找 java:comp/env 上下文。

  • DataSource ds = (DataSource) envCtx.lookup("jdbc/appDB");java:comp/env 上下文中查找名为 jdbc/appDB 的数据源,并将其转换为 DataSource 类型。

  • connection = ds.getConnection(); 从数据源获取数据库连接。

  • connection.close();finally 块中关闭数据库连接,确保资源释放。

  • 异常处理:代码中包含了 NamingExceptionSQLException 的处理,以捕获 JNDI 查找和数据库操作可能出现的异常。

代码示例 2: 访问环境条目 (Environment Entry)

假设在 context.xml 中配置了一个名为 appName 的环境条目:

<Environment name="appName" value="WebApp Value" type="java.lang.String"/>

在 Servlet 或 JSP 中访问环境条目的代码示例:

import javax.naming.InitialContext; import javax.naming.Context; import javax.naming.NamingException; public class JndiEnvEntryExample { public void accessEnvironmentEntry() { try { // 1. 获取 InitialContext InitialContext initCtx = new InitialContext(); // 2. 查找 java:comp/env 上下文 Context envCtx = (Context) initCtx.lookup("java:comp/env"); // 3. 查找环境条目 String appName = (String) envCtx.lookup("appName"); // 4. 使用环境条目 System.out.println("Application Name from JNDI: " + appName); } catch (NamingException e) { System.err.println("JNDI NamingException: " + e.getMessage()); e.printStackTrace(); } } }

代码解释:

  • 代码结构与访问数据源的示例类似,只是查找的 JNDI 名称和类型不同。

  • String appName = (String) envCtx.lookup("appName");java:comp/env 上下文中查找名为 appName 的环境条目,并将其转换为 String 类型。

最佳实践:

  • 资源查找路径: 通常情况下,Web 应用程序应该从 java:comp/envjava:comp/resource 上下文开始查找资源。避免直接使用全局 JNDI 命名空间,以提高应用程序的隔离性和可移植性。

  • 异常处理: 务必处理 NamingException 异常,以应对 JNDI 查找失败的情况。

  • 资源释放: 对于需要显式释放的资源 (例如数据库连接、文件句柄等),在使用完毕后及时关闭或释放资源,防止资源泄漏。

  • 配置管理: 使用 JNDI 进行资源配置可以提高应用程序的灵活性和可维护性。建议将应用程序的配置信息和外部资源通过 JNDI 进行管理,而不是硬编码在代码中或分散在多个配置文件中。

5.4.6 JNDI 的优势总结

Tomcat JNDI 为 Web 应用程序提供了强大的资源管理和配置机制,带来了诸多优势:

  • 配置外部化: 将应用程序的配置信息 (例如数据库连接信息、邮件服务器配置等) 从应用程序代码中分离出来,集中在 Tomcat 的 JNDI 配置中管理。这使得配置修改更加方便,无需重新编译和部署应用程序。

  • 资源池化和共享: JNDI 可以用于配置和管理资源池,例如数据库连接池。多个 Web 应用程序可以共享同一个资源池,提高了资源利用率和性能。

  • 环境隔离: 每个 Web 应用程序都有自己的 JNDI 命名上下文,实现了应用程序之间的环境隔离。应用程序只能访问自身上下文和全局上下文中的资源,避免了命名冲突和资源互相干扰。

  • 可移植性和标准化: JNDI 是一个标准的 Java API,使用 JNDI 的应用程序可以更容易地在不同的 Java EE 容器和 JNDI 提供者之间移植。Tomcat JNDI 实现了标准的 JNDI API,保证了应用程序的可移植性。

  • 安全性: Tomcat JNDI 可以与 Tomcat 的安全机制集成,实现对 JNDI 资源的访问控制。可以配置资源的认证和授权策略,确保资源的安全性。

总而言之,Tomcat JNDI 是 Tomcat 服务器中一项至关重要的技术,它为 Web 应用程序提供了标准化的资源访问和配置管理方式,极大地提升了应用程序的灵活性、可维护性、可移植性和安全性。理解和掌握 Tomcat JNDI 对于开发和部署高质量的 Web 应用程序至关重要。


作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U