连接池(深入 J2EE 的连接合用)

不羁的心 提交于 2019-11-29 09:56:11

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 的连接管理
使用 JDBC 1.0 的连接管理

回页首

使用服务供应商设施的连接合用

现在看一下在 J2EE 环境中,数据库和非数据库资源类型当前可以使用哪些连接合用设施。

JDBC 2.0 标准扩展 API
JDBC 2.0 标准扩展 API 指定数据库服务供应商可以实现具有以下特性的合用技术:允许请求客户机透明地共享资源池的多个连接对象。在那种情况下,因为池管理器预先在启动时创建连接对象,所以,J2EE 组件可以使用连接对象,而不会导致数据库资源管理器上的系统开销。应用服务器供应商在其内存空间实现池管理器,并根据需要动态改变池的大小,从而优化资源的使用。图 2 中显示了这种情况。

图 2. 使用 JDBC 2.0 标准扩展的连接合用
使用 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 中的资源适配器
J2EE Connector Architecture 1.0 中的资源适配器

Connector 1.0 中的连接合用
Connector 1.0 的编程模型如下:

  • EJB 执行连接 factory 的 JNDI 查询,然后发出getConnection()请求。
  • 连接 factory 将请求委托给ConnectionManager。
  • 连接管理器在应用服务器中查询连接池的实例。如果没有可用的连接池,则管理器使用ManagedConnectionFactory来创建一个物理(不合用的)连接。

    在那种情况下,假定资源适配器供应商实现接口。然而,连接器体系结构并不指定应用服务器如何实现连接池,而是提供一些指示,例如,根据适配器类型、服务质量 (QoS) 需求等来划分连接池。有关详细信息,请参阅 J2EE Connector Architecture 规范

例如,基于即将出现的 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 应用方面扮演着重要角色。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!