Spring 2.0 JNDI集成

地址:http://lincoln.iteye.com/blog/87712 JNDI是JAVAEE 平台技术中最重要的基础支撑技术之一。他为各种Java对象进行命名,并采用目录层次结构管理它们,借助于JNDI API能够操控各种JAVA对象。实际上,JAVAEE5 引入各种Annotation注释(比如,@EJB,@Resource)底层采用JNDI API查找 JavaEE 容器受管资源(比如,EJB3.0组件,JDBC DataSource,JMS ConnectionFactory),并注入到那些应用了Annotation注释的JavaEE组件 (比如,Servlet,JSF后端Bean,EJB3.0组件)中。
Spring2.0针对JNDI API的使用提供了JNDI集成,org.springframework.jndi包就是见证。在Spring 1.x使能应用中,JndiObjectFactoryBean是Spring开发者使用最频繁的工厂Bean,而JndiTemplate模板的使用也非常频繁。自从Spirng 2.0开始,<jndi-lookup/>内容模式被引入到JNDI集成工作中。此后,<jidi-lookup/>便代替了JnidObjectFactoryBean的地位,当然JndiObjectFactoryBean是<jndi-lookup/>底层采用的工厂Bean。
本章从介绍JNDI背景知识及实例入手,进而进入到Spring提供的JNDI集成支持中。随后,Spring2.0引入的<jndi-lookup/>内容模式被介绍到。

背景知识及示例
现有的企业当中,存在各式各样的命名和目录服务。何谓命名和目录服务?命名和目录服务是同过名字,目录形式来管理系统中的对象,无力设备等内容的一种服务。比如,微软活动目录(AD)、OpenDAP服务器。为了通过应用操纵它们,开发者需要借助于响应的客户端API或客户软件
在JNDI出现之前,开发者只能够通过专有方式操作命名和目录服务,这无疑加大了开发者的学习负担。甚至,企业的实现环境都是异构的,哪怕是同一种目录服务器都会因为运行的操作系统的不同而提供多套客户端API。
JNDI,即Java命名目录服务接口(Java Naming and Directory Interface),它能够对命名和目录服务器进行CRUD操作,这同JDBC与RDBMS的关系类似。只要命名和目录服务器厂商提供对应的JNDI实现,开发者便能够一致地通过接口操纵它们,从而避免了与厂商绑定的风险。
类似于DNS,JNDI能够讲对象赋予有意义的名字。在DNS中,通过逻辑能够实现对IP地址的映射。在JNDI中,通过预先绑定的名字能够找到目标服务或者对象。比如,借助于JNDI,我们能通过“java.:/AgileSpringDS”名字获得javax.sql.DataSource对象。这些都是通过Java命名系统获得的。JNDI在Java SE/Java EE中起到了很重要的作用,正如DNS在当今的因特网中的地位一样,而且会越来越重要。比如,Web服务的兴起、SOA架构的兴起,会使得JNDI在应用中扮演关键角色。
通常,Java EE应用服务器(比如,GlassFish,JBoss)都会提供命名或目录服务实现(或称为服务提供者)。BEA WebLogic内部采用了LDAP服务器完成登录用户的认证。同样地,在Java SE环境开发中也可以使用本地JNDI服务提供者(而不是由Java EE服务器提供的)。通过http://java.sun.com/products/jidi/serviceproviders.html,开发者能够浏览到很多JNDI服务提供者。这里,我们以 File System提供者为例。如果开发者熟悉IBM WebSphere MQ,则应该知道他的JNDI实现这是在File System基础之上开发的。打开Eclipse filesystemjndidemo项目,来分析如下代码。


