JNDI 详解:它是什么,为什么用,怎么用?

JNDI 详解:它是什么,为什么用,怎么用?

一、JNDI 是什么?(核心定义)

JNDI 的全称是 Java Naming and Directory Interface(Java命名和目录接口)。

通俗地说,它是 Java 的一个"电话簿"或"字典" ,专门用来查找各种资源对象(如数据库连接池、消息队列、EJB组件等)。

在 MyBatis 的配置中,<dataSource type="JNDI"> 表示:"我不在这里配置数据库连接信息,而是让 MyBatis 去 JNDI 这个'电话簿'里根据名字查一个现成的数据源来用。"


二、JNDI 的设计思想与工作原理

2.1 类比:DNS 域名系统

  • DNS :你输入 www.baidu.com,DNS 服务帮你找到对应的 IP 地址(220.181.38.251)。
  • JNDI :你告诉程序"我要找名叫 jdbc/mydb 的数据源",JNDI 服务帮你找到实际的数据库连接池对象(包含 IP、端口、用户名、密码等)。

2.2 核心机制:绑定(Bind)与查找(Lookup)

JNDI 基于一个树形目录结构,类似文件系统的文件夹:

复制代码
java:comp/env
    └── jdbc
        └── mydb   (指向一个 DataSource 对象)
  • 绑定(Bind) :由应用服务器(如 Tomcat、WebLogic)管理员提前把数据源对象注册到 JNDI 目录中,并起一个名字(如 jdbc/mydb)。
  • 查找(Lookup) :应用程序通过 JNDI API,根据名字(java:comp/env/jdbc/mydb)从目录中把数据源对象取出来。

三、JNDI 在 MyBatis 中的具体用法

3.1 MyBatis 配置文件中的写法

xml 复制代码
<dataSource type="JNDI">
    <property name="data_source" value="java:comp/env/jdbc/mydb"/>
    <!-- 或简写为 -->
    <property name="data_source" value="jdbc/mydb"/>
</dataSource>
  • type="JNDI":告诉 MyBatis 不要自己创建数据源,而是去 JNDI 容器中查找。
  • data_source 属性:指定要查找的 JNDI 名称。

注意java:comp/env 是 J2EE 标准的环境命名上下文(ENC),推荐写法是把资源放在这个前缀下,便于容器统一管理。

3.2 对比 MyBatis 的其他数据源类型

类型 行为 适用场景
POOLED MyBatis 自己创建连接池,配置写在 XML 里 独立应用、Spring Boot 默认
UNPOOLED MyBatis 自己创建普通连接,每次新建 临时测试
JNDI MyBatis 去容器里查找现成的连接池 Java EE 应用服务器环境(如 Tomcat、WebLogic)

四、为什么要在应用服务器里配置 JNDI 数据源?

4.1 优点

  1. 集中管理:数据库连接池由应用服务器统一管理,多个应用可以共享同一个连接池。
  2. 运维友好 :DBA 或运维人员可以直接在服务器管理控制台修改数据库密码、连接数等参数,无需改代码和重新部署
  3. 避免密码泄漏 :密码不出现在项目的配置文件(如 application.ymlmybatis-config.xml)中,降低安全风险。
  4. 容器级优化:应用服务器(如 Tomcat、WebLogic)的连接池实现通常经过多年优化(如 Tomcat 自带的 DBCP 或 HikariCP 集成),性能和监控能力更强。

4.2 缺点

  1. 环境依赖 :应用必须部署在支持 JNDI 的容器中(Tomcat、Jetty、WebLogic 等),不能在纯 java -jar 的独立运行环境下使用(除非借助 Spring Boot 等模拟 JNDI)。
  2. 配置复杂 :需要额外在服务器端配置(如 Tomcat 的 context.xml),增加了部署步骤。
  3. 本地开发不便:开发人员需要在自己的电脑上配置好 JNDI 资源,否则运行报错。

五、完整配置示例(以 Tomcat 为例)

5.1 第一步:在 Tomcat 中配置 JNDI 数据源

META-INF/context.xml(项目内部)或 $CATALINA_HOME/conf/context.xml(全局)中添加:

xml 复制代码
<Context>
    <Resource name="jdbc/mydb"
              auth="Container"
              type="javax.sql.DataSource"
              driverClassName="com.mysql.cj.jdbc.Driver"
              url="jdbc:mysql://localhost:3306/xie"
              username="root"
              password="1234"
              maxTotal="20"
              maxIdle="10"
              maxWaitMillis="10000"/>
</Context>

5.2 第二步:在 MyBatis 中引用它

xml 复制代码
<dataSource type="JNDI">
    <property name="data_source" value="java:comp/env/jdbc/mydb"/>
</dataSource>

5.3 第三步(可选):在 web.xml 中声明引用

xml 复制代码
<resource-ref>
    <description>MySQL Datasource</description>
    <res-ref-name>jdbc/mydb</res-ref-name>
    <res-type>javax.sql.DataSource</res-type>
    <res-auth>Container</res-auth>
</resource-ref>

六、Java 代码里直接使用 JNDI 的样子(不依赖 MyBatis)

java 复制代码
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.sql.DataSource;

public class JNDIExample {
    public static void main(String[] args) throws Exception {
        // 1. 创建 JNDI 上下文
        Context initContext = new InitialContext();
        // 2. 查找环境命名上下文
        Context envContext = (Context) initContext.lookup("java:comp/env");
        // 3. 根据名称获取数据源
        DataSource ds = (DataSource) envContext.lookup("jdbc/mydb");
        // 4. 获取数据库连接
        Connection conn = ds.getConnection();
        // ... 执行 SQL
        conn.close();
    }
}

七、总结:一句话记住 JNDI

JNDI 是 Java 应用与外部资源(如数据库连接池)之间的"中间商",应用通过"名字"去拿资源,而不是自己"造"资源。它在服务器容器环境中极为常见,是 Java EE 规范的重要组成部分。

在 MyBatis 中,如果你在非容器环境 (如 Spring Boot 内嵌 Tomcat 以 jar 包形式运行),通常用 POOLED 或 HikariCP 直连即可,无需配置 JNDI;只有在传统 Java EE 应用(部署到外部 Tomcat/WebLogic 的 war 包) 或需要与 DBA 运维解耦时,才建议使用 JNDI 类型。

相关推荐
paopaokaka_luck6 小时前
基于springboot3+vue3的云南本土影视文旅推荐平台(协同过滤算法、Echarts图形化分析)
前端·spring boot·学习·算法·echarts·mybatis
paopaokaka_luck16 小时前
基于springboot3+vue3的企业考勤管理系统(部门树递归、Echarts图形化分析)
开发语言·spring boot·学习·echarts·mybatis·需求分析·代码规范
SQL-First布道者1 天前
⚡ Spring JDBC 完整体系 · 第 8 讲 · 查询四象限完备
java·spring boot·后端·spring·mybatis·spring jdbc
乐观的Terry2 天前
11、发布系统-用户认证与权限体系
java·spring boot·spring·spring cloud·mybatis
步行cgn2 天前
carList.forEach(System.out::println)
java·开发语言·mybatis
豆角焖肉3 天前
MyBatis多表关联查询(一对多/多对一/多对多)
mybatis·一对多·多表设计·多对多·一对一·多对一
学Linux的语莫3 天前
Redis 的两种持久化方式:RDB 和 AOF,一次讲懂
数据库·redis·mybatis
yio_yin4 天前
MyBatis
java·前端·mybatis
無a伟4 天前
Redis事务详解:原理、实战、坑点与实践
mybatis