一、概念:

1、JNDI(JavaNaming and Directory Interface,Java命名和目录接口)是SUN公司提供的一种标准的Java命名系统接口,JNDI提供统一的客户端API,客户端通过统一接口的API,来使用不同服务,这些不同的服务分别实现了JNDI服务供应接口(SPI),使得Java应用程序可以和这些命名服务和目录服务之间进行交互。目录服务是命名服务的一种自然扩展。两者之间的关键差别是目录服务中对象不但可以有名称还可以有属性(例如,用户有email地址),而命名服务中对象没有属性。

JNDI中的命名(Naming),就是将Java对象以某个名称的形式绑定(binding)到一个容器环境(Context)中,以后调用容器环境(Context)的查找(lookup)方法又可以查找出某个名称所绑定的Java对象。

JNDI可访问的现有的目录及服务有:DNS、XNam 、Novell目录服务、LDAP(Lightweight Directory Access Protocol轻型目录访问协议)、 CORBA对象服务、文件系统、Windows XP/2000/NT/Me/9x的注册表、RMI、DSML v1&v2、NIS。

JNDI中的目录(Directory)是指将一个对象的所有属性信息保存到一个容器环境中。JNDI的目录(Directory)原理与JNDI的命名(Naming)原理非常相似,主要的区别在于目录容器环境中保存的是对象的属性信息,而不是对象本身,所以,目录提供的是对属性的各种操作。

2、JNDI树结构示意图:

3、JNDI环境属性:

4、  JNDI的基本使用方法:
一种是在代码里指定上面的参数:
  Hashtable
env = new Hashtable();

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

  env.put(Context.PROVIDER_URL, "dns:" +
dnsServer);

  DirContext ctx = new InitialDirContext(env);

另一种是在jndi.properties文件中指定,文件内容可以如下:

  java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory

  java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces

  java.naming.provider.url=localhost

jndi.properties文件为所有的InitialContexts设置默认的属性,jndi.properties文件的搜索次序:·CLASSPATH,·$JAVA_HOME/lib;

二、Demo:

从JDK 1.4开始的版本又集成了用于DNS查询的JNDI服务程序,所以,如果我们使用JDK 1.4及更高的JDK版本来开发DNS信息查询程序时,不需要下载和安装JNDI API和用于DNS查询的JNDI服务程序。

下面是一个使用JNDI
API获取DNS信息的程序,运行这个程序时,需要指定一个或两个参数,第一个参数是必须的,为要查询的域名,第二个参数是可选的,为查询时所使用的DNS服务器的IP地址,如果没有指定第二个参数,DNS的JNDI服务程序将使用底层操作系统上设置的DNS服务器。

import java.util.Hashtable;

import javax.naming.Context;

import javax.naming.NamingEnumeration;

import javax.naming.NamingException;

import javax.naming.directory.Attribute;

import javax.naming.directory.Attributes;

import javax.naming.directory.DirContext;

import javax.naming.directory.InitialDirContext;

public class DNSQuery

{

    public static void main(String[] args) throws NamingException

