JNDI笔记

jndi
JNDI服务是web容器提供的服务。web应用可以通过JNDI服务从容器中得到各种组件(包括但不限于数据源),实现各组件的解耦

例子

以下举一个例子。 在tomcat的conf/server.xml中配置:

1
2
3
4
5
6
7
8
<Context path="/jndi"> 

<Resource name="bean/MyBeanFactory" auth="Container"
type="com.huawei.jndi.bean.MyBean"
factory="org.apache.naming.factory.BeanFactory"
bar="23"/>

</Context>

上面就在tomcat中声明了一个组件,接下来在代码中可以获取这个组件:

1
2
3
4
5
6
7
8
9
10
11
try
{
Context initContext = new InitialContext();
Context envCtx = (Context) initContext.lookup("java:comp/env");
MyBean bean = (MyBean) envCtx.lookup("bean/MyBeanFactory");
System.out.println(bean.getBar());
}
catch (Exception e)
{
e.printStackTrace();
}

在tomcat中配置jndi组件,然后在代码中获取已配好的组件。各web容器的JNDI实现类不同,比如在JBOSS中,JNDI提供类是org.jnp.interfaces.NamingContextFactory

这样看来,JNDI的作用和spring的依赖注入倒是差不多。但是通过JNDI,可以实现跨应用,甚至跨域获取组件。在服务器A上配置的组件,在另一台服务器B上,可以通过JNDI获取到

spring也提供了对jndi的封装,使用起来更加方便,以下是一个例子。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<!-- JNDI模板 -->
<bean id="jndiTemplate" class="org.springframework.jndi.JndiTemplate">
<property name="environment">
<props>
<prop key="java.naming.factory.initial">org.jnp.interfaces.NamingContextFactory</prop>
<prop key="java.naming.provider.url">10.137.96.212:18199</prop>
<prop key="java.naming.factory.url.pkgs">org.jnp.interfaces:org.jboss.naming</prop>
</props>
</property>
</bean>

<!-- 创建连接工厂 -->
<bean id="jmsConnectionFactory" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiTemplate" ref="jndiTemplate" />
<property name="jndiName" value="TopicConnectionFactory" />
</bean>

先声明JndiTemplate,配置好目标地址、JNDI服务提供类。然后通过JndiObjectFactoryBean,就可以很方便地获取JNDI组件,并进行类型转换

JNDI规范的归属

JNDI本身是java se最早的一批规范,但是似乎不像JDBC等,有专门的JSR编号,在jsr.org上,找不到专门描述JNDI的规范

http://jcp.org/en/jsr/all

另外在JAVA EE规范中第5章,也专门提到了JNDI

http://java.chinaitlab.com/Special/java_ee/Chapter5.html

关于JNDI的资料,还有以下2个官方链接:

http://docs.oracle.com/cd/E17802_01/products/products/jndi/javadoc/
http://docs.oracle.com/javase/jndi/tutorial/getStarted/overview/index.html

可以这么理解,JNDI规范虽然本身不是JAVA EE规范的一部分,但是JAVA EE规范要求,所有的JAVA EE容器,都需要实现JNDI规范

但是,就算脱离了JAVA EE环境,只要有专门的JNDI实现,应用程序一样可以使用JNDI的服务,比如SUN公司的遗产,fscontext

http://docstore.mik.ua/orelly/java-ent/jenut/ch06_02.htm#ch06-pgfid-982058

JNDI规范的价值

在EJB2是企业应用开发主流技术的时候,JNDI很有用

http://blog.csdn.net/zhaosg198312/article/details/3979435

但是现在,java ee without EJB的风潮已经兴起很久了,特别是以spring为代表的IOC容器大行其道,通过IOC容器已经可以实现组件注入的功能,JNDI规范的应用已经比以前少得多了

很多近年才接触JAVA EE的开发者,甚至都没有听过JNDI的概念;大量的简单应用,也没有涉及到JNDI

以下几个介绍JNDI的链接,似乎也不错

http://blog.csdn.net/zhaosg198312/article/details/3979435
http://stackoverflow.com/questions/1350816/what-is-the-purpose-of-jndi

我个人有2个理解:

第一,JAVA EE对一个端到端开发过程中,涉及到的角色进行了划分,一种是写应用的人,叫Developer;另一种是部署应用的人,叫Deployer。JAVA EE规范认为,作为developer,无需关心数据源来自哪里,这是deployer的职责。所以developer只需要写:

1
2
Context context = new InitialContext();
dataSource = (DataSource) context.lookup("Database");

但是,实际上现在的开发过程中,这2者似乎都是程序员的事,并没有这么明确的分工,所以JNDI的这层意义被削弱了。但是,将资源获取,和资源配置分离开的思想,依然是正确的,也是主流的做法

第二,JNDI起到了很好的抽象层的作用。还是上面的那段代码,就算不考虑角色分工,代码本身也是非常简洁和优雅的。现在我们一般通过spring管理数据源,将DataSource定义为一个bean,然后注入到DAO对象,或者DAO代理对象中,这种做法其实起源于JNDI,历史远远早于IOC容器之前

其他

对于JNDI,Java Naming and Directory Interface中,“命名”和“目录”的理解

命名:JNDI的本质,就是为了容易地获取应用外部的种种资源。相当于有一个外部服务,托管了应用将会用到的所有资源。而应用要获取资源,就需要传递一个唯一的标识。就像使用Map数据结构,需要传递一个key,才能获取value。对JNDI也一样,资源的唯一标识,就是资源的命名,这是JNDI里Naming的含义

目录:设想JNDI服务管理了大量的资源,当然就希望有一个方式对资源进行分类,就像硬盘里的文件多了,也会建立子目录来管理是一个道理。Context接口也提供了createSubcontext()、destroySubcontext()等方法,来创建目录。这是JNDI里Directory的含义 上面也是我看了一堆资料,然后猜测的,不一定对,但是基本能自圆其说

另外,JNDI可以跨应用地获取资源,以实现分布式,这个也是比Spring这样的普通IOC容器强的地方,当然是否用得到,则是另一回事。“跨应用获取资源”的范围可大可小,部署在同一个容器中的不同应用,获取global resource也是跨应用;获取不同服务器上的资源,也是跨应用,但是到目前为止,我还没有见过这种用法