许多企业 Java™ 技术开发人员都会构建自己的对象管理基础架构,以此改进应用程序性能。但是,对于跨多台物理机器上的分布式 JVM 运行的应用程序,传统的对象池会遇到问题。在本文中,Zhengrong Tang 将提供一个对象管理框架,这个框架可以轻松地处理分布式系统。
为了提高 Java™ 应用程序的性能,许多开发人员都会开发自己的对象管理解决方案来替代默认的垃圾收集器。一种常用的解决方案是对象池(object pooling)。创建 Java 对象是一种开销很大的操作;如果只创建对象一次并多次重复使用它们,就会减少开销。这对于服务器端应用程序尤其有意义,因为通常会重复执行相同的服务器代码。对于在单一 Java 虚拟机(JVM)中运行的应用程序,这样的解决方案通常很容易实现。但是,在多层的体系结构中,要跨多台机器和多个 JVM 管理对象实例,这会非常复杂。
在本文中,我将介绍一个在多层 J2EE 体系结构中管理 Java 对象的框架。这个框架基于 Servlet、JSP、EJB、JMS 和 Struts 技术定义的标准接口。因此,它并不依赖于任何特定厂商的解决方案。当不再需要对象实例时,其他许多对象管理解决方案要求应用程序显式地释放它们;但是这个框架并非如此,它使用范围的概念自动地释放对象实例。在禁用默认的垃圾收集器时内存泄漏是一个严重的问题,这个特性会显著降低内存泄漏的风险。总之,这个框架为改进分布式 J2EE 环境中的性能提供了一个实用且易用的解决方案。
对象创建和池
Java 对象创建和垃圾收集都是开销很大的操作。频繁的对象创建是导致 Java 应用程序性能问题的主要原因之一。这个问题在 servlet 等服务器端程序中影响更严重。在方法中常常有许多短期存在的本地变量,但是方法本身会被频繁地反复调用。因此,会频繁地创建对象,然后通过垃圾收集销毁它们。这种 object churning 现象会严重损害性能。
对象池 是这个问题的一种解决方案。其思想是创建一个对象集合(通常包含相同类型的对象)并把它们存储在一个池中。如果需要一个对象,就从池中获取它,而不需要重新创建它。当这个对象完成它的工作之后,它被返回给池,可供以后重新使用。对象池需要跟踪每个对象的状态,而且应该是线程安全的。可以找到许多 Java 对象池的实现,比如 Apache 的 Common Pool(参见 参考资料)。如果不考虑实现细节,对象池一般采用清单 1 所示的接口。
清单 1. 对象池 API
public Object getObject(Class clazz); public void returnObject(Object obj); |
getObject() 方法从池中获取给定类的一个实例。returnObject() 方法把这个对象释放回池中。
对象池在大多数情况下都可以提高性能。但是,它并非没有代价。首先,当不再需要对象时,开发人员必须显式地调用 returnObject(object)。这完全背离了自动垃圾收集机制的目标,而垃圾收集是 Java 语言的重要特性之一(可能是最重要的特性)。第二,应用程序有出现内存泄漏的风险。如果不把对象显式地返回池中,对象就会一直留着。这两个问题使开发人员不太敢采用对象池技术。
如果 Java 开发人员可以享受对象池的性能优势,同时不必为显式释放对象操心,那就好了。幸运的是,这在大多数服务器端 J2EE 应用程序中是可行的。本文讨论的框架会提供一个实用的解决方案。
一个基于范围(scope)的解决方案
我们看看一个包含 servlet、JSP 页面和 EJB 组件的服务器端应用程序。图 1 给出一种典型的设计,它使用 MVC 和 Façade 模式。
图 1. 服务器端应用程序
在收到请求时,servlet 调用会话 bean 上的一个方法,这个方法进而调用实体 bean 上的一个方法。在会话调用返回之后,servlet 把请求转发给 JSP 页面。在整个流程中,按照 图 1 所示的方式创建对象。不同的对象有不同的寿命。一些对象只在一个请求的处理周期中存在;请求完成之后,就不再需要这些对象了。其他对象的寿命可能更长:例如,它们可能在一个 HTTP 会话甚至整个应用程序范围内存在。如果标识出每个对象的范围,就可以指定在这个范围结束时自动释放对象。例如,图中的 object1 和 object4 在请求范围内存在。请求完成之后,可以自动释放这两个对象。object2 在事务范围内存在。在事务终止之后,可以自动释放它。object3 在应用程序范围内存在,因此在应用程序的整个生命周期内都存活。
为了实现这种效果,要解决两个问题:首先,修改对象池,让它理解范围的概念。第二,建立一种自动通知机制,从而在范围结束时发出通知。
ObjectManager API
在本文中,我将用对象管理器(object manager) 这个词表示这个框架,以便区别于传统的对象池。与对象池一样,对象管理器也负责从池中获取对象和把对象返回池中。另外,对象管理器还理解范围的概念。清单 2 给出对象管理器的 API.
清单 2. ObjectManager API
为了从对象池获取对象,需要提供一个范围类型和一个范围键。对象管理器把范围信息与获取的每个对象关联起来。在调用 releaseAll() 方法时,对象管理器可以识别出与给定的范围相关联的对象,并把它们释放回池中。
[1] [2] [3] [4] [5] 下一页