JNDI的来龙去脉

JNDI的来龙去脉


参考资料: 什么是JNDI?

前言

JNDI这个名词第一次见到是在阅读SpringBoot源码的时候,在看BeanFactory接口的一个实现类SimpleJndiBeanFactory的时候,有这么一段解释:

This factory resolves given bean names as JNDI names within the J2EE application’s "java:comp/env/" namespace.

解释:此工厂将给定的bean名称解析为J2EE应用程序的“java:comp / env /”命名空间中的JNDI名称。然后看到返回的Be按包的方法中,根据名称判断是否是单例,不是的话调用lookup方法,否则调用doGetSingletion方法。
在这里插入图片描述
在doGetSingletion方法中,再一次看到这个JNDI,其中singletonObjects为一个哈希表,key为bean的name,value为bean instance(实例)。这个方法的最后,也是调用lookup然后返回给jndi对象。
在这里插入图片描述
在阅读lookup方法时,又发下它是SpringBoot下的类JndiLocatorSupport里的方法,再一次好奇JNDI为何方神圣?


Naming

JNDI全称为Java Naming and Directory Interface(JAVA命名和目录接口),从定义上看它包含两部分内容,Naming(命名)、 Directory(目录)。在一个由多个模块组成的应用中,这些模块还有着互相调用的关系时,JNDI可以为我们提供统一的命名和目录访问的API。它类似一种文件组织结构,如图所示:


在这里插入图片描述
在上图中,每个椭圆代表都是一个对象,JNDI通过Naming(命名)将每个对象绑定到一个上下文context(或者叫容器环境,其实,它的本质上也是个对象来着)中,Naming为每个context起了唯一的标志符,即a、b、c、d、e。在每个context中,Naming还为每个椭圆对象也起了名字(饲养员、管理员、肉食动物等等)。

我们知道,在文件系统中,同一层次的目录或文件不能起一样的名字,但在不同层次结构的目录和文件却可以,同样,在JNDI也是如此,譬如你在a中命名了饲养员这个对象,就不能再次用这个名字在a中命名其他椭圆对象,但你在b中可以。

Naming正是通过这种组织结构,将各个context组织成一种树形结构,其中b、c是a的子context,我们可以简单理解为一种调用关系,饲养员饲养着肉食动物和草食动物。d和e又分别是b、c的子context。

通过图中的关系描述,我们可以知道想要找到一个椭圆对象,我们需要找到一个context,这里不同于我们的文件系统,在JNDI中没有所谓的根,即固定从某个根节点开始寻找,而是直接诶通过context名称定义到具体的context,然后通过该context查询即lookup相应的对象。(这也解释了SpringBoot源码中的lookup方法的作用了)

那么问题又来了,JNDI是怎样为每个context命名的呢?原来在JNDI API中提供了一个InitialContext类,在该类中提供了三种初始化context的构造方法。在初始化的过程中,它又会调用NamingManager类中的getInitialContext方法:

    public static Context getInitialContext(Hashtable<?,?> env)
        throws NamingException {
        InitialContextFactory factory;

        InitialContextFactoryBuilder builder = getInitialContextFactoryBuilder();
        if (builder == null) {
            // No factory installed, use property
            // Get initial context factory class name

            String className = env != null ?
                (String)env.get(Context.INITIAL_CONTEXT_FACTORY) : null;
            if (className == null) {
              /****省略没什么关系的代码节省篇幅***/
            }
            
            try {
                factory = (InitialContextFactory)
                    helper.loadClass(className).newInstance();
            } catch(Exception e) {
            	    /****省略没什么关系的代码节省篇幅***/
            }
        } else {
            factory = builder.createInitialContextFactory(env);
        }
        return factory.getInitialContext(env);
    }

根据源码我们可以看出 InitialContextFactoryBuilder的实例为null时表示第一次初始化,此时,我们为context创建的className是根据JNDI的环境属性java.naming.factory.initial进行的。当然了,我们也可以根据Context的操作方法的url参数的Schema来选择context的名称,如下方法所示:

/**
     * Retrieves a context for resolving the string name <code>name</code>.
     * If <code>name</code> name is a URL string, then attempt
     * to find a URL context for it. If none is found, or if
     * <code>name</code> is not a URL string, then return
     * <code>getDefaultInitCtx()</code>.
     *<p>
     * See getURLOrDefaultInitCtx(Name) for description
     * of how a subclass should use this method.
     * @param name The non-null name for which to get the context.
     * @return A URL context for <code>name</code> or the cached
     *         initial context. The result cannot be null.
     * @exception NoInitialContextException If cannot find an initial context.
     * @exception NamingException In a naming exception is encountered.
     * @see javax.naming.spi.NamingManager#getURLContext
     */
    protected Context getURLOrDefaultInitCtx(String name)
        throws NamingException {
        if (NamingManager.hasInitialContextFactoryBuilder()) {
            return getDefaultInitCtx();
        }
        String scheme = getURLScheme(name);
        if (scheme != null) {
            Context ctx = NamingManager.getURLContext(scheme, myProps);
            if (ctx != null) {
                return ctx;
            }
        }
        return getDefaultInitCtx();
    }

Directory

与文件系统中目录的概念有所不同,JNDI中的Directory是指将一个对象的所有属性信息保存到一个容器环境中。原理和Nami ng非常相似。

主要的区别在于目录容器环境中保存的是对象的属性信息,而不是对象本身,所以,目录提供的是对属性的各种操作。

注意一点,JNDI的Directory与Naming一般结合使用,在JNDI API中,提供的代表目录容器环境的类为DirContext,而DirCont ext又是Context的子类,显然它除了能完成目录相关的操作外,也能完成所有的Naming操作。

DirContext是对Context的扩展,它在Context的基础上增加了对目录属性的操作功能,可以在其中绑定对象的属性信息和查找对象的属性信息。

如图,这里可能会有人疑问,我们在讲Naming时不是说在一个context中不同对象不能取相同的名称吗?是的,但这里是DirContext,给对象和对象的属性取相同的名称,就好比在一个目录中创建名字相同的文本文件和新的目录文件,这是允许的。而且,我们的属性还可以设置成不同的值,也可以在DirContext中只绑定对象的属性信息,而不绑定任何对象自身。

关于DirContext的创建我们同样可以采用API中的InitialDirContext类进行初始化。

在这里插入图片描述


学习资料

ORACLE JNDI 教程
JNDI+Tomcat 配置数据库数据源
Apache Tomcat官网对JNDI使用的讲解
Spring利用JNDI配置数据源

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

legendaryhaha

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值