一、概念:

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. nyoj311(完全背包变形)

    完全背包 时间限制:3000 ms  |  内存限制:65535 KB 难度:4   描述 直接说题意,完全背包定义有N种物品和一个容量为V的背包,每种物品都有无限件可用.第i种物品的体积是c,价值是 ...

  2. Oracle11g温习-第三章:instance实例管理

    2013年4月27日 星期六 10:30 1.instance 功能:   用于管理和访问database. 2.init parameter files :管理实例相关启动参数.位置:$ORACLE ...

  3. OAF开发中一些LOV相关技巧 (转)

    原文地址:OAF开发中一些LOV相关技巧 在OAF开发中,LOV的使用频率是很高的,它由两部分构成一是页面上的LOV输入框(如OAMESSageLovInputBean),二是弹出的LOV模式窗口(O ...

  4. iOS UI-团购案例(通过xib文件自定义UITableViewCell)

    一.Model #import <Foundation/Foundation.h> @interface Goods : NSObject @property (nonatomic, co ...

  5. 使用kubeadm安装Kubernetes v1.10

    关于K8S: Kubernetes是Google开源的容器集群管理系统.它构建于docker技术之上,为容器化的应用提供资源调度.部署运行.服务发现.扩 容缩容等整一套功能,本质上可看作是基于容器技术 ...

  6. UVALive 2318 水题

    给出c 个竞争者.v 个投票人.每个投票人的投票顺序.问你谁会胜出.在第几轮.完全是个水题.比赛的时候debug接近两个点没过.因此差点放弃了整场比赛.猜测是错在找最大和第二大的序号哪里错的.因为我换 ...

  7. 【译】MVC3 20个秘方-(15)使用CAPTCHA去防止恶意软件自动提交评论(防灌水)

    [译]MVC3 20个秘方-(15)使用CAPTCHA去防止恶意软件自动提交评论(防灌水)   问题 有种不太幸运的情况,有人用自动程序去提交表单,在整个互联网中造成大量的垃圾.为了防止这种情况的方法 ...

  8. 通过Viewpager 来实现微信界面左右滑动。

    package com.lixu.huadong; import java.util.ArrayList; import android.os.Bundle; import android.suppo ...

  9. Java数字签名算法--RSA

    签名具有的特性: 安全性 抗否认性 数字签名:带有密钥(公钥.私钥)的消息摘要算法(使用私钥进行签名,使用公钥进行验证) 数字签名算法:RSA.DSA.ECDSA 数字签名特性: 验证数据完整性 认证 ...

  10. tp5中捕获异常的配置

    首选在配置文件中加入配置如下 // 异常处理handle类 留空使用 \think\exception\Handle    'exception_handle'       => '\\app\ ...