
本文共 4284 字,大约阅读时间需要 14 分钟。
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方法。


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

我们知道,在文件系统中,同一层次的目录或文件不能起一样的名字,但在不同层次结构的目录和文件却可以,同样,在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 namename
. * Ifname
name is a URL string, then attempt * to find a URL context for it. If none is found, or if *name
is not a URL string, then return *getDefaultInitCtx()
. ** 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
name
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类进行初始化。
学习资料
发表评论
最新留言
关于作者
