资源描述
东南大学硕士学位论文摘要在当今的企业级应用中,JAVA占据着重要的位置。在这种应用中,三层 构架已经成为一种事实的技术标准。它们分别是处理数据库事务的后台,处理 业务的中间层,以及用于交互的显示层.在这三层中,都涉及到数据的收集及 处理。所以数据的收集与处理是企业级应用的核心之一,它对整个系统的性能 有重要的决定作用。如果对这些数据进行缓存,那么将极大的提高系统的性能。这个缓存系统以基于最大缓存时间的策略实现了一个基础缓存系统,在这个基 础系统上,通过实现缓存的集群、面向方面的缓存、以及对实时数据的缓存,形成一个比较完善的缓存系统。关键词:缓存系统、缓存集群、实时数据缓存、面向方面缓存东南大学硕I学位论文Abstract:In todays enterprise-level applications Java occupy important positions.In such applications,three-tier architecture has become a fact of the technical standardsoThey are background which dealing with database services,the middle-tier processing business logic,and showing tier.In this three-tier architecture,which allinvolve data collection and processing.Therefore,data collection and processing isimpact on the performance of system.If tiiese data is cached,then the systems performance will be greatly improved.The caching system bases on the time-to-live strategy to achieve a basis caching system.Through it,caching clusters,real-time data caching,AOP caching systems is implemented。Keywords:Caching system,caching clusters,real-time date caching,AOPIV第一章前言随着Internet网络的迅速发展,基于互联网的企业应用要求软件平台具有开放性、分布性和平 台无关性。于是就相继出现了 RPC心OM心。RBA等技术,但这些技术在实际应用中存在着许多不 足和局限。它们的特定协议难以通过防火墙,因而不适于Web上的应用开发。为了进一步开发基于 Web的应用,出现了 Sun公司的Sun ONE(Open Net Environment开发网络环境)。Sun ONE体系结构以Java语言为核心,包括J2SE/J2EE/J2ME和一系列的标准、技术及协议。开发人员很容易就能从网上免费获得和使用包括Java集成开发环境、Java数据库和中间件(Application Server)服务器等产品,以及它们的源代码。Sun ONE更接近或能满足互联网在智能 化Web服务方面对分布性、开发性和平台无关性的要求。随着Java技术的不断发展,它根据市场 进一步细分为:针对企业网应用的J2EE(Java2 Enterprise Edition)、针对普通PC应用的J2SE(Java 2 Standard Edition)和针对嵌入式设备及消费类电器的J2ME(Java 2 Micro Edition)三个版本。在当今竞争激烈的市场中,各种机构正面临着一种艰难的挑战:既要在业已缩短的开发周期内 降低成本,又要提供广泛的电子商务服务。为了解决这个问题,许多公司都正在研究如何使用Java 在中间层实施商业逻辑。Java的使用者常常发现,开发变得简单了,部署的速度也变快了。此外,分布式Java应用的实施还可以提高系统的可伸缩性和可靠性。结果是Java大量的用于企业级应用 开发中。在企业级应用中,三层构架技术已经非常成熟。它们是处理数据库的后台,处理商业逻辑的中间层,以及用于数据交互的显示层。在这三层中,都涉及到数据的收集和处理。所以数据的处理是企业级应用的 核心之一,系统对数据处理的能力对系统的性能有着决定性的作用。而在企业级应用中,需要处理的数据 容量是海量的,由这些数据所生成的对象也往往非常复杂。在企业级开发中,JAVA开发者经常要通过JDBC 从数据库中获得大量,复杂的数据,并把这些数据组装成相应的对象。如果是在集群环境下,这些对象还 要被位于不同IP地址的多台主机共享。在这些更杂的对象被创造及使用后,它们将被JAVA虚拟机的包收 集机制回收并销毁。如果系统再次需要使用这些对象,就不得不重新创建它们,这将极大的增加系统的负 担、降低系统的性能。所以如果要提高系统的整体性能,缓存这些对象将是一个必然的选择。图展示了使用企业级应用程序的客户通过客户端(client)或web端(浏览器)向位于服 东南大学硕士学位论文务器中的商业逻辑处理层提交要处理的商业事务。根据商业事务需要处理的数据,商业逻辑处理层 首先从缓存系统中查找数据,如果数据不存在,则从数据库中查找数据,同时把数据装入缓存中,以便以后继续使用。缓存系统的核心柩架是使用基于对象缓存最大时间(Tkne-to-Live,TTL)策略实 现的基础缓存系统,在这个基础缓存系统之上,实现了分布式缓存,面向方面缓存,实时数据缓存。1.1 缓存系统的课题来源随着电信重组和中国加入WTO,国内各电信企业面临着严峻的市场竞争形势,如何从售后阶段 考虑,提升面向市场前端和大客户的主动服务能力、快速响应能力、业务开通能力和业务保障能力 等全方位支撑响应市场经营作是每个电信运营商迫切需要解决的问题。目前,各大电信运营商的运维作重心正在从“面向网络、面向设备”向“面向业务、面向客 户”转移。在这种情况广东网通集团提出了以客户为中心的企业理念。在这种理念的指导下,广东网通集团提出了对客户进行分类,把那些业务量大的客户单独挑选出来.统称它们为“大客户”,这些大客户包括银行、政府机关、大型企业等。网通集团为了更好的服务于这些大客户,专门新成 立了大客户部,专门针对这些大客户提供及时的、专业级的服务。虽然网通集团已经基本建设了较完善的覆盖多专业的网络、并在满足每一专业网络或业务的管 理需求方面,建立了相应的专业网管系统或网元管理系统,形成了较全面的网络管理体系,并利用 各自的专业网管系统基本实现了故障及配置管理。但是,目前的网络管理体系还存在不尽如人意的 地方,特别是缺乏跨专业的故障关联分析和面向业务客户的故障分析早现功能,具体表现在:网络设备和网管系统多厂商、多技术、多专业的存在,导致了许多网管终端的存在;不同网 管终端的操作界面及管理方式各不相同,导致需要不同的维护人员去管理不同的网管系统,造成人 力支出增加,运维成本提高。缺乏对跨专业告警信息进行集中处理的方式和手段,由于告警信息中包含大量的无用或重复 告警信息,使维护人员很难将精力集中在对重要告警信息的处理上,降低了故障处理的效率;部分专业网管的原始告警信息无法与相应的业务和客户信息关联,即无法进行告警对业务和 客户的影响性分析,无法做到对客户业务故障的主动式管理:在大客户部门的成立后一段时间内,部门工作人员发现在为大客户提供服务的过程中面临着以 上提到的许多困难。这些困难主要是在为大客户提供服务时要跨越多个领域,如电路管理、性能管 理、告警管理等。这些不同的领域属于不同的部门,使用不同的软件来实现具体的业务,这无疑增 加了工作人员的负担。但在向大客户提供服务时最大的困难是这些系统并没有针对大客户部门的业 务需求提供具体的功能。所以大客户部门急需一个针对大客户的具体业务,进行专门处理的软件系 统。这地终形成了广东网通大客户网络服务系统的设计与开发。在大客户网络服务系统开发的过程中,用户对系统的运行速度提出了很高的要求。但在软件开 发过程中,由于电信具体业务的复杂性,一个具体业务可能与大量的数据相关。如工作人员杳询一 个大客户的信息,得到的结果是这个大客户有上千条电路,每一个电路又由多个子网连接而成,这 些子网本身也包括了大量的信息,同时这些子网又与众多告警信息相关联。系统还必需能快速的展 示每个电路的具体路由图,而路由图的生成需要大量的计算与绘图。由于大客户网大络服务系统采用客户端一服务器的模式(C/3),每次业务的处理都需要由客 户端发起,服务器端进行相关业务的处理,在业务处理过程中,服务器端通过数据库服务黯获取具 体的数据,并把这些数据组装成数据流发送到客户端。客户端最后向工作人员展现数据。在开发过 程中,开发人员发现大部分数据有一个共同的特点,就是数据的变化比较少。例如工作人员查询一 个大客户的电路信息后,可能过了一段时间再次查询这个大客户的电路信息,在这两次或多次查询 过程中,大客户电路信息的改变非常少,最多的情况是修改、增加或删除了几条电路,而电路的大 部分数据没有改变。但在具体使用开发中的系统时,为了保证数据的1E确性,这两次业务操作都重 新查询了数据库。这样的系统执行策略就造成了一个问题,既尽管数据的变化不多,但每次业务的重新提交都导 致了系统的重新处理。这包括从数据库中取得数据,在服务器端处理数据并将数据发送回客户端,客户端最后还要对这些数据进行处理。这些操作的最终结果是极大了降低了系统的运行速度,增加 了系统的负担。这也导致了用户在试用系统的过程中对系统的整体速度提出了意见,要求开发人员提高系统的 整体运行速度和执行效率。用户的需求直接导致了大客户网络管理系统数据缓存功能的提出。在数 据缓存功能设计过程中,系统设计人员发现缓存功能跨越了多个业务模块,既在多个模块中都要使 用缓存功能。这样为了保证系统的完整性、易修改性和可维护性,提出了缓存功能模块的开发计划。这个计划的最终目的是通过提供缓存接口给各个业务模块开发人员,使得这些业务模块实现具体的 数据缓存功能,并通过缓存系统提高系统的进行速度。1.2 缓存系统及其发展趋势缓存系统是指通过将数据存储在计算机内存中或永久磁盘中,以便应用程序可以快速的重新获 取这些数据,缓存系统在需要大量处理数据的企业级应用中有着广泛的使用。在JAVA语言成为企 业级应用主要开发语言后,一些基于JAVA语言的缓存系统被发展,并被成功应用于各种应用系统 中。例如,基于数据库的关系对象映射产品,如hibernate,JDO,缓存对于这些产品性能的提高起 着重要的作用。在用于显示数据的客户端,缓存对于servlet性能的提高也有着重要的作用。但由于 这些缓存系统自身原因,它们或多或少的都存在一些问题,如不支持集群,没有考虑数据的实时性,对用户的操作不透明等等。1.3 缓存系统的总体设计在设计缓存系统时,首先要确定是缓存系统是企业级应用软件一个子功能,一个实现缓存功能 的模块。它不是一个具体的应用软件,它通过给企业级应用软件提供接口调用来实现应用软件的具 体缓存功能。虽然它是大客户网络管理系统中的一个组成部分,但在设计时,还要考虑缓存系统应 可用于公司的其它项目,这就要求在具体设计时需要考虑缓存系统的通用性,既把缓存系统作为一 个相对独立的,可用于企业级应用软件的一个功能模块。在系统设计的同时,还应该考虑系统的前 瞻性,既在设计缓存系统时使用一些新的设计理念,留出一些新功能的接口(如面向方面的实现),以便在将来可以适应企业级应用软件的升级。在设计系统时首要的考虑如何实现通过最可行的方案,以最快的速度来实现最基本的缓存功能,以满足大客户网络管理系统现实的业务需求,以便争取用户对系统的认同。所以在设计时,首先设 计了基于缓存对象最大缓存时间属性的基础缓存系统,这个基础缓存系统实现了在同一个JVM虚拟 机中对数据的内存缓存。在这个基础之上,增加了把缓存对象存储在永久磁盘上的功能实现,它实 现了在缓存系统关闭时可以对缓存对象进行保存,在缓存系统重新启动时可以自动读取已经保存在 磁盘上的缓存对象,以及在内存容量紧张时把一些缓存对象临时存储在磁盘上。最后通过实现缓存 对象清除算法来更新缓存对象,使得缓存系统初步建立并可以实际使用.在实现了以上一个具体的、可用的缓存系统之后,通过研究分布式应用在Java语言中的具体实 现策略,缓存系统实现了基于socket的UDP多播,基于RMI协议,以及基于JMS协议的分布式缓 存。考虑到实际的软件开发过程中,面向对象的方法具有很大的局限性。这种局限性使得应用系统 中的代码充斥着同样的缓存操作代码。为了满足未来软件系统的升级,通过对面向方面的设计方法 的研究,把缓存这个系统关注点从系统代码中抽离出来,并把它作为系统中的一个关注点来实现,3东南大学硕士学位论文从而最终实现系统代码的模块化。最后,根据大客户网管系统的具体要求以及在实际使用时遇到的问题,增加了缓存执行要求的 XML格式定义,增加了事件监听器机制。并通过对实时数据的缓存和分布式缓存在网管系统中的使 用,验证了缓存系统的可用性,最终完成缓存系统的初步开发。1.4 论文的组织结构本论文的组织结构为:第二章主要讲述了基于 TIL的基础缓存系统的设计,通过对缓存元素定 义、缓存对象执行策略、缓存对象清除算法等方面的设计与实现,详细说明了缓存系统的基础架构。第三章通过对基于Java语言的网络协议的研究,提出了使用socket、RMI、JMS三种分布式网络实 现机制来实现分布式缓存的设计与实现。本章对程序设计的具体方法和系统API等方面也给出了详 细的介绍。第四章主要讲述了面向对象方法在软件设计过程中的可能造成的问题,以及如何使用面 向方面技术来解决这些问题。本章详细介绍了面向方面缓存系统的设计与实现。第五章主要结合缓 存系统在大客户网管系统中使用时遇到的问题,在缓存系统中增加了 XML配置、事件监听器,实 时与非实时数据缓存的设计,由于这三个部分不是缓存系统的核心组成部分,所以本章只对它们的 设计与使用进行了简单的介绍。在文章的最后,通过在客户模块中使用缓存系统,验证了缓存系统 的可用性。4第二章基础缓存架构在设计一个中小型软件时,最好的方式是先从最基础的系统需求开始,仔细研究系统要实现的 最基础功能,并在实现这些最基础功能的基础上不断地对系统进行完善,最终形成一个可用的软件 产品。现在首先来分析缓存系统最基础、最低的需求,即实现在同一个机器上的同一个JAVA虚拟 机。VM)中实现对数据的缓存。图2.1展示了在同一个主机中,系统可能存在两个或多个Java虚拟机(JVM),在这种情况下 虽然这些Java虚拟机位于同一个主机内存中,但不同的JVM之间的数据是不能共享的。所以基础 缓存架构是实现基于同一个主机的同一个JVM的缓存实现。下面将首先对Java虚拟机做简要介绍。5东南大学硕上学位论文2.1 Java 虚拟机(JVM)就本质而言,Java是一种技术,它由四方面组成:Java编程语言,Java类文件格式,Java虚拟 机和Java应用程序接口(Java API)。它们的关系如F图所示*Java编译环境Java平的行期环境图2.2 Java四个方面的关系运行期环境代表着Java平台,开发人员编写Java代码(Java文件),然后将之编译成字节码(.class 文件)。最后字节码被装入内存,一旦字节码进入虚拟机,它就会被解释器解料执行,或者是被即时 代码发生器有选择的转换成机器码执行。从上图也可以看出Java平台由Java虚拟机和Java应用程 序接口搭建,Java语言则是进入这个平台的通道,用Java语言编写并编译的程序可以运行在这个平 台上,在Java平台的结构中,可以看出,Java虚拟机(JVM)处在核心的位置,是程序与底层操作系 统和硬件无关的关键。它的下方是移植接口,移植接口由两部分组成:适配器和Java操作系统,其 中依赖了平台的部分称为适配器;JVM通过移植接口在具体的平台和操作系统上实现;在JVM的 上方是Java的基本类库和扩展类库以及它们的API,利用Java API编写的应用程序(application)和 小程序Oavaapplet)可以在任何Java平台上运行而无需考虑底层平台,就是因为有Java虚拟机(JVM)实现了程序与操作系统的分离,从而实现了 Java的平台无关性。2.1.1 Java虚拟机(JVM)概述Java虚拟机的特点由以下几个部分组成;1.JVMQava虚拟机)是一种用于计算设备的规范,可用不同的方式(软件或硬件)加以实现。编译虚拟机的指令集与编译微处理器的指令集非常类似。2.Java虚拟机包括一套字节码指令集、一组寄存器、一个栈、一个垃圾回收堆和一个存储方 法域。63.Java虚拟机是可运行Java代码的假想计算机。只要根据JVM规格描述将解释器移植到特定 的计算机上,就能保证经过编译的任何Java代码能够在该系统上运行.4.Java虚拟机是一个想象中的机器,在实际的计算机上通过软件模拟来实现。Java虚拟机有 自己想象中的便件,如处理器、堆栈、寄存器等,还具有相应的指令系统。Java语言的一个非常重要的特点就是与平台的无关性。而使用Java虚拟机是实现这一特点的关 键。一般的高级语言如果要在不同的平台上运行,至少需要编译成不同的目标代码。而引入Java语 言虚拟机后,Java语言在不同平台上运行时不需要重新编译。Java语言使用模式Java虚拟机屏蔽了 与具体平台相关的信息,使得Java语言编译程序只需生成在Java虚拟机上运行的目标代码(字节码),就可以在多种平台上不加修改地运行。Java虚拟机在执行字节码时,把字节码解释成具体平台上的 机器指令执行。X1.2 JVM规格描述JVM的设计目标是提供一个基于抽象规格描述的计算机模型,为解释程序开发人员提供很好的 灵活性,同时也确保Java代码可在符合该规范的任何系统上运行.JVM对其实现的某些方面给出?具体的定义,特别是对Java可执行代码,即字节码(Bytecode)的格式给出了明确的规格。这一规格 包括操作码和操作数的语法和数值、标识符的数值表示方式、以及Java类文件中的Java对象、常量 缓冲池在JVM的存储映象。JVM定义了控制Java代码解释执行和具体实现的五种规格,它们是:JVM指令系统、JVM寄 存器、JVM栈结构、JVM碎片回收堆、JVM存储区。JVM指令系统:JVM指令系统同其他计算机的指令系统极其相似。Java指令也是由操作码和操作数两部分组 成。操作码为8位二进制数,操作数紧随在操作码的后面,其长度根据需要而不同。操作码用于指 定一条指令操作的性质(在这里采用汇编符号的形式进行说明),如iload表示从存储器中装入一个 整数,anewarmy表示为一个新数组分配空间,iand表示两个整数的“与“,ret用于流程控制,表示从 对某一方法的调用中返回.当长度大于8位时,操作数被分为两个以上字节存放。JVM采用了Big endian”的编码方式来处理这种情况,即高位bits存放在低字节中。这同Motorola及其他的RISC CPU 采用的编码方式是一致的,而与Intel采用的“little endian”的编码方式即低位bits存放在低位字节的 方法不同。Java的8位操作码的长度使得JVM最多有256种指令,目前已使用了 160多种操作码。JVM寄存器:所有的CPU均包含用于保存系统状态和处理器所需信息的寄存器组。如果虚拟机定义较多的寄 存器,便可以从中得到更多的信息而不必对栈或内存进行访问,这有利于提高运行速度。然而,如 果虚拟机中的寄存器比实际CPU的寄存器多,在实现虚拟机时就会占用处理器大量的时间来用常规 存储器模拟寄存器,这反而会降低虚拟机的效率。针对这种情况,JVM只设置了 4个最为常用的寄 存器。它们是:pc程序计数器、optop操作数栈顶指针、frame当前执行环境指针,van;指向当前 执行环境中第一个局部变量的指针。所有寄存器均为32位。pc用于记录程序的执行。optop frame 和vars用于记录指向Java栈区的指针。JVM栈结构:作为基于栈结构的计算机,Java栈是JVM存储信息的主要方法。当JVM得到一个Java字节码 应用程序后,便为该代码中类的每一个方法创建一个栈框架,以保存该方法的状态信息。每个栈框 架包括以下三类信息:局部变量:用于存储类的方法中所用到的局部变量。vars寄存器指向该变量表中的第一个局部变 量。执行环境:用于保存解释器对Java字节码进行解释过程中所需的信息。它们是,上次调用的方 法、局部变量指针、操作数栈的栈顶和栈底指针.执行环境是一个执行一个方法的控制中心。例如:7东南大学硕上学位论文如果解释器要执行iadd(整数加法),首先要从fiame寄存器中找到当前执行环境,而后便从执行环境 中找到操作数栈,从栈顶弹出两个整数进行加法运算,最后将结果压入栈顶。操作数栈:用于存储运算所需操作数及运算的结果。JVM碎片回收堆:Java类的实例所需的存储空间是在堆上分配的。解驿器具体承担为类实例分配空间的工作。解 释器在为一个实例分配完存储空间后,便开始记录对该实例所占用的内存区域的使用。一旦对象使 用完毕,便将其回收到堆中。在Java语言中,除了 new语句外没有其他方法为对象申请利和放内存。对内存进行释放和回收 的工作是由Java运行系统承担的。这允许Java运行系统的设计者自己决定碎片回收的方法。在SUN 公司开发的Java解释器和Hot Java环境中,碎片回收用后台线程的方式来执行。这不但为运行系统 提供了良好的性能,而且使程序设计人员摆脱了自己控制内存使用的风险。JVM存储区:JVM有两类存储区,常量缓冲池和方法区。常量缓冲池用于存储类的名称、方法和字段名以及 串常量。方法区则用于存储Java方法的字节码。对于这两种存储区域具体实现方式在JVM规格中 没有明确规定。这使得Java应用程序的存储布局必须在运行过程中确定,依赖于具体平台的实现方 式。对比分析:如果把Java原程序想象成C+原程序,Java原程序编译后生成的字节码就相当于 C+原程序编译后的80 x86的机器码(二进制程序文件),JVM虚拟机相当于80 x86计算机系统,Java解释器相当于80 x86CPU在80 x86CPU上运行的是机器码,在Java解释器上运行的是Java字 节码。Java解释器相当于运行Java字节码的“CPU”,但该“CPU”不是通过硬件实现 的,而是用软件实现的。Java解释器实际上就是特定的平台下的一个应用程序。只要实 现了特定平台下的解释器程序,Java字节码就能通过解释器程序在该平台下运行,这是 Java跨平台的根本。2.L3 JVM的体系结构一个JVM实例的行为不光是它自己的事,还涉及到它的子系统、存储区域、数据类型和指令这 些部分,它们描述了 JVM的一个抽象的内部体系结构,其目的不光规定实现JVM时它内部的体系 结构,更重要的是提供了一种方式,用于严格定义实现时的外部行为。每个JVM都有两种机制,一 个是装载具有合适名称的类(类或是接口),叫做类装载子系统;另外的一个负责执行包含在已装载的 类或接口中的指令,叫做运行引擎。每个JVM又包括方法区、堆、Java栈、程序计数器和本地方法 栈这五个部分,这几个部分和类装载机制与运行引擎机制一起组成的体系结构图为:8我子系统美文件图2.3 JVM的体系结构JVM的每个实例都有一个它自己的方法区和一个堆,运行于JVM内的所有的线程都 共享这些区域;当虚拟机装载类文件的时候,它解析其中的二进制数据所包含的类信息,并把它们放到方法域中;当程序运行的时候,JVM把程序初始化的所有对象置于堆上;而每个线程创建的时候,都会拥有自己的程序计数器和Java栈,其中程序计数器中的 值指向下一条即将被执行的指令,线程的Java栈则存储为该线程调用Java方法的状态;本地方法调用的状态被存储在本地方法栈,该方法栈依赖于具体的实现2.L4 JVM的运行过程上面对虚拟机的各个部分进行了比较详细的说明,下面通过一个具体的例子来分析它的运行过 程。虚拟机通过调用某个指定类的main方法启动,传递给main 一个字符串数组参数,使指定的类 被装载,同时链接该类所使用的其它的类型,并且初始化它们。例如对于程序:class HelloApppublic STatic void main(String args)(System.suLprintlnCHeH。Woridr*);for(int i=0;i args,length;i+)System.out.println(args);)编诺后在命令行模式下键入:java HelloApp run virtual machine将通过调用HelloApp的方法main来启动java虚拟机,传递给main 一个包含三个字符串“run”、“irtuaT*、machine”的数组.现在我们略述虚拟机在执行HelloApp时可能采取的步骤。开始试图执行类HelloApp的main方法,发现该类并没有被装载,也就是说虚拟机当前不包含 该类的二进制代表,于是虚拟机使用ClassLoader试图寻找这样的二进制代表。如果这个进程失败,则抛出一个异常。类被装载后同时在main方法被调用之前,必须对类HelloApp与其它类型进行链 接然后初始化。链接包含三个阶段:检验,准备和解析。检验检查被装载的主类的符号和语义,准 备则创建类或接口的静态域以及把这些域初始化为标准的默认值,解析负责检查主类对其它类或接 9东南大学硕上学位论文口的符号引用,在这一步它是可选的。类的初始化是对类中声明的静态初始化函数和静态域的初始 化构造方法的执行。一个类在初始化之前它的父类必须被初始化。整个过程如下:图2.4 Java虚拟机的运行过程2.2缓存元素类结构定义在企业级应用中,商业逻辑层根据要处理的商业事务从数据库中取得相应数据并对这些数据进 行处理。从数据库中获取的这些数据并不是一些杂乱的二进制符号,而是根据规则组装成的对象集 合。其过程是应用程序从数据库中取得数据集,接着把这些数据集根据类的定义格式组装成相应的 对象,应用程序使用这些对象进行商业业务处理。在这些对象使用结束后,由Java的包收集机制自 动的问收并销毁。如果系统事先对这些对象进行缓存,那么以后再次使用这些对象时则可以从缓存 中取得这些对象,这样就减少了从数据库中再次读取数据所需要的资源消耗和系统占用。为了在缓 存系统对这些对象进行缓存,以便系统可以再次从缓存中获取这些对象,这些对象必需事先定义一 些属性,这样缓存系统才可以对这些对象进行相应的正确操作.在这些对象属性的基础上,定义对 象方法来处理这些属性。这些属性与方法的集合就构成了一个缓存系统中的基础类:缓存元素类(Element)。2.2.1 缓存元素执行的接口Java中的接口是一系列方法的声明,是一些方法特征的集合,一个接口只有方法的特征没有方 法的实现,因此这些方法可以在不同的地方被不同的类实现,而这些实现可以具有不同的行为(功 能).接口把方法的特征和方法的实现分割开来。这种分割体现在接口常常代表一个角色,它包装与 该角色相关的操作和属性,而实现这个接口的类便是扮演这个角色的演员 一个角色由不同的演员 来演,而不同的演员之间除了扮演一个共同的角色之外,还有其自身的特征。缓存系统为了实现分布式缓存,必需实现以F功能:缓存对象可以通过网络传送到另一台主机,缓存对象在到达网络上的另一个主机后,可以重新组装成原来的对象。而这需要缓存元素类实现Java 系统的两个接口,Serializable接口,Ckmeable接口.Serializable接口:缓存元素类通过实现java.io.Serializable接口以启用其序列化功能。未实现此接口的类将无法使 其序列化或反序列化。可序列化类的所有子类型本身都是可序列化的。序列化接口没有方法或字段,仅用于标识可序列化的语义.对象序列化能让你将一个实现了Serializable接口的对象转换成一组字 节(byte),这样以后需要这个对象时候,就能把这些字节数据恢复出来,并据此重新构建那个对象。同时这些字节数据可以通过网络进行传输,从而实现Java的分布式功能.CloneableficO:缓存元素类通过实现javaang.ckmeable接口以实现对象的拷贝功能,其本质是在内存中重新划 分一个空间,把对象拷贝到这个内存空间中。实现这个接口的类必需实现cbneO方法,当要拷贝对 象时,调用类的ckmeO方法实现对象的拷贝。缓存元素类的clone方法代码如下:public final Object clone()throws CloneNotSupportedException Element element=new Element(deepCopy(key),deepCopy(value),version);element.creationTime=creationTime;element.lastAccess,Hme=lastAccessTime;element.nextToLastAccessTime-nextlbLastAccessTime;elementitCount=hitCount;return element;在上面的代码中,缓存元素类的值(value)属性是一个要缓存的具体对象,这个对象可能还包 含其它的对象。使用普通的对象拷贝方法将不能保证对象的对象也能被正确的拷贝。这里通过 deepCopy方法实现复杂对象,既对象的对象的拷贝。也就是说如果一个对象还包括其它的对象,那 么简单拷贝只能拷贝最外层的对象,也就是只能拷贝对象的表面.为了把自身拥有的对象也进行拷 贝,必需在拷贝时使用Serializable方法,以下是deepCopy方法的代码片断,private Object deepCopy(Object oldValue)Serializable newValue=null;ByteArrayOutputStream bout=new ByteArrayOutputStream();ObjectOutputStream oos=new ObjectOutputStream(bout);oos,writeObject(oldVialue);ByteArraylnputStream bin=new ByteArraylnputStream(bouttoByteArray();Objectinputstream ois=new ObjectInputStream(bin);newValue=(Serializable)ois.readObject();return newValue;2.2.2 缓存元素类的属性定义东南大学硕士学位论文Element-serialVersionUID:long-key:object-value:object-version:long*lastAccessTime:long-nextToLastAccessTime:longhitCount:iong图2.5缓存元素类属性UML图缓存元素类就是由图2.5所示的这些属性组成的,缓存系统中的方法使用这些属性实现缓存系统 的对象缓存功能。这些属性的具体功能定义如下:serialVersionUID:在java中serialVersionUID是控制反序列化能否成功的标志,只要这个值不一 样,对象就无法进行反序列化。但只要这个值相同,无论如何都将反序列化。在这个过程中,对于 向上兼容性,新数据流中的多余的内容将会被忽略:对于向F兼容性而言,旧的数据流中所包含的 所有内容都将会被恢复,新版本的类中没有涉及到的部分将保持默认值。为了在反序列化时,确保 类版本的兼容性,最好在每个要序列化的类中加入private static final long serialVerskmUID这个属性。这样,即使类的结构在与之对应的对象已经序列化后做了修改,该对象依然可以被正确反序列化,否则,如果不显式定义该属性,这个属性值将由JVM根据类的相关信息计算,而修改后的类的计算 结果与修改前的类的计算结果往往不同,从而造成对象的反序列化因为类版本不兼容而失败。key:缓存对象的名称,缓存系统通过它唯一指定一个缓存对象。value:缓存系统要缓存的对象。version:缓存对象的版本号,用于实时数据缓存中。它可以用来确定缓存的对象是否已经被更 新。createTime:缓存对象被存入缓存的时间。lastAccessTime:缓存对象最后被访问的时间。nextToLastAccessTime;缓存对象上次访问的时间。通过与lastAccessTime比较,可以得知缓存对 象是否已经超过了对象缓存时间最大值(TTL)。hitCount:缓存对象被访问的总次数。223缓存元素类的方法定义Element+equalsO:bool+hashCode():int+updateAccessStatistics():void图2.6缓存元素类主要方法UML图1.equals方法:这个方法是缓存元素类从Java的基类,Object类继承的方法。equalsO用来确定类的对象是否一致,12既这些对象的值是否一致.特殊情况是根据equalsO方法,如果两个对象是相等的,它们必须有相 同的hashCode。值。类的equals()的语义在Implementer的左侧定义;定义对类来说equals()意味着什么 是其设计工作的一部分,O0ect提供的缺省实现简单引用下面的等式:public boolean equals(Object obj)(return(this=obj);在这种缺省实现模式下,只有它们引用真正同一个对象时方法才返回真值。同样,提供的 hashCodeO方法的缺省实现通过将对象的内存地址映射成一个整数值来生成对象的哈希值。这里要注 意的是由于在某些架构上,地址空间大于int值的范围,这会造成两个不同的对象有相同的哈希值。Java语言规范对equals(Object)方法的要求如下:L自反性:对于任何非空引用x,Kequals(Object)将返回true。2.对称性:对于任何引用x和y,当且仅当y.equals(x)返回true时,xequals(y)返回true3.传递性:对于任何引用x、y和z,如果kequals(y)返回true并且y.equals(z)也返回true,那 么,equals(z)也应该返回true04.一致性:如果x和y引用的对象没有改变,那么工8四13)的重复调用应该返回同一结果。S.对任何非空引用x,?cequals(nun)应该返回回能。以下是缓存系统equals代码的片断:public final boolean equals(Object object)Element element=(Element)object;if(ky=null|elemenLgeQ与 ectKeyO-null)return false;return key.equals(elenient.getObjectKeyO);在缓存系统中,一个缓存对象由一个键值(key)唯一的确定,只要确定缓存对象的键值相等,就 可以确定这两个缓存对象是相等的。所以,缓存元素类通过键值判断缓存的对象是否相等。2.hasCode方法:一个对象的HashCode就是一个简单的Hash算法的实现,虽然它和那些真正的复杂的Hash算 法相比还不能叫真正的算法,但如何实现它,与对象在存取时性能有着非常重要的关系。有可能,不同的HashCode可能会使对象存取产生成百上千倍的性能差别.例如,在缓存系统中使用了 Java中两个重要的数据结构:HashMap和Hashtable,虽然它们在功 能和具体实现上有很大的差别,如继承关系不同,对value的约束条件
展开阅读全文