    {

        /*第一个参数指定要查询的域或主机名,第二个参数指定查询的DNS服务器,

        为了程序的简单易读性,省略了严格的参数错误检查*/

        String domain = args[0];

        String dnsServer = args.length<2 ? "" : ("//" + args[1]);

        //通过环境属性来指定Context的工厂类

        Hashtable env = new Hashtable();

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

        env.put(Context.PROVIDER_URL, "dns:" + dnsServer);

        DirContext ctx = new InitialDirContext(env);

        //分别获取包含所有属性和只包含Mx属性的Attributes对象

        Attributes attrsAll = ctx.getAttributes(domain);   

        Attributes attrsMx = ctx.getAttributes(domain, new String[]{"MX"});

        /*上面的整段程序代码也可以用下面这段程序代码来替代,下面这段程序

        代码通过查询URL中的Schema信息来自动选择Context的工厂类*/

        /*

        DirContext ctx = new InitialDirContext();

        Attributes attrsAll = ctx.getAttributes("dns:" + dnsServer + "/" + domain);

        Attributes attrsMx = ctx.getAttributes(

            "dns:" + dnsServer + "/" + domain, new String[]{"MX"});        

        */

        System.out.println("打印出域" + domain +

                                "的Attributes对象中的信息:");

        System.out.println(attrsAll);

        System.out.println("--------------------------");

        System.out.println("打印只检索域" + domain +

                                "的MX记录的Attributes对象:");   

        System.out.println(attrsMx);

        System.out.println("--------------------------");

        System.out.println("逐一打印出Attributes对象中的各个属性:");         

        NamingEnumeration attributes = attrsAll.getAll();

        while(attributes.hasMore())

        {  

            System.out.println(attributes.next());

        }

        System.out.println("--------------------------");

        //直接调用get方法从attrsMx集合检索MX属性

        System.out.println("直接检索Attributes对象中的MX属性:");    

        Attribute attrMx = attrsAll.get("MX");

        System.out.println(attrMx);

        System.out.println("--------------------------");          

        //获取Mx属性中的第一个值:

        System.out.println("获取Mx属性中的第一个值:");

        String recordMx = (String)attrMx.get();

        System.out.println(recordMx);

        //从Mx属性的第一个值中提取邮件服务器地址

        System.out.println("从MX属性值中提取的邮件服务器地址:");

        String smtpServer = recordMx.substring(

                            recordMx.indexOf(" ") + 1);

        System.out.println(smtpServer);

} 

三、源码解析:

1、Java命名系统的接口是Context,JNDI API中提供了一个InitialContext类来创建用作JNDI命名操作的入口Context对象。

2、Java目录系统的接口是DirContext,DirContext是Context的子类,显然它除了能完成目录相关的操作外,也能完成所有的命名(Naming)操作。DirContext是对Context的扩展,它在Context的基础上增加了对目录属性的操作功能,可以在其中绑定对象的属性信息和查找对象的属性信息。JNDI API中提供了一个InitialDirContext类来创建用作JNDI命名与目录属性操作的入口DirContext对象。

3、InitialContext类中的myprops成员变量是一个Hashtable类型,存储属性名称和属性值的键值对,用于初始化Context时的相关参数,defaultInitCtx成员变量存储真正实现服务的Context对象,象Context的API接口(比如bind, lookup, rebind等)都是调用这个defaultInitCtx来实现的;

4、InitialContext对象的启动过程:

构造函数如果传入了一个hashtable对象,则克隆该hashtable对象(包括克隆原hashtable对象里面的数据),如果没传,则创建一个新的hashtable对象:

可以看到构造函数都会调用init函数,在init函数中又会调用ResourceManager.getInitialEnvironment函数,下面是getInitialEnvironment函数的实现:

可以看到getInitialEnvironment函数中会判断构造函数传过来的hashtable参数如果没传,则创建一个初始只有11个元素的hashtable对象;

在这个函数中,会读取VersionHelper.PROPS的所有属性,其定义如下:

在读取这些属性值时,首先优先从构造函数传递过来的hashtable中去读取,如果读取不到,再到java.naming.applet中去读取对应的属性值,如果还是读取不到,则从系统参数中去读取;如果这三个里面只要有任何一个独到属性值了,则将属性名和属性值的键值对存储到env变量中并返回这个env对象;

再来看看init函数:

可以看到init函数首先调用上面的getInitialEnvironment返回一个存储有服务对象实例化时需要的属性的hashtable对象,如果这个hashtable里面有java.naming.factory.initial属性时,则调用getDefaultInitCtx来构造服务对象并存储在defaultInitCtx变量里面;

可以看到getDefaultInitCtx调用NamingManager.getInitialContext来实例化服务对象,而在getInitialContext中根据java.naming.factory.initial属性值指定的类名实例化服务对象,然后调用factory.getInitialContext来初始化其他属性并返回实例化的Context对象;

5、InitialContext对象相关接口的实现:

可以看到InitialContext对象相关接口的实现都是调用了getURLOrDefaultInitCtx函数返回的服务示例的接口;

可以看到这个函数会根据传递的name参数查找到对应的子容器对象Context返回,如果查找不到则返回默认的Context对象defaultInitCtx;

6、InitialDirContext对象的启动过程:

可以看到InitialDirContext的构造函数什么也没做,只是调用父类InitialContext的构造函数;

7、InitialDirContext对象相关接口的实现:

bind/lookup/rebind等接口以及新增加的 getAttributes/modifyAttributes/getSchema等接口的实现是依赖于getURLOrDefaultInitDirCtx函数返回的DirContext对象,而getURLOrDefaultInitDirCtx函数又是调用父类的getURLOrDefaultInitCtx函数实现的;

Java JNDI 学习的更多相关文章

  1. 如何学习Java?学习Java顺序?

    Java相对于Asp.Net或Asp.Net MVC来讲,入门是比较困难和烦琐的!它不像.Net哪样有安装开发工具就可以跑程序了,不需要配置复杂的运行环境. 推荐的学习Java的学习顺序如下: 一.J ...

