`
Lewiss
  • 浏览: 19599 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

JNDI Glean

    博客分类:
  • J2SE
阅读更多
JNDI 基本说明

JNDI ( Java Naming and Directory Interface ),是 Java 提供的一组与各种命名目录服务系统交互的接口。它是一套标准的接口,独立于各种命名目录服务系统,与具体类型的命名目录服务无关。Java 应用程序通过 JNDI 接口与命名目录服务交互,交互细节由服务提供者实现,Java 应用程序无需关心。
(个人觉得这是JAVA 的特点:向Java应用程序开发人员开放简单的接口,复杂的实现细节由服务提供者完成)

命令目录服务包括两个服务:命名服务(Naming Service)和目录(Directory Service)服务。命名服务就是用一个人类容易理解的名称与对象相关联,并且允许通过该名称找到与之对应的对象。我们天天都会用到的命名服务:DNS。个人觉得,目录服务是命名服务的超集,目录服务除了有命名服务的功能外,它的对象还可以有属性。常用的目录服务类型有 LDAP 等。


JNDI 上下文
JNDI 一个主要功能就是用名字(name)来标识对象(object)。name 在 JNDI 中唯一,它跟某个特定的 object 关联,这种关联关系称之为 binding。binding的集合在 JNDI 中称为上下文 context。在JNDI 特定的上下文中,通过 name就可以找到相应的对象。

Naming Service Context:命名服务上下文视图:


在上图中,a 为根 context,在它下面绑定有 dog、pig和 sheep 三个对象,同时又有 b 和 c 两个子 context,而 b 中有 d 这个子 context,d 又有 e 这个子 context,每个 context 中都绑定了相应的对象。
如果当前 context 为 a,那么 acontext.lookup(“dog”)就得到 dog 对象,而 acontext.lookup(“b/d/e/cat”) 就可得到猫这个对象。
如果当地 context 为 d,那么 dcontext.lookup(“wolf”) 就可得到 wolf 对象,dcontext.lookup(“e/rabit”) 就可得到 rabit 对象。

Directory Service Context:目录服务上下文视图:


可以看到,目录服务上下文 context 与命名服务上下文结构关系相似,只是目录服务上下文的中的对象多了属性。如在 a 上下文中,dog 对象有 name、color 和category属性,在 b 上下文中,cat 对象也有相同的属性。


也可以用map来帮助理解JNDI 的context。一个map 就相当于一个 JNDI context, map 的一个 entry 就是 JNDI context 的一个 binding,而 entry 的 key 相当于 binding 的 name,entry 的value 相当于 binding 的 object。当然这种理解不是非常准确的,因为 JNDI 的 context 还有目录层次的结构,但是可以用子 map 的方式来理解整个 JNDI 的 context,如下图所示:



在上图中,如果当前 context 为 rootMap,那么 context.lookup(“/mysqlDS”) 将得到 mysql 的连接池对象 DataSource。因为name “/mysqlDS”是跟 DataSource 绑定的;如果用context.lookup(“/jmxServerUrl”) ,将得到 JMX 服务器的连接 URL 对象 JMX_URL;同理,context.lookup(“/name_n+1/sub_name_1”) 将得到对象 sub_object1。

如果当前context为 subMap1,那么用context.lookup(“mysqlDS”) 就可以得到DataSource,而不用在 “mysqlDS” 中加上 “/”。同时,context.getSubContext(“name_n+1”) 可以得到 subMap2 的 context subcontext,并且 subcontext.lookup(“sub_name_1”) 就可得到对象 sub_object1。
在上图中,上下文结构及对象信息是维护在命名目录服务器中的, JNDI 只是操作接口。


JNDI 架构
JNDI 的实现原理其实跟 JDBC 的实现原理是一样的。在 JDBC 中,Java 定义了一套标准的、独立于数据库系统的 API。JDBC 开发者只管使用 JDBC 的 API,并加载(安装)相应数据库的驱动即可,完全不用理会该数据库驱动是怎么跟它的数据库交互的。如 JDBC 的设计架构如下图所示:


在上图中,Java 应用程序 Application1 和 Application2 只与 JDBC API 交互,而不用管数据库的 JDBC驱动是怎么跟数据库交互的(JAVA 又是这样:向Java应用程序开发人员开放 JDBC接口,复杂的实现细节由相应的 JDBC 驱动完成)。如果系统用的是 MySQL 数据库,那么就得加载 MySQL JDBC 驱动,如果是 Oracle 数据库,那么就得提供 Oracle 的 JDBC 驱动,驱动管理者(DriverManager)会自动帮Java 应用程序 Application1 和 Application2 选择对应的 JDBC 驱动与数据库进行交互。

JNDI 的实现架构跟 JDBC 的实现架构相似,如下图所示:


JNDI API 对应于 JDBC API
Naming Manager 对应于 Driver Manager
LDAP、DNS、RMI对应于 MySQL、Oracle 的 JDBC 驱动

Java Application 只与 JNDI API 交互,而不管具体的命名目录服务系统是 LDAP、DNS 还是 RMI。如果系统与 LDAP 命名目录服务系统交互,那么必须加载(安装)LDAP 驱动,如果与 DNS 命名服务系统交互,那么必须加载(安装)DNS 驱动。


JNDI SPI
在 JNDI 中,有一个概念叫做 SPI(Server Provider Interface),服务提供者接口,是 JNDI 定义的标准接口。服务提供者根据命名命令服务系统的不同,需对接口做相应的实现,并使用该实现与命名命令服务系统交互。如上图中,LDAP、DNS、RMI 就是服务提供者,它们都实现了标准的 LDAP、DNS、RMI 访问协议,使用这些协议,可以与 LDAP 系统、DNS 系统和RMI 服务器交互。
如,MySQL 和 Oracle 的 JDBC 驱动就相当于 JNDI 中的服务提供者。

Java 从 1.3 版本开始就包含了 LDAP、CORBA和 RMI 的驱动实现(服务提供者),所以访问者三种类型的命名目录服务的话不用再另外加载(安装)驱动,但如果不是,就需加载相应的驱动,就像Java 访问 MySQL 数据库需加载 MySQL 的 JDBC 驱动一样。例如通过 JNDI 访问本地文件系统的话,需加载相应的访问文件系统的驱动,sun 有一个这样的驱动实现:com.sun.jndi.fscontext.RefFSContextFactory。


Tomcat 的 JNDI SPI 实现
在上面的 JNDI 架构中,命名目录服务系统有可能部署在远程主机中,JNDI 使用相应的驱动与命名目录服务系统进行远程通信。如,LDAP 的驱动将与远程 LDAP 服务器进行通信,命名和目录信息存储于远程命名目录服务系统中。
但是在Tomcat 中稍有不同。Tomcat也有相应的 JNDI SPI 实现,但是该 SPI 实现(LDAP驱动)并不访问远程命名目录服务,它只是在内存中实现了一个虚拟命名目录服务,用于存储命名和对象信息并维护相应的绑定关系。Tomcat 中的数据源就对象就是存储于 Tomcat 实现的本地命名目录服务中的。
关于 Tomcat 的 JNDI SPI 实现,可以通过这两个类进行跟踪:
org.apache.naming.java.javaURLContextFactory
org.apache.naming.NamingContext

下面用两张图说明 LDAP 驱动与 Tomcat 驱动(SPI 实现)访问过程的不同:
LDAP 访问过程:



TOMCAT 访问过程图:



由上图可以看到,Java App 通过 JNDI 访问 LDAP 服务,LDAP 驱动要跟 LDAP服务进行远程通信,即LDAP 服务是在 Java App 的 JVM 之外的(Java App 与 LDAP 驱动在同一 JVM 内)。
但是 Tomcat 的 JNDI SPI 驱动实现不同。由上图可以看出,Servlet 通过 JNDI 接口访问 Tomcat 的虚拟命名目录服务时,Tomcat 的 JNDI SPI 实现直接访问其内存虚拟命名目录服务,而不需要跨越 JVM,即在 Tomcat 中,Servlet、Tomcat JNDI SPI 驱动以及 Tomcat 的内存虚拟命名目录都在同一 JVM 。

Tomcat 的 JNDI SPI 实现规定,命名空间必须以 java: 开头,如,我们通常在 Tomcat 中这样查找数据源(如 Servlet):
Context ctx=new InitialContext();
Object o = ctx.lookup("java:comp/env/mysqlDataSource");
DataSource ds=(DataSource)o;

这里,我们在初始化 context 的时候,不用指定加载的实现驱动,是因为 Tomcat 在启动的时候已经指定了其 SPI 实现到系统属性中:
见:org.apache.catalina.startup.Embedded
System.setProperty(javax.naming.Context.INITIAL_CONTEXT_FACTORY,
                     "org.apache.naming.java.javaURLContextFactory");

当初始化 context 不指定加载驱动时,JVM 自动从指定的系统属性(javax.naming.Context.INITIAL_CONTEXT_FACTORY)中查找该驱动。
所以,我们对 mysqlDataSource 的查找请求转到 Tomcat 的 JNDI SPI 实现中,JNDI SPI 实现
根据名称从其内存的虚拟命名目录服务查找 mysql 的数据源对象,并返回给应用程序。


JNDI 简单使用
JNDI 的使用相对简单,JNDI 开发人员只需初始化一个 context 实例(可以把该实例看成是命名目录服务系统的一个镜像),并通过该 context 实例绑定对象、查找对象以及解除对象。
在初始化context 实例时,需根据目标命名目录服务系统提供相应的驱动类供 JNDI 加载使用:
Hashtable env = new Hashtable(11); env.put(Context.INITIAL_CONTEXT_FACTORY,"com.sun.jndi.fscontext.RefFSContextFactory");
Context ctx = new InitialContext(env);

在上例中,要访问的目标命名目录服务系统是本地文件系统,所以需提供 JNDI 的文件系统驱动。如果是访问 LDAP 系统,那么 context 的初始化应该提供 LDAP 驱动类:
Hashtable env = new Hashtable(11);
env.put(Context.INITIAL_CONTEXT_FACTORY,   "com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.PROVIDER_URL,"ldap://localhost:389/o=JNDITutorial");
DirContext ctx = new InitialDirContext(env);

常用的 JNDI 操作有
查找对象:lookup(String name)
绑定对象:bind(String name, Object obj)
解除对象:unbind(String name)
还有重命名、重绑定、创建子 context 等。
关于 JNDI 的更多细节,请参阅相应书籍。
  • 大小: 14 KB
  • 大小: 17.9 KB
  • 大小: 98.1 KB
  • 大小: 4.6 KB
  • 大小: 25 KB
  • 大小: 17.4 KB
  • 大小: 7.9 KB
分享到:
评论
2 楼 snailxr 2011-04-13  
hao!!!!!!!!!!!!!1
1 楼 小哥1900 2011-03-17  
好文章,学习鸟,楼主 ,有前途~~~

相关推荐

    jndi-tool JNDI服务利用工具

    JNDI服务利用工具 RMI/LDAP,支持部分场景回显、内存shell,高版本JDK场景下利用等,fastjson rce命令执行,log4j rce命令执行 漏洞检测辅助工具

    Tomcat中JNDI原理

    简单我tomcat5.0中的JNDI应用

    hibernate 3.1+tomcat 5.5.x(配置jndi)

    hibernate 3.1+tomcat 5.5.x(配置jndi)hibernate 3.1+tomcat 5.5.x(配置jndi)hibernate 3.1+tomcat 5.5.x(配置jndi)hibernate 3.1+tomcat 5.5.x(配置jndi)hibernate 3.1+tomcat 5.5.x(配置jndi)hibernate 3.1+...

    关于JNDI测试项目

    JNDI测试项目JNDI测试项目JNDI测试项目JNDI测试项目JNDI测试项目JNDI测试项目JNDI测试项目JNDI测试项目JNDI测试项目JNDI测试项目JNDI测试项目JNDI测试项目JNDI测试项目JNDI测试项目JNDI测试项目JNDI测试项目JNDI测试...

    jndi-1_2_1.zip_jndi_jndi-1.2.1.jar

    在JAVA编程中对JNDI的支持.是一个开放的源码.

    jboss配置MySql的JNDI

    jboss配置MySql的JNDI

    jndi-JNDI-Injection-Exploit

    java asm jndi_JNDI-Injection-Exploit,用于log4j2漏洞验证 可执行程序为jar包,在命令行中运行以下命令: $ java -jar JNDI-Injection-Exploit-1.0-SNAPSHOT-all.jar [-C] [command] [-A] [address] 其中: -C ...

    Windows_7_下搭建LDAP服务器并使用JNDI

    Windows_7_下搭建LDAP服务器并使用JNDI Windows_7_下搭建LDAP服务器并使用JNDI Windows_7_下搭建LDAP服务器并使用JNDI

    tomcat jndi数据源解密factory

    自定义jndi数据源factory类,用于解密jndi中的加密数据,解密方式为DES,具体可根据实际需求修改。

    JNDI基础教程课件

    jndi入门学习资料,介绍jndi基本原理,安装和使用,基本配置

    jndi配置

    jndi配置,jndi配置jndi配置jndi配置jndi配置jndi配置jndi配置jndi配置

    jndi所依赖的jar包

    jndi所依赖的jar包,fscontext.jar和providerutil.jar,jndi.jar 将jndi.jar复制到%JAVA_HOME%\jre\lib\ext目录下就可得到持久的扩展

    hibernate中jndi的配置使用

    配置了tomcat之后发现jndi好简单啊,可是碰到了hibernate该怎么做呢,本例详细解析

    jndi jndi jndi

    jndi.jndi.jndi.jndi.jndi.jndi.jndi.jndi.jndi.

    JNDI Java操作示例

    JNDI java操作示例,JNDI java操作示例

    tomcat8 JNDI数据源加密

    TOMCAT8 JNDI对用户名和密码加密

    JNDI配置原理详解.doc

    JNDI配置原理详解 JNDI配置原理详解.doc

    JNDI配置方法详解

    JNDI(Java Naming and Directory Interface)是SUN公司提供的一种标准的Java命名系统接口,JNDI提供统一的客户端API,通过不同的访问提供者接口JNDI SPI的实现,由管理者将JNDI API映射为特定的命名服务和目录系统,...

    JNDI配置详细介绍

    tomcat的JNDI配置详细介绍 介绍详细,思路清晰

Global site tag (gtag.js) - Google Analytics