Java 2 Enterprise Edition (J2EE) 规范提供了实现高度可伸缩、可靠和可用的电子商务应用的分布式基于服务的体系结构。一般,J2EE 应用体系结构与模型-视图-控制器 (MVC) 框架相对应 -- 资源库/外部系统资源支持域模型(模型),JSP/Servlet 管理显示(视图),而 EJB 处理商业逻辑(控制器)。 html
经过服务器端全部三层中的组件实现一个典型的电子商务应用用例。考虑到用户交互数量的庞大(对于面对客户的应用,有上百万个),须要优化地共享有限的服务器端资源。这类资源可能包括数据库、消息队列、目录、企业系统 (SAP、CICS) 等等,它们中的每个均可以由使用表明资源访问点的链接对象的应用来访问。管理对那些共享资源的访问对于知足 J2EE 应用的高性能需求来讲相当重要。 java
链接合用是由数据库供应商倡导的技术,其目的是容许客户机共享一组高速缓存的链接对象,这些对象提供对数据库资源的访问。在本文中,我分析了 J2EE 环境中服务器端资源(例如数据库、消息队列、目录和企业系统)的链接合用。 sql
考虑一下 代码示例 ,其中,EJB 使用 JDBC 1.0、 不使用链接合用来访问数据库资源。 数据库
很明显,该示例的主要问题是链接的打开和关闭。考虑到实体 bean 是共享组件,所以,对每一个客户机请求,都要进行几回获取和释放数据库链接的操做。 编程
从图 1 能够看出,使用 JDBC 1.0 经过数据库管理器获取和释放数据库链接将影响 EJB 层的性能。这种影响是由数据库资源管理器进程建立和摧毁那些对象而引发的。应用服务器通常须要花 1 到 3 秒的时间来创建数据库链接(包括与服务器通讯、认证等等),并须要对每个客户机 (EJB) 的请求进行链接。 后端
回页首 缓存
如今看一下在 J2EE 环境中,数据库和非数据库资源类型当前可使用哪些链接合用设施。 安全
JDBC 2.0 标准扩展 API
JDBC 2.0 标准扩展 API 指定数据库服务供应商能够实现具备如下特性的合用技术:容许请求客户机透明地共享资源池的多个链接对象。在那种状况下,由于池管理器预先在启动时建立链接对象,因此,J2EE 组件可使用链接对象,而不会致使数据库资源管理器上的系统开销。应用服务器供应商在其内存空间实现池管理器,并根据须要动态改变池的大小,从而优化资源的使用。图 2 中显示了这种状况。 服务器
经过使用DataSource接口 (JDBC 2.0) 或DriverManager(JDBC 1.0) 接口,J2EE 组件能够得到物理数据库链接对象。要得到逻辑(合用的)链接,J2EE 组件必须使用如下这些 JDBC 2.0 合用管理器接口: oracle
对于那些接口和 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、DB二、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 包括下列接口以支持资源合用:
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"。
在以上全部示例中,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 接口相似。
Connector 1.0 中的链接合用
Connector 1.0 的编程模型以下:
在那种状况下,假定资源适配器供应商实现接口。然而,链接器体系结构并不指定应用服务器如何实现链接池,而是提供一些指示,例如,根据适配器类型、服务质量 (QoS) 需求等来划分链接池。有关详细信息,请参阅 J2EE Connector Architecture 规范。
例如,基于即将出现的 EJB 2.0 链接器体系结构的、至企业/旧有系统的 Sun 链接器的产品版 iPlanet Unified Integration Framework Toolkit v 6.0,为 EJB 层可能要访问的每一个后端系统定义了链接池。一个按期执行的线程监控池对象的使用和寿命。有关详细信息,请参阅 iPlanet Unified Integration Framewor。
尽管有了管理链接池的资源管理器,可是还不能保证 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 应用方面扮演着重要角色。