  2. Java的学习之路

    记事本 EditPlus eclipse Java的学习软件,已经系统性学习Java有一段时间了,接下来我想讲一下我在Java学习用到的软件. 1.第一个软件:记事本 记事本是Java学习中最基础的编 ...

  3. Java多线程学习笔记

    进程:正在执行中的程序,其实是应用程序在内存中运行的那片空间.(只负责空间分配) 线程:进程中的一个执行单元,负责进程汇总的程序的运行,一个进程当中至少要有一个线程. 多线程:一个进程中时可以有多个线 ...

  4. Java Web 学习路线

    实际上,如果时间安排合理的话,大概需要六个月左右,有些基础好,自学能力强的朋友,甚至在四个月左右就开始找工作了.大三的时候,我萌生了放弃本专业的念头,断断续续学 Java Web 累计一年半左右,总算 ...

  5. Java基础学习-- 继承 的简单总结

    代码参考:Java基础学习小记--多态 为什么要引入继承? 还是做一个媒体库,里面可以放CD,可以放DVD.如果把CD和DVD做成两个没有联系的类的话,那么在管理这个媒体库的时候,要单独做一个添加CD ...

  6. 20145213《Java程序设计学习笔记》第六周学习总结

    20145213<Java程序设计学习笔记>第六周学习总结 说在前面的话 上篇博客中娄老师指出我因为数据结构基础薄弱,才导致对第九章内容浅尝遏止地认知.在这里我还要自我批评一下,其实我事后 ...

  7. [原创]java WEB学习笔记95:Hibernate 目录

    本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用 内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系. 本人互联网技术爱 ...

  8. Java多线程学习(转载)

    Java多线程学习(转载) 时间:2015-03-14 13:53:14      阅读:137413      评论:4      收藏:3      [点我收藏+] 转载 :http://blog ...

  9. java基础学习总结——java环境变量配置

    前言 学习java的第一步就要搭建java的学习环境,首先是要安装JDK,JDK安装好之后,还需要在电脑上配置"JAVA_HOME”."path”."classpath& ...

随机推荐

  1. python-day27--configparser模块

    1.来看一个好多软件的常见文档格式如下: [DEFAULT] ServerAliveInterval = 45 Compression = yes CompressionLevel = 9 Forwa ...

  2. Mac无法写入移动硬盘,Mac移动硬盘不能写

    对于使用 Mac 的朋友,有时候难免需会使用移动硬盘.一般的移动硬盘的容量都比较大,再加上国内大多数人使用的都是 Windows 系统,为了通用与方便,所以硬盘的分区一般都是 NTFS 格式的.对于 ...

  3. 记一次使用utl_http方法调用接口,报字符或值错误

    背景:ebs系统和其他系统通过utl_http包调用接口,使用log方法记录日志. 某次调用接口,执行到记录日志行报字符或值错误. 查找原因,发现是p_str的长度超过的32767的限制. 解决办法: ...

  4. Oracle HRMS APIs

    Oracle HRMS APIs..... Here I will be sharing all the Oracle HRMS APIs related articles. 参考地址: Oracle ...

  5. 使用Windbg解析dump文件

    WinDbg OllyDbg SoftICE (已经停止更新) 虽说WinDbg在无源码调试方面确实比较困难,但在调试内核方面却真的有独到之处. https://www.pediy.com/kssd/ ...

  6. 快速切题 poj1068

    Parencodings Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 19716   Accepted: 11910 De ...

  7. 如何获取选定部分的HTML

    其实这个程序很简单,首先是如何获取选定部分的HTML,还记得这段吗: HTMLDoc := WebBrowser1.Document as IHTMLDocument2;  SelectRange : ...

  8. 读书笔记 C# Lookup<TKey,TElement>和ToLookup方法的浅析

    Lookup<TKey,TElement>类型对象和分组是一样的,就好比使用Linq的group关键字后所查询出来的结果,使用foreach的时候,都可以用IGrouping<TKe ...

  9. MyEclipse WebSphere开发教程:WebSphere 7安装指南(三)

    [周年庆]MyEclipse个人授权 折扣低至冰点!立即开抢>> [MyEclipse最新版下载] 五.应用WebSphere 7.0.0.x和Java SDK更新 1. 要应用这些PAK ...

  10. dubbo集群应用

    前面写了一篇dubbo的基础应用篇,单机版 http://www.cnblogs.com/yun965861480/p/6257670.html, 这次将集群的相关配置记录下来. 1.zookeepe ...