转:http://www.ibm.com/developerworks/cn/java/j-jndi/index.html
虽然 J2EE 平台提高了普通企业开发人员的生活水平,但是这种提高是以不得不学习许多规范和技术为代价的,这些规范和技术则是 J2EE 为了成为无所不包的分布式计算平台而整合进来的。Dolly Developer 是众多开发人员中的一员,她已经发现了一个特性,该特性有助于缓解随企业级应用程序部署而带来的负担,这个特性就是 JNDI,即 Java 命名与目录接口(Java Naming and Directory Interface)。让我们来看看 Dolly 在没有 JNDI 的时候是怎么做的,以及她是如何正确地应用 JNDI 来改善其状况的。
Dolly Developer 正在编写使用 JDBC 数据源的 Web 应用程序。她知道自己正在使用 MySQL,所以她将一个对 MySQL JDBC 驱动程序类的引用进行了编码,并通过使用适当的 JDBC URL 连接到其 Web 应用程序中的数据库。她认识到数据库连接池的重要性,所以她包含了一个连接池包,并把它配置成最多使用 64 个连接;她知道数据库服务器已经被设置成最多允许 128 台客户机进行连接。
在开发阶段,每件事都进行得很顺利。但是,在部署的时候,开始失控。Dolly 的网络管理员告诉她,她不能从她的桌面机访问生产服务器或登台服务器(staging server),所以她不得不为每个部署阶段开发不同的代码版本。因为这种情况,她需要一个新的 JDBC URL,所以还要为测试、阶段和生产进行独立的部署。(一听到要在每个环境中建立单独部署,熟悉配置管理的人会战战兢兢的,但是既然这是种非常普遍的情况,所以他们也只好硬着头皮上了。)
就在 Dolly 认为通过不同的 URL 建立彼此独立的部署已经解决了自己的配置问题时,她发现她的数据库管理员不想在生产环境中运行 MySQL 实例。他说,MySQL 用作开发还可以,但是对于任务关键型数据而言,业务标准是 DB2®。现在她的构建不仅在数据库 URL 方面有所不同,而且还需要不同的驱动程序。
事情越变越糟。她的应用程序非常有用,并且变得非常关键,以致于它从应用服务器那里得到了故障恢复的能力,并被复制到 4 个服务器集群。但是数据库管理员提出了抗议,因为她的应用程序的每个实例都要使用 64 个连接,而数据库服务器总共只有 200 个可用连接 —— 全部都被 Dolly 的应用程序占用了。更麻烦的是,DBA 已经确定 Dolly 的应用程序只需要 32 个连接,而且每天只有一个小时在使用。随着她的应用程序规模扩大,应用程序遇到了数据库级的争用问题,而她的惟一选择就是改变集群的连接数量,而且还要做好准备,在集群数量增长或者应用程序复制到另一个集群时再重复一次这样的操作。看来她已经决定了如何配置应用程序,应用程序的配置最好是留给系统管理员和数据库管理员来做。
如果 Dolly 在开发应用程序时了解 J2EE 所扮演的角色,那么她就可能避免遭遇这种困境。J2EE 规范把职责委托给多个开发角色:组件提供者(Component Provider)、应用程序组装者(Application Assembler)、部署人员(Deployer)和系统管理员(System Administrator)。(在许多公司中,组件提供者和组件组装者的角色是融合在一起的,部署人员和系统管理员的角色是融合在一起的。)在真正了解 J2EE 中的 JNDI 角色之前,掌握 J2EE 角色的作用非常重要。
假设有一个企业应用程序,该应用程序包含一个 Web 应用程序,还有一个负责业务逻辑和持久性的 EJB 组件。开发这个应用程序的组件供应商可能有许多,但是在许多情况下,可以由一个人来承担全部职责。组件可以包含数据传输对象(一个 JAR 文件)、EJB 接口(另一个 JAR 文件)、EJB 实现本身(另一个 JAR 文件),以及用户界面组件 —— servlet、JSP、HTML 页面和其他静态 Web 内容。用户界面组件被进一步打包成 Web 应用程序,其中包含 servlet 类、JSP 文件、静态内容,以及其他必需组件的 JAR(包括 EJB 接口)。
这听起来好像用到的组件太多了,几乎超出了人的想像范围,尤其是在考虑构建一个典型的 Web 应用程序需要使用多少个 JAR 文件的时候。但是,重要的是认识到在这里必须小心地管理依赖性。接口和传输对象是 Web 应用程序和 EJB 实现可以依赖的对象,但是依赖性的方向应该是相同的;还要避免产生循环依赖。J2EE 组件(例如 WAR 文件和 EJB JAR 文件)必须在它们的部署单元之外声明它们在资源上的依赖性。
应用程序组装者负责把 Web 应用程序中的依赖内容包含进来,并把它们整体打包成单个企业应用程序。工具在这里帮助很大。IDE 可以协助创建反映模块和 JAR 依赖性的项目结构,还允许您随意指定包含或排除的模块。
部署人员负责确保部署环境中存在组件所需的资源,并将组件绑定到平台的可用资源上。例如,Web 应用程序中的外部 EJB 引用(部署描述符中的 ejb-ref
)就是在此时被绑定到实际部署的 EJB 组件 —— 而且是立即绑定。
任何不平凡(nontrivial)的 J2EE 应用程序都需要访问描述它期望使用环境的信息。这意味着开发和测试组件时,为了临时测试代码,开发人员要承担一些部署方面的职责。重要的是要理解:这么做的时候,您就走出了开发人员的领域。否则,可以试着依靠 JDBC 驱动程序,或 URL、JMS 队列名称,或者其他具有无意识的、偶尔可能是灾难性暗示的机器资源。
Dolly 的问题的解决方案是从她的应用程序中清除所有对数据存储的直接引用。没有对 JDBC 驱动程序的引用,没有服务器名称,没有用户名称或口令 —— 甚至没有数据库池或连接管理。Dolly 需要编写代码来忽略将要访问的特定外部资源,只需要知道其他人会提供使用这些外部资源所需的链接即可。这允许部署人员(任何处在这个角色的人)把数据库连接分配给 Dolly 的应用程序。Dolly 没有必要参与其中。(从数据库安全性到遵守 Sarbanes-Oxley 法案,她都没有参与进来,她这样做也有充足的业务理由。)
许多开发人员知道:代码和外部资源之间的紧密耦合是潜在的问题,但是在实践中却经常忘记角色的划分。在小型开发工作中(指的是团队规模或部署规模),即使忽视角色划分也能获得成功。(毕竟,如果应用程序只是个人的应用程序,而且您不准备依靠它,那么把应用程序锁定在特定的 PostgreSQL 实例上也挺好的。)
J2EE 规范要求所有 J2EE 容器都要提供 JNDI 规范的实现。JNDI 在 J2EE 中的角色就是“交换机” —— J2EE 组件在运行时间接地查找其他组件、资源或服务的通用机制。在多数情况下,提供 JNDI 供应者的容器可以充当有限的数据存储,这样管理员就可以设置应用程序的执行属性,并让其他应用程序引用这些属性(Java 管理扩展(Java Management Extensions,JMX)也可以用作这个目的)。JNDI 在 J2EE 应用程序中的主要角色就是提供间接层,这样组件就可以发现所需要的资源,而不用了解这些间接性。
现在我们重新来看一下 Dolly 的情况。在其简单的 Web 应用程序中,她直接从应用程序代码中使用了一个 JDBC 连接。参见清单 1,我们可以看出,Dolly 显式地把 JDBC 驱动程序、数据库 URL 以及她的用户名和口令编码到了 servlet 中:
Connection conn=null;
try {
Class.forName("com.mysql.jdbc.Driver",
true, Thread.currentThread().getContextClassLoader());
conn=DriverManager.getConnection("jdbc:mysql://dbserver?user=dolly&password=dagger");
/* use the connection here */
c.close();
}
catch(Exception e) {
e.printStackTrace();
}
finally {
if(conn!=null) {
try {
conn.close();
} catch(SQLException e) {}
}
}
|
如果不用这种方式指定配置信息,Dolly(以及她的同伴们)使用 JNDI 来查找 JDBC DataSource
会更好一些,如清单 2 所示:
Connection conn=null;
try {
Context ctx=new InitialContext();
Object datasourceRef=ctx.lookup("java:comp/env/jdbc/mydatasource");
DataSource ds=(Datasource)datasourceRef;
Connection c=ds.getConnection();
/* use the connection */
c.close();
}
catch(Exception e) {
e.printStackTrace();
}
finally {
if(conn!=null) {
try {
conn.close();
} catch(SQLException e) { }
}
}
|
为了能够得到 JDBC 连接,首先要执行一些小的部署配置,这样我们才可以在本地组件的 JNDI 下文中查找 DataSource
。这可能有点烦琐,但是很容易学。不幸的是,这意味着即使是为了测试组件,开发人员也必须涉足部署人员的领地,并且还要准备配置应用服务器。
为了让 JNDI 解析 java:comp/env/jdbc/mydatasource
引用,部署人员必须把 <resource-ref>
标签插入 web.xml 文件(Web 应用程序的部署描述符)。 <resource-ref>
标签的意思就是“这个组件依赖于外部资源”。清单 3 显示了一个示例:
<resource-ref>
<description>Dollys DataSource</description>
<res-ref-name>jdbc/mydatasource</res-ref-name>
<res-ref-type>javax.sql.DataSource</res-ref-type>
<res-auth>Container</res-auth>
</resource-ref>
|
<resource-ref>
入口告诉 servlet 容器,部署人员要在 组件命名上下文(component naming context) 中设置一个叫做jdbc/mydatasource
的资源。组件命名上下文由前缀 java:comp/env/
表示,所以完全限定的本地资源名称是:java:comp/env/jdbc/mydatasource
.
这只定义了到外部资源的本地引用,还没有创建引用指向的实际资源。(在 Java 语言中,类似的情况可能是: <resource-ref>
声明了一个引用,比如 Object foo
,但是没有把 foo
设置成实际引用任何 Object
。)
部署人员的工作就是创建 DataSource
(或者是创建一个 Object
对象,让 foo
指向它,在我们的 Java 语言示例中就是这样)。每个容器都有自己设置数据源的机制。例如,在 JBoss 中,是利用服务来定义数据源(请参阅 $JBOSS/server/default/deploy/hsqldb-ds.xml,把它作为示例),它指定自己是 DataSource
的全局 JNDI 名称(默认情况下是 DefaultDS
)。在创建资源之后,第三步仍然很关键:把资源连接或者绑定到应用程序组件使用的本地名称。在使用 Web 应用程序的情况下,是使用特定于供应商的部署描述符扩展来指定这个绑定,清单 4 中显示了一个这样的例子。(JBoss 用称为 jboss-Web.xml
的文件作为特定于供应商的 Web 应用程序部署描述符。)
清单 4. 用特定于供应商的部署描述符将资源绑定到 JDI 名称
<resource-ref>
<res-ref-name>jdbc/mydatasource</res-ref-name>
<jndi-name>java:DefaultDS</jndi-name>
</resource-ref>
|
这表明应该将本地资源引用名称( jdbc/mydatasource
)映射到名为 java:DefaultDS
的全局资源。如果全局资源名称出于某种原因发生了变化,而应用程序的代码无需变化,那么只需修改这个映射即可。在这里,有两个级别的间接寻址:一个定义并命名资源(java:DefaultDS
),另一个把特定于本地组件的名称( jdbc/mydatasource
)绑定到命名的资源。(实际上,当您在 EAR 级别上映射资源时,可能还存在第三级别的间接寻址。)
当然,J2EE 中的资源并不局限于 JDBC 数据源。引用的类型有很多,其中包括资源引用(已经讨论过)、环境实体和 EJB 引用。特别是 EJB 引用,它暴露了 JNDI 在 J2EE 中的另外一项关键角色:查找其他应用程序组件。
试想一下这种情况:当一家公司从 Order Ontology Processing Services(OOPS)购买了一个可部署的 EJB 组件来处理客户订单时,会发生什么。为了便于举例说明,我们把它叫做 ProcessOrders V1.0。ProcessOrders 1.0 有两部分:一组接口和支持类(home 和 remote 接口,以及支持的传输类);实际 EJB 组件自身。选择 OOPS 是因为它在这个领域的专业性。
该公司遵照 J2EE 规范,编写使用 EJB 引用的 Web 应用程序。公司的部署人员把 ProcessOrders 1.0 绑定到 JNDI 树中,将它用作ejb/ProcessOrders/1.0
,并解析 Web 应用程序的资源名称,以指向这个全局 JNDI 名称。目前为止,这些都是 EJB 组件非常普通的用法。但是,当我们考虑公司的开发周期与公司供应商之间的交互时,事情就变得复杂起来。在这里,JNDI 也能帮助我们。
我们假设 OOPS 发布了一个新版本,即 ProcessOrders V1.1。这个新版本有一些新功能,公司内部的一个新应用程序需要这些新功能,而且很自然地扩展了 EJB 组件的业务接口。
在这里,公司有以下几个选择:可以更新所有应用程序来使用新版本,也可以编写自己的版本,或者使用 JNDI 的引用解析,允许每个应用程序在不影响其他应用程序的情况下使用自己的 EJB 组件版本。立刻更新所有应用程序对维护来说是一场噩梦,它要求对所有组件都进行完整的回归测试,这通常是一项艰巨的任务,而且如果发生任何功能测试失败的话,那么还要进行另一轮调试。
编写内部(in-house)组件常常是没有必要的重复工作。如果组件是由在这个业务领域内具有专业知识的公司编写的,那么给定的 IT 商店不可能像专业的组件供应商那样精通业务功能。
正如您可能已经猜到的那样,最好的解决方案是用 JNDI 解析。EJB 的 JNDI 引用非常类似于 JDBC 资源的引用。对于每个引用,部署人员都需要把新组件按特定的名称(比如说 ejb/ProcessOrders/1.1
)绑定到全局树中,对于需要 EJB 组件的其他每个组件,还要为组件在部署描述符中解析 EJB 引用。依赖于 V1.0 以前的应用程序不需要进行任何修改,也不需要重新测试,这缩短了实现的时间、降低了成本并减少了复杂性。在服务趋于转换的环境中,这是一种很有效的方法。可以对应用程序架构中所得到的所有组件进行这类配置管理,从 EJB 组件到 JMS 队列和主题,再到简单配置字符串或其他对象,这可以降低随时间的推移服务变更所产生的维护成本,同时还可以简化部署,减少集成工作。
有一个古老的计算机科学笑话:每个编程问题都可以仅仅用一个抽象层(或间接的)来解决。在 J2EE 中,JNDI 是把 J2EE 应用程序合在一起的粘合剂,但还没有紧到无法让人很容易地把它们分开并重新装配。JNDI 提供的间接寻址允许跨企业交付可伸缩的、功能强大且很灵活的应用程序。这是 J2EE 的承诺,而且经过一些计划和预先考虑,这个承诺是完全可以实现的。实际上,它要比许多人想像的容易得多。
相关推荐
- **开发者角色**:定义了在J2EE项目中不同开发者的职责范围。 - **本书所用的软件**:列出了指南编写过程中使用的主要工具和软件。 - **第二章:动手做一个EJB**: - **准备工作**:介绍了开始编写EJB...
J2EE应用运行在容器中,如应用服务器,如Tomcat、WebLogic、GlassFish等。容器提供了诸如安全、事务管理、生命周期管理等服务,使开发者能够专注于业务逻辑的实现。 通过以上介绍,我们可以看到J2EE是一个强大且...
在这个场景下,“JNDI 在 J2EE 中的角色”是一个具体的文章主题,它涉及到Java Naming and Directory Interface (JNDI)在Java Enterprise Edition (J2EE)平台中的应用。 JNDI是Java提供的一种服务接口,它允许Java...
在J2EE实例中,你会接触到诸如Web层、业务逻辑层(Service层)和数据访问层(DAO层)的分层架构设计。Web层通常由Servlet和JSP组成,负责接收用户请求并返回响应;业务逻辑层处理业务规则和计算,常通过JavaBean或...
在IT行业中,J2EE(Java 2 Platform, Enterprise Edition)作为企业级应用开发的基石,一直备受关注。掌握J2EE技术是许多Java开发者职业生涯中的重要一步,而面试则是检验开发者技能的关键环节。本集锦汇总了J2EE...
在J2EE(Java Platform, Enterprise Edition)环境中,JMS扮演着核心角色,尤其是在实现企业级的分布式系统和微服务架构时。 JMS的主要组件包括: 1. **消息生产者(Message Producer)**:负责创建并发送消息到...
在J2EE(Java 2 Platform, Enterprise Edition)框架中,JNDI扮演着核心角色。它不仅用于资源定位,也是EJB(Enterprise JavaBeans)、JMS(Java Message Service)、JDBC(Java Database Connectivity)等关键组件...
它在J2EE 5中扮演着消息传递的重要角色。 7. **Java Transaction API (JTA)** 和 **Java Transaction Service (JTS)**:这些API和服务用于管理和协调跨越多个资源的事务,确保数据的一致性和完整性。 8. **Java ...
- **Java Naming and Directory Interface (JNDI)**:JNDI提供了一种查找和命名服务的方法,使得应用程序可以在不同的环境中查找和引用资源。 - **Java Message Service (JMS)**:JMS提供了一种消息传递机制,使得...
- **开发者角色**:在J2EE项目中,开发者角色包括应用程序设计师、业务逻辑开发者、Web组件开发者和系统集成者。每个角色都有特定的任务,共同构建复杂的企业级应用。 ### J2EE的实践与部署 - **J2EE组件的打包**...
在J2EE中,Servlet扮演着服务器与客户端之间交互的重要角色,它可以处理请求,生成响应,并能持久化数据。Servlet API提供了对HTTP协议的抽象,使得开发者无需关注底层通信细节,只需专注于业务逻辑。 2. **JSP...
在J2EE环境中,jar(Java Archive)文件扮演着至关重要的角色,它们封装了Java类库,方便开发者集成和使用。以下将详细阐述J2EE中jar文件的相关知识点。 1. **JAR文件基础** JAR文件是Java的归档文件格式,用于...
可扩展标记语言(XML)在J2EE中扮演着重要角色,尤其是在Web服务和数据交换方面。XML提供了一种灵活的数据表示方式,易于解析和生成,成为不同系统间交换数据的首选格式。 #### JMS:消息中间件的接口 Java消息...
J2EE在早期版本中主要包含了Web组件、EJB(Enterprise JavaBeans)、JMS(Java Message Service)、JTA(Java Transaction API)等核心技术。 **一、J2EE架构** J2EE架构基于分层模型,通常包括以下层次: 1. **...
J2EE(Java 2 Platform, Enterprise Edition)是Java平台的企业版,主要用于构建分布式、多层的企业级应用程序,尤其在处理B/S架构中的业务逻辑、数据存储和事务处理等方面具有显著优势。 在J2EE技术体系中,主要...
8. **部署与容器**:J2EE应用通常在应用服务器如Tomcat、Glassfish或WebLogic中运行。通过实例,你可以学习如何编写部署描述符(deployment descriptor),以及如何在容器中部署和管理应用。 9. **性能优化**:J2EE...
在Java世界中,J2EE(Java 2 Platform, Enterprise Edition)是一个用于构建企业级分布式应用的框架。这个"j2ee练习"标题和描述暗示我们可能会探讨一系列与J2EE相关的编程练习,旨在帮助开发者熟悉和提升在该平台上...
2. **J2EE部署描述符**:在J2EE应用中,部署描述符(Deployment Descriptor)是XML文件,用于配置应用程序的行为,例如Servlet映射、安全角色等。理解如何编写和使用这些文件对于正确部署应用至关重要。 3. **应用...