JCA 规范的新版本不会使应用程序与后端系统之间的连接变得更快,但 JCA 1.5 引入了两组接口,可以加快使用连接的应用程序的运行。第一组接口解除了以前 JCA 版本中应用服务器 style="COLOR: #000000" href="http://server.it168.com/" target=_blank>服务器管理连接句柄方式的限制。
许多读者都知道,J2EE 支持两种连接使用模式,本文称之为 get-use-close 和 cached-handle。对这些模式的进一步分析有助于理解 JCA 1.5 在这方面所带来的性能改善。
get-use-close
在 get-use-close 模式中,应用程序在需要新连接时,总是先获取新连接,然后使用,然后再关闭它,如清单 1 所示。(为清楚起见,本文没有在示例清单中加入异常处理逻辑。)
清单 1. 使用 get-use-close 模式的一个 Enterprise JavaBean (EJB)
1 public class GetUseCloseEJB implements SessionBean {
2 ...
3 public void businessMethod() {
4 InitialContext context = new InitialContext();
5 DataSource dataSource = (DataSource)context.lookup("java:comp/env/jdbc/mydatasource");
6 Connection connection = datasource.getConnection();
7 ...
8 connection.close();
9 }
10 }
get-use-close 模式看起来效率不高,但是应用服务器实现的连接池可降低“获得”操作的成本。此外,因为应用程序只在需要时才保留连接,所以应用程序的不同实例或者部分可以重复使用该连接,从而降低了总的资源占用,如图 1 所示。
图 1. 使用中的 get-use-close 模式
如图 1 所示,每当 bean 方法调用 getConnection 时,连接管理器都会重复使用池中托管的连接,并只创建一个新连接句柄。当连接句柄通知连接管理器它已关闭时,托管的连接就被清除并返回池中。图 1 中的绿色线条表示托管连接与应用程序的这个实例相关联的时间。
cached-handle
在 cached-handle 模式中,应用程序在一开始是获得连接,然后在一个实例字段中缓存对它的引用,如清单 2 所示。
清单 2. cached-handle 模式
1 public class CachedHandleEJB implements SessionBean {
2 private Connection _connection;
3 ...
4 public void ejbCreate() {
5 InitialContext context = new InitialContext();
6 DataSource dataSource = (DataSource)context.lookup("java:comp/env/jdbc/mydatasource");
7 _connection = datasource.getConnection();
8 }
9 public void businessMethod() {
10 ...
11 }
12 }
应用程序开发人员通常都使用 cached-handle 方法,因为他们认为这样应用程序的性能会更好。但是因为 get-use-close 模式中连接池的作用,这两种使用模式的性能差别一般来说是很小的。尽管 cached-handle 模式可使业务方法中的逻辑更简单,但是需要额外的逻辑以便在钝化(passivation)时关闭连接,并在激活时重建连接。当容器毁坏 bean 时(如由于方法生成了一个运行时异常),还有可能留下打开的连接。
cached-handle 模式的最大问题是当 bean 或者 servlet 的一个实例使用该连接时,其他实例就不能使用它——因此连接数最多只会有实例那么多。如图 2 所示。
图 2. 使用中的 cached-handle 模式
从图 2 中可以看到,创建 EJB 时(从绿色线条开始),托管的连接与连接句柄关联,并且这个 bean 实例以外的任何其他对象都不能使用这个连接。(绿色线条无限延伸。)
针对这种情况,JCA 1.5 规范引入了两个新的接口,如清单 3 所示。
清单 3. 解除关联(dissociation)和惰性关联(lazy association)接口
1 public interface DissociatableManagedConnection {
2 void dissociateConnections() throws ResourceException;
3 }
4 public interface LazyAssociatableConnectionManager {
5 void associateConnection(Object connection,
6 ManagedConnectionFactory mcf,
7 ConnectionRequestInfo cxReqInfo)
8 throws ResourceException
9 }
解除关联
资源适配器的托管连接实现第一个接口—— 解除关联 接口——以向连接管理器表明适配器支持这种优化。当连接暂时超出范围时(即当 bean 或者 servlet 方法退出时),如果连接管理器支持这种优化的话,它就可以解除由应用程序使用的连接句柄与表示物理资源的托管连接的关联。这使托管连接可以返回连接池,为应用程序的其他部分所使用。
惰性关联
这种优化使用 惰性关联,而不是在下次调用方法时重新将连接句柄与托管连接关联。如果方法没有使用连接,或者它只调用连接句柄上不需要访问后端的简单方法,那么托管连接未必会从池中移出。相反,当连接句柄确定它不需要与一个托管连接重新关联时,它就可以将连接管理器强制转换为 LazyAssociatableConnectionManager 并调用 associateConnection 方法。该方法以连接句柄为第一个参数,然后是托管连接厂,以及对 allocateConnection 的第一次调用时传递的请求信息。然后连接管理器从池中找到另一个合适的托管连接,并使用这个托管连接的 associateConnection 方法将它与连接句柄关联。
图 3 显示了这种优化对 图 2 中的 cached-handle 用法的效果。
图 3. 惰性关联降低资源用量
图 3 中虚线箭头表示方法完成时 EJB 容器对连接管理器的通知。这时,托管的连接与连接句柄解除关联,只有当方法试图使用这个句柄时,托管连接才会重新关联。短的绿色线条显示托管连接现在绑定到 EJB 上,以缩短时间并可以在别的地方重新使用。