暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

JNDI的API分析(Tomcat之JNDI系统源码分析之一)

中间件技术讨论圈 2016-12-18
695

JNDI规范是一个非常老的规范了,我想任何一个在java领域工作的人都应该接触过JNDI,本文算是给Tomcat的JNDI系列的源码分析来一个开头,让大家热热身,后续的一周时间,我们会深入分析Tomcat的是如何实现JNDI的。


1.包分析

严格意义上来讲,其实JNDI规范并没有对应的JCP社区的JSR规范,因为很早时间随着JDK就已经发布了,导致没有对应的PDF可以下载,但是JAVA EE 6的规范中有对应的JNDI规范如何在JAVA EE规范中进行实施,也就是如何绑定和查找JAVA EE对象,这块我们下一节再详细阐述。

在JDK中的几个包如下:


其中,我们关心的Context,IntialContext等接口都在javax.naming包中,这个包是JNDI的API包,

Context:上下文接口

InitialContext:初始化上下文,可以理解为JNDI的入口,非常的重要

而javax.naming.spi是JNDI的实现层,可以有下图进行理解:


处于核心的地位是NamingManager,也就是名称管理器,我们大多数的情况作为客户端,一般是不需要和NamingManager打交道的;

对于JNDI,其最终实现可以理解为一个存储设施,例如树就是一个比较经典的做法,你可以在内存中为其构造一个树,如Tomcat,OpenEJB中,大多数应用服务器都提供了JNDI的查找,我们可以看一下国产应用服务器TongWeb的JNDI树:


不单单能清晰的展现出树的形态,并且当你点击左侧的节点,TongWeb应用服务器会非常人性化的告诉你,你当前该节点挂载的是什么类型的,你需要怎么进行查找,实在是非常人性化之举,而像一些开源的,如Tomcat,Openejb这些,你只能通过JNDI接口去获取这些信息,实在是不直观,而这也就是商业服务器和开源服务器的差距的地方了。

当然,从上述的包的分析来看,除了内存中的类似于树的结构,你也可以将这些信息存入目录服务中,因为目录服务如LDAP,天生就是树状的,和JNDI的需求是类似的,因此javax.naming.directory,javax.naming.ldap这两个包就是JNDI如何支持目录服务的,尤其是javax.naming.ldap这个包,基本上实现了LDAP V3的协议,你完全可以通过LDAP的API去实现JNDI。


对于SPI来讲,JDK中的Naming默认提供了目录服务,从上图我们也可以看到,其实可以有n多种选择,这种选择主要就由javax.spi包来实现了:


其中上图中的三个类是最为关键。

InitialiContextFactory:主要是初始化上下文InitialContext的生成工厂,它能生成InitialContext,所以至关重要,因为我们在客户端需要在环境变量率先指定这个工厂,如在Jboss中,我们在代码中需要将工厂设置到env中:


在Tomcat中,InitialiContextFactory就是javaURLContextFactory,你需要设置这个:


同时,在Tomcat比较有意思的是,这个javaURLContextFactory同时也继承了ObjectFactory:


那什么是ObjectFactory呢?

就是当JNDI创建一些对象绑定的时候,不同类型的节点会有不同的instance实例的创建方式,从下面的类的继承关系可以看:


数据源,ejb,rmi绑定,不同的JNDI对应的实体节点其对象创建也不同,因此需要实现不同的Objectfactory;

javaURLContextFactory恰恰是创建默认的Context节点类型的,所以从代码上你可以看到其返回的还是SelectorContext,依然是Context接口类型;


javax.naming.directory主要是一些目录操作:


怎么理解这个目录包呢,就是

目录(Directory)可看作是对命名(Naming)的一个扩充,一个目录对象不仅像命名一样,而且还提供的对属性(Attributes)的操作.由API文档可知,javax.naming.directory.DirContext类扩展自Context接口,同样,javax.naming.directory.InitialDirContext也扩展自 javax.naming.InitialContext,由此也可看出目录操作完全支持命名操作。

下面给出一个DNS Service Provider例子以演示有关目录的一些操作: 

public class TestDNSJndi { 

    public static void main(String[] args) throws Exception { 

        Properties env= newProperties(); 

        env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.dns.DnsContextFactory"); 

        //此IP一定要为要访问的DNS服务器的IP,可通过网络设置查看 

        env.put(Context.PROVIDER_URL, "dns://10.17.45.239"); 

        DirContext ctx= newInitialDirContext(env); 

        System.out.println("a:" + ctx); 

        DirContext ctx1 =(DirContext) ctx.lookup("www.sina.com"); 

        System.out.println("b:" + ctx1); 

        printAttributes("c:", ctx1.getAttributes("")); 

        //从ctx.getAttributes("www.sina.com")与ctx1.getAttributes("")结果一样 

        printAttributes("d:", ctx.getAttributes("www.sina.com")); 

        Attributes attrs1 = ctx.getAttributes("www.sina.com", newString[] { "a" }); 

        Attributes attrs2 = ctx.getAttributes("www.163.com", newString[] { "a" }); 

        Attributes attrs3 = ctx1.getAttributes("", new String[] { "a" }); 

        Attributes attrs4 = ctx.getAttributes("www.baidu.com", newString[] { "a" }); 

        printAttributes("e:", attrs1); 

        printAttributes("f:", attrs2); 

        printAttributes("g:", attrs3); 

        printAttributes("attrs4:", attrs4); 

        System.out.println("nameParse:"+ctx1.getNameInNamespace()); 

        //list,此方法会导致程序lock 

        //listEnumation("list:",ctx.list("")); 

        //----------------------search 

        Attributes matchAttrs =new BasicAttributes(true); 

        matchAttrs.put(new BasicAttribute("a", "61.172.201.13")); 

        NamingEnumeration answer = ctx1.search("www.sina.com", matchAttrs); 

        printNamingEnumeration("search :", answer); 

    } 


下一篇我们会继续分析这些JNDI的环境变量,请期待!

文章转载自中间件技术讨论圈,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论