级别: 初级 Siva Visveswaran (siva.visveswaran@javaworld.com), JavaWorld 专栏作家
2000 年 10 月 12 日 连接合用是一种用于在请求客户机之间共享服务器资源的技术。本文重点讲述在 J2EE 环境中对数据库资源和非数据库资源连接合用的支持。Siva 分析了 JDBC 2.0、JMS 1.02 和 JNDI 1.2 在连接合用方面的标准扩展 API,并讲述了那些 API 的某些现有供应商实现。然后,他讲述了即将出现的、支持用独立于供应商/可插入的方法来管理资源连接的 J2EE Connector Architecture 1.0。
Java 2 Enterprise Edition (J2EE)
规范提供了实现高度可伸缩、可靠和可用的电子商务应用的分布式基于服务的体系结构。通常,J2EE
应用体系结构与模型-视图-控制器 (MVC) 框架相对应 --
资源库/外部系统资源支持域模型(模型),JSP/Servlet
管理显示(视图),而 EJB 处理商业逻辑(控制器)。
通过服务器端所有三层中的组件实现一个典型的电子商务应用用例。考虑到用户交互数量的庞大(对于面对客户的应用,有上百万个),需要优化地共享有限的服务器端资源。这类资源可能包括数据库、消息队列、目录、企业系统
(SAP、CICS)
等等,它们中的每一个都可以由使用代表资源访问点的连接对象的应用来访问。管理对那些共享资源的访问对于满足
J2EE 应用的高性能需求来说至关重要。
连接合用是由数据库供应商倡导的技术,其目的是允许客户机共享一组高速缓存的连接对象,这些对象提供对数据库资源的访问。在本文中,我分析了
J2EE
环境中服务器端资源(例如数据库、消息队列、目录和企业系统)的连接合用。
为何合用资源连接?
考虑一下
代码示例 ,其中,EJB 使用 JDBC
1.0、
不使用连接合用来访问数据库资源。
很明显,该示例的主要问题是连接的打开和关闭。考虑到实体 bean
是共享组件,因此,对每个客户机请求,都要进行几次获取和释放数据库连接的操作。
从图 1 可以看出,使用 JDBC 1.0
通过数据库管理器获取和释放数据库连接将影响 EJB
层的性能。这种影响是由数据库资源管理器进程创建和摧毁那些对象而引起的。应用服务器一般需要花
1 到 3
秒的时间来建立数据库连接(包括与服务器通信、认证等等),并需要对每一个客户机
(EJB) 的请求进行连接。
图 1. 使用 JDBC 1.0 的连接管理
使用服务供应商设施的连接合用
现在看一下在 J2EE
环境中,数据库和非数据库资源类型当前可以使用哪些连接合用设施。
JDBC 2.0 标准扩展 API
JDBC 2.0 标准扩展 API
指定数据库服务供应商可以实现具有以下特性的合用技术:允许请求客户机透明地共享资源池的多个连接对象。在那种情况下,因为池管理器预先在启动时创建连接对象,所以,J2EE
组件可以使用连接对象,而不会导致数据库资源管理器上的系统开销。应用服务器供应商在其内存空间实现池管理器,并根据需要动态改变池的大小,从而优化资源的使用。图
2 中显示了这种情况。
图 2. 使用 JDBC 2.0 标准扩展的连接合用
通过使用
DataSource 接口 (JDBC 2.0) 或
DriverManager (JDBC 1.0) 接口,J2EE
组件可以获得物理数据库连接对象。要获得逻辑(合用的)连接,J2EE
组件必须使用以下这些 JDBC 2.0 合用管理器接口:
-
javax.sql.ConnectionPoolDataSource
接口,该接口充当合用的
java.sql.Connection
对象的资源管理器连接
factory。每家数据库服务器供应商都提供该接口的实现(例如,Oracle
实现
oracle.jdbc.pool.OracleConnectionPoolDataSource
类)。
-
javax.sql.PooledConnection
接口,该接口封装到数据库的物理连接。同样,数据库供应商提供其实现。
对于那些接口和 XA 连接的每一个,都存在一个 XA(X/Open
规范)等价定义。
以下代码示例显示了 EJB
应用如何利用合用的连接对象来访问数据库资源(基于 JDBC
2.0)。本例中的 EJB 组件使用 JNDI
查询来确定数据库连接池资源的位置。JNDI 1.2 标准扩展 API 允许 Java
应用以相同的方式访问位于完全不同的目录和命名系统中的对象。使用 JNDI
API,应用可以查询目录来确定任何资源(例如,数据库服务器、LDAP
服务器、打印服务器、消息服务器、文件服务器等等)的位置。有关 JNDI
的合适概述,请参阅
"The Java Naming and
Directory Interface (JNDI): A More Open and Flexible
Model"。
请注意:
实际代码可能会根据数据库供应商实现类的不同而不同。
以上代码(使用 JDBC 2.0)和使用 JDBC 1.0
的主要不同在于:
getConnection()
从池中获取已打开的连接,而
close()
只将连接对象释放回池。如今,几乎每一家数据库服务器供应商(如
Oracle、DB2、Sybase 和 Informix)都提供 JDBC 2.0
驱动程序。如今大多数应用服务器供应商(IBM、BEA、iPlanet、IONA
等)也都支持 JDBC 2.0。
应该说明的一点是:如今,几乎所有应用服务器都采用两层连接合用体系结构,其中,池位于应用服务器内存空间(与独立的连接代理不同)。
JMS 1.02 标准扩展 API
J2EE 应用组件可以使用消息传递资源与其它企业应用异步通信。JMS 1.02
标准扩展 API
提供独立于供应商的方式来与消息传递服务供应商通信。与数据库资源一样,通过使用可以合用的连接对象来访问消息队列。
JMS 1.02 API 包括下列接口以支持资源合用:
- 用于 factory 对象的
javax.jms.QueueConnectionFactory 或
javax.jms.TopicConnectionFactory
- 用于连接对象的
javax.jms.QueueConnection 或
javax.jms.TopicConnection
JMS 服务供应商实现那些接口。
代码样本 显示了 EJB
组件如何使用连接对象来访问消息队列资源。
在连接合用时,JMS factory 类通常要有代理(由管理员配置),以便
open() 和
close()
请求实际上发往管理连接池的代理。遵循 JMS API 的指示,JMS
服务器供应商可以实现数据库来管理消息队列。在那种情况下,适当的 JDBC
驱动程序将提供连接合用。如果应用已经使用 JDBC 2.0
连接池启用的数据库,那么,您所要做的只是为 JMS 配置 JNDI
特性,以使用那个 JDBC 实例。
JNDI API for LDAP
javax.naming.LDAP 包包括特定于 LDAP
的类(而不包括在通用
javax.naming.directory 中)。与
JDBC 2.0 和 JMS 1.02 API 不同,JNDI LDAP API
不为连接合用指定任何接口。目录服务供应商可以有选择地通过 SDK
提供支持。例如,iPlanet 的 Netscape Directory Server SDK 4.0 for
Java 包括以下构建 LDAP 客户机所用的类:
public class netscape.ldap.util.ConnectionPool extends java.lang.Object
methods: Connection(), getConnection(), close(), etc.
|
有关详细信息,请参阅
"Netscape Directory
Server Application Programmer's Guide"。
J2EE Connector
Architecture 1.0
在以上所有示例中,EJB
组件必须导入特定于供应商的实现类,以使用资源的连接合用设施。很明显,这种做法降低了
EJB 的可移植性,并不利于 J2EE 的发展。
理想的做法是内置一个可用于任何资源类型和所有连接管理功能(包括合用)的通用连接接口。这就是即将出现的
J2EE Connector Architecture 1.0
规范的目标之一,在我写这篇文章之时,就已经公开了一份草案副本。(请参阅
参考资料)。
图 3
显示了体系结构内部的主要概念,
资源适配器 。应用服务器所支持的每一种资源类型的可插入组件,资源适配器,都在应用服务器地址空间中执行。访问那些适配器的客户机
API 可以是 Common Client Interface (CCI)
或(为了向后兼容)特定于资源的 API(例如 JDBC 2.0)。例如,CCI 定义
javax.resource.cci.ConnectionFactory 和
javax.resource.cci.Connection ,分别作为连接 factory
和连接的接口 -- 与上一节中提到的 JDBC 2.0 接口类似。
图 3. J2EE Connector Architecture 1.0
中的资源适配器
Connector 1.0 中的连接合用
Connector 1.0 的编程模型如下:
例如,基于即将出现的 EJB 2.0
连接器体系结构的、至企业/旧有系统的 Sun 连接器的产品版 iPlanet
Unified Integration Framework Toolkit v 6.0,为 EJB
层可能要访问的每个后端系统定义了连接池。一个定期执行的线程监控池对象的使用和寿命。有关详细信息,请参阅
iPlanet Unified Integration Framewor。
EJB
层的设计考虑事项
尽管有了管理连接池的资源管理器,但是还不能保证 EJB 层具有最优性能
-- 还有一些设计考虑事项!
首先,考虑以下 EJB 客户机代码示例,该客户机访问实现连接池的 LDAP
目录 。
import netscape.ldap.util.*;
...
public class NewCustomerBean implements SessionBean {
...
private SessionContext context; // Bean Context
private LDAPConnection lc; // LDAP Connection object
...
public void setSessionContext(SessionContext sc) {
this.context = sc;
// initialize JNDI lookup parameters
Context ctx = new InitialContext(parms);
...
ConnectionPool cp = (ConnectionPool)ctx.lookup(cpsource);
// Establish LDAP Connection.
try {
this.lc = cp.getConnection();
...
}
|
以上做法有什么不妥吗?首先,有状态会话对象
(
NewCustomerBean ) 在
setEntityContext
中打开连接对象,然后持续占用它,直到使用完为止 --
如果用户(会话)数量迅速增加,就成为代价相当大的实现。第二,也是更重要的,因为连接对象不是序列化的,所以,按照
EJB 1.2 规范,容器可以在钝化时(例如,将会话 bean 从其活动状态移至
bean 实例池)废弃 bean 实例。
一种替代方法是分别在会话 bean 的
ejbActivate() 和
ejbPassivate()
方法中获取和释放资源连接。如果没有连接池,代价当然会很高,也不会建议那样做。然而,有了合用之后,使用该技术,可以用最小的
EJB
层开销来获取和释放连接。这里的要点在于:除了规范和实现所提供的设施之外,设计选择总是关键性能决定因素。
第二个考虑事项是有关认证问题的。您可能已经注意到,合用的连接意味着共享的连接,而共享的连接意味着连接不与特定的认证证书绑定。例如,在
JDBC 2.0
连接中,应用服务器池管理器在启动时,使用一个存储在配置文件中的认证证书(通常是用户标识/口令)来从数据库管理器请求预设数量的连接。有时候,那可能不满足应用的安全性策略。LDAP
连接需要将 LDAP
子树与特定证书绑定,因而也有同样的问题。在那些情况下,一种替代方法可能是使用利用特定证书建立好的已高速缓存的连接,它可以对相同类型的证书重复使用。这种方法的不利之处是已高速缓存的连接要保留很长时间。另一种替代方法可能是对资源使用通用连接,并实现某种应用层安全性。
结束语
在本文中,我根据资源的共享特性和访问资源的 EJB 组件,显示了 J2EE
环境中连接合用资源的必要。您已看到由 JDBC 2.0、JMS 1.02 和 JNDI 1.2
标准扩展 API 定义的设施,和供应商对那些 API
接口实现的支持。虽然特定于供应商的解决方案很健壮,但是对它们的使用却是以
EJB 的可移植性作为代价的。即将出现的 J2EE Connector Architecture
1.0 解决了该问题,并使资源可插入,从而使 EJB
层从处理特定于供应商的库中解脱出来。最后,我解释了为什么您的设计在利用那些合用技术来制作高性能的
J2EE 应用方面扮演着重要角色。
参考资料
关于作者  | |  |
Siva Visveswaran 已有三年以上从事 Java 技术的经历,并曾对 J2EE
深深着迷。最近,他潜心于 Fortune 100 金融服务公司和 .com
公司的大型复杂 J2EE 应用的体系结构和开发工作。他有着超过 12 年的 IT
行业经历,目前正作为大型管理咨询公司的首席顾问,致力于电子商务体系结构、基础设施技术和内容管理解决方案的工作。Siva
拥有密歇根州底特律 Wayne State 大学的计算机科学硕士学位。可以通过
siva.visveswaran@javaworld.com
与他联系。
|
对本文的评价
|