Java代码
Hashtable<String,String> env = new Hashtable<String,string>(2);
//设定上下文工厂
Env.put(Context.INITIAL_CONTEXT_FACTORY,”com.sun.jndi.fscontext.RefFSContextFactroy”);
//设置文件系统路径(注意,开发者需要依据自身的机器修改”file:d://eclipse”)
Env.put(Context.PROVIDER_URL,”file:d://eclipse”);

Context initCtx = null;
Try{
//获得初始化上下文
initCtx = new initialContext(env);

//借助于JNDI,查找文件
Object fc =initCtx.lookup(“eclipse.ini”);
Log.info(fc);
}
Catch(NamingException ne){
//处理命名异常
Log.error(“NamingException”,ne);
}
Finally{
Try{
//关闭上下文
initCtx.close();
}catch(NamingException ne){;}
}
Hashtable<String,String> env = new Hashtable<String,string>(2);
//设定上下文工厂
Env.put(Context.INITIAL_CONTEXT_FACTORY,”com.sun.jndi.fscontext.RefFSContextFactroy”);
//设置文件系统路径(注意,开发者需要依据自身的机器修改”file:d://eclipse”)
Env.put(Context.PROVIDER_URL,”file:d://eclipse”);

Context initCtx = null;
Try{
//获得初始化上下文
initCtx = new initialContext(env);

//借助于JNDI,查找文件
Object fc =initCtx.lookup(“eclipse.ini”);
Log.info(fc);
}
Catch(NamingException ne){
//处理命名异常
Log.error(“NamingException”,ne);
}
Finally{
Try{
//关闭上下文
initCtx.close();
}catch(NamingException ne){;}
}

上述代码先构造env,然后传给InitialContext.此时,”file:d://eclipse”成了JNDI树的根,eclipse目录下的所有文件和目录都成为了树的成员。在查找到eclipse.ini后,需要关闭相应的InitialContext。整个过程需要处理NamingException异常。
用户可以将应用对象存储在命名和目录服务提供者中,并供JNDI应用访问。比如,开发者可以将数据源存储在命名和目录服务器中;通过JNDI能够获得JTA事务管理其(存储在JavaEE 应用服务器提供的命名和目录服务器中)。
实例仅仅展示了JNDI的冰山一角。在实际企业应用中,JNDI的使用更多地发生于Web,EJB,Ear应用场合。比如,在JSF受管组件中访问EJB3.0组件,借助于JNDI访问JMS Topic及ConnectionFactory。在这些场合中,JNDI的使用非常复杂。如果直接通过JNDI API操控目标资源,开发者要处理很多与实际业务无关的开发内容,具体如下:第一,要负责InitialContext的创建、关闭工作;第二,要负责异常处理;第三,要考虑JNDI树上查找目标资源的实际;第四,查找到目标资源后,开发者还要考虑缓存策略(运行时是否需要重新去JNDI树上获取资源,否则他会持有过期资源);第五,要区别对待开发时和生产环境的JNDI处理。考虑到这些对开发者的不利因素,Spring对JNDI提供了全方位的支持,这也是Spring驱动敏捷开发的又一举措。
通过将JNDI查找操作定义在Spring配置文件中,应用能够操作到相关的JNDI对象,开发者再也不用对JNDI进行硬编码。最为重要的一点是,应用对这些JNDI对象的依赖都是通过IoC容器注入的,因此开发者不用关注具体对象是从哪里来。甚至,Spring2.0对于Java EE资源(包括JNDI)的配置做了许多简化工作,比如引入<jee:jndi-lookup/>内容模式。 为了简化 JNDI API 的使用,Spring 2.0框架专门提供了org.springframework.jndi包。其中,JndiTemplateEditor类继承于PropertyEditorSupport类,供实现JndiTemplate对象的属性编辑器使用,即开发者能够通过字符串方式实现对JndiTemplate值得设置(或者在IDE中编辑它)。

通常,开发者可以通过如下4种方式对JNDI资源进行CRUD操作。

1. 单独使用JndiObjectFactroyBean:这种方式最常见(Spring1.x)。这是负责查找JNDI对象的FactroyBean。

2. 同时使用JndiObjectTargetSource和ProxyFactoryBean:这种组合使用较少,因为这同上述单独使用JndiObjectFactoryBean的效果一样,而且在配置上也没有占有优势。

3. 使用JndiTemplate:辅助类,类似于JdbcTemplate,以简化对JNDI的CRUD操作。如果用户需要进行高级自定义工作,则还可以使用JndiCallback回调接口。

4. Spring2.0引入的<jndi-lookup/>内容模式。

单独使用JndiObjectFactoryBean

为了展示JndiObjectFactoryBean的功力,我们来使用JBoss应用服务器提供的JNDI服务。通过JBoss的JMX控制台应用,开发者能够获得全局JNDI名。

我们以消息队列“queue/testQueue”为例,并结合Jbossjndidemo项目进行阐述。

Java代码
<bean id="tq"

class="org.springframework.jndi.JndiObjectFactoryBean">

<!-- 指定JNDI模板 -->

<property name="jndiTemplate" ref="jndiTemplate" />

<!-- 指定JNDI名字 -->

<property name="jndiName" value="queue/testQueue" />

<!-- 是否缓存查找到的Java对象 -->

<property name="cache" value="true"></property>

<!-- 启动时是否去JNDI树查找目标资源(即,由jndiName指定的) -->

<property name="lookupOnStartup" value="true"></property>

<!-- 是否为资源引用 -->

<property name="resourceRef" value="false"></property>

</bean>



<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">

jnp://localhost:1099

</prop>

<prop key="java.naming.factory.url.pkgs">

org.jboss.naming:org.jnp.interfaces

</prop>

</props>

</property>

</bean>

<bean id="tq"

class="org.springframework.jndi.JndiObjectFactoryBean">

<!-- 指定JNDI模板 -->

<property name="jndiTemplate" ref="jndiTemplate" />

<!-- 指定JNDI名字 -->

<property name="jndiName" value="queue/testQueue" />

<!-- 是否缓存查找到的Java对象 -->

<property name="cache" value="true"></property>

<!-- 启动时是否去JNDI树查找目标资源(即,由jndiName指定的) -->

<property name="lookupOnStartup" value="true"></property>

<!-- 是否为资源引用 -->

<property name="resourceRef" value="false"></property>

</bean>



<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">

jnp://localhost:1099

</prop>

<prop key="java.naming.factory.url.pkgs">

org.jboss.naming:org.jnp.interfaces

</prop>

</props>

</property>

</bean>Spring2.0引入的jndi-lookup内容模式

自从Spring2.0开始,便引入了XML Schema来管理BeanFactory、ApplicationContext的配置。无论是语义,还是表达、复用能力,XML Schema都强于DTD。使用XML Schema定义新的数据类型非常方便,当然,要掌握XML Schema还是要费一番功夫的。在RDBMS领域,存在很多O/R Mapping技术,比如Hibernate、JPA、TopLink、Kodo JDO等。在XML领域,也存在很多O/X Mapping技术,比如XML Beans、JAXB、Castor等。借助于它们,应用操作XML文档会很方便。

Spring引入的jee内容模式中含有jndi-lookup数据类型,使用它能够大大简化JNDI的配置。开发者只需要调整Spring XML配置文件,而应用本身不需要做任何修改。相应的内容模式如下,它定义了jndi-lookup的结构和语义。

Jndi-name: 待查找的JNDI名,必填项
Resource-ref:是否是资源引用,可选项。如果是,则需要在web.xml和厂商特定的部署描述符中进行映射。默认取值为false。
Cache:是否缓存查找到的JNDI对象,可选项。默认取值为true
Expected-type:期待的JNDI对象类型,可选项
Lookup-on-startup:是否在启动时去JNDI上查找对象,可选项。默认取值为true
Proxy-interface:代理接口,可选项。配合cache和lookup-on-startup使用
Environment:JNDI环境信息,可选项。如果有多项值对需要给出,则要遵循属性文件的格式。

接下来,我们将重点放在DTD(Spring1.x)到XML Schema(Spring2.0)的移植上。开发者只需要将jee命名空间(spring-jee-2.0.xsd)导入到spring配置文件中,便可以使用到它,具体如下。
Java代码
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jee="http://www.springframework.org/schema/jee"
xsi:schemaLocation=
"http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/jee
http://www.springframework.org/schema/jee/spring-jee-2.0.xsd">

<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jee="http://www.springframework.org/schema/jee"
xsi:schemaLocation=
"http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/jee
http://www.springframework.org/schema/jee/spring-jee-2.0.xsd">

研究这一新特性,示例配置如下,开发者再也看不到JndiObjectFactoryBean、JndiObjectTargetSource的影子,而且配置清晰。
Java代码
<jee:jndi-lookup id="tq" jndi-name="queue/testQueue"
cache="false"
expected-type="javax.jms.Queue"
lookup-on-startup="true"
proxy-interface="javax.jms.Queue"
resource-ref="false">
<jee:environment >
java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
java.naming.provider.url=jnp://localhost:1099
java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces
</jee:environment>
</jee:jndi-lookup>

<jee:jndi-lookup id="tq" jndi-name="queue/testQueue"
cache="false"
expected-type="javax.jms.Queue"
lookup-on-startup="true"
proxy-interface="javax.jms.Queue"
resource-ref="false">
<jee:environment >
java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
java.naming.provider.url=jnp://localhost:1099
java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces
</jee:environment>
</jee:jndi-lookup>由于该示例运行在web容器之外,因此配置看起来稍微有一点复杂。如果应用运行在web容器之中,而且与本地JNDI服务交互,则不用提供environment属性。下面给出的两个版本都是合法的。
Java代码
<jee:jndi-lookup id="tq" jndi-name="queue/testQueue"/>

<jee:jndi-lookup id="tq" jndi-name="queue/testQueue"/>
Java代码
<jee:jndi-lookup id="tq" jndi-name="queue/testQueue"
cache="false"
expected-type="javax.jms.Queue"
lookup-on-startup="true"
proxy-interface="javax.jms.Queue"
resource-ref="false"/>

<jee:jndi-lookup id="tq" jndi-name="queue/testQueue"
cache="false"
expected-type="javax.jms.Queue"
lookup-on-startup="true"
proxy-interface="javax.jms.Queue"
resource-ref="false"/>最后要指出的是Spring2.0兼容Spring1.x的所有配置。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值