JNDI 详解:它是什么,为什么用,怎么用?
JNDI 详解它是什么为什么用怎么用一、JNDI 是什么核心定义JNDI的全称是Java Naming and Directory InterfaceJava命名和目录接口。通俗地说它是Java 的一个“电话簿”或“字典”专门用来查找各种资源对象如数据库连接池、消息队列、EJB组件等。在 MyBatis 的配置中dataSource typeJNDI表示“我不在这里配置数据库连接信息而是让 MyBatis 去 JNDI 这个‘电话簿’里根据名字查一个现成的数据源来用。”二、JNDI 的设计思想与工作原理2.1 类比DNS 域名系统DNS你输入www.baidu.comDNS 服务帮你找到对应的 IP 地址220.181.38.251。JNDI你告诉程序“我要找名叫jdbc/mydb的数据源”JNDI 服务帮你找到实际的数据库连接池对象包含 IP、端口、用户名、密码等。2.2 核心机制绑定Bind与查找LookupJNDI 基于一个树形目录结构类似文件系统的文件夹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 配置文件中的写法dataSourcetypeJNDIpropertynamedata_sourcevaluejava:comp/env/jdbc/mydb/!-- 或简写为 --propertynamedata_sourcevaluejdbc/mydb//dataSourcetypeJNDI告诉 MyBatis 不要自己创建数据源而是去 JNDI 容器中查找。data_source属性指定要查找的 JNDI 名称。注意java:comp/env是 J2EE 标准的环境命名上下文ENC推荐写法是把资源放在这个前缀下便于容器统一管理。3.2 对比 MyBatis 的其他数据源类型类型行为适用场景POOLEDMyBatis自己创建连接池配置写在 XML 里独立应用、Spring Boot 默认UNPOOLEDMyBatis自己创建普通连接每次新建临时测试JNDIMyBatis去容器里查找现成的连接池Java EE 应用服务器环境如 Tomcat、WebLogic四、为什么要在应用服务器里配置 JNDI 数据源4.1 优点集中管理数据库连接池由应用服务器统一管理多个应用可以共享同一个连接池。运维友好DBA 或运维人员可以直接在服务器管理控制台修改数据库密码、连接数等参数无需改代码和重新部署。避免密码泄漏密码不出现在项目的配置文件如application.yml或mybatis-config.xml中降低安全风险。容器级优化应用服务器如 Tomcat、WebLogic的连接池实现通常经过多年优化如 Tomcat 自带的 DBCP 或 HikariCP 集成性能和监控能力更强。4.2 缺点环境依赖应用必须部署在支持 JNDI 的容器中Tomcat、Jetty、WebLogic 等不能在纯java -jar的独立运行环境下使用除非借助 Spring Boot 等模拟 JNDI。配置复杂需要额外在服务器端配置如 Tomcat 的context.xml增加了部署步骤。本地开发不便开发人员需要在自己的电脑上配置好 JNDI 资源否则运行报错。五、完整配置示例以 Tomcat 为例5.1 第一步在 Tomcat 中配置 JNDI 数据源在META-INF/context.xml项目内部或$CATALINA_HOME/conf/context.xml全局中添加ContextResourcenamejdbc/mydbauthContainertypejavax.sql.DataSourcedriverClassNamecom.mysql.cj.jdbc.Driverurljdbc:mysql://localhost:3306/xieusernamerootpassword1234maxTotal20maxIdle10maxWaitMillis10000//Context5.2 第二步在 MyBatis 中引用它dataSourcetypeJNDIpropertynamedata_sourcevaluejava:comp/env/jdbc/mydb//dataSource5.3 第三步可选在 web.xml 中声明引用resource-refdescriptionMySQL Datasource/descriptionres-ref-namejdbc/mydb/res-ref-nameres-typejavax.sql.DataSource/res-typeres-authContainer/res-auth/resource-ref六、Java 代码里直接使用 JNDI 的样子不依赖 MyBatisimportjavax.naming.Context;importjavax.naming.InitialContext;importjavax.sql.DataSource;publicclassJNDIExample{publicstaticvoidmain(String[]args)throwsException{// 1. 创建 JNDI 上下文ContextinitContextnewInitialContext();// 2. 查找环境命名上下文ContextenvContext(Context)initContext.lookup(java:comp/env);// 3. 根据名称获取数据源DataSourceds(DataSource)envContext.lookup(jdbc/mydb);// 4. 获取数据库连接Connectionconnds.getConnection();// ... 执行 SQLconn.close();}}七、总结一句话记住 JNDIJNDI 是 Java 应用与外部资源如数据库连接池之间的“中间商”应用通过“名字”去拿资源而不是自己“造”资源。它在服务器容器环境中极为常见是 Java EE 规范的重要组成部分。在 MyBatis 中如果你在非容器环境如 Spring Boot 内嵌 Tomcat 以jar包形式运行通常用POOLED或 HikariCP 直连即可无需配置 JNDI只有在传统 Java EE 应用部署到外部 Tomcat/WebLogic 的 war 包或需要与 DBA 运维解耦时才建议使用JNDI类型。
