网站内容管理系统

  作者:板桥banq

上页

2.3  Castor 与XML持久化

在Java中,对象序列化成二进制数据是比较方便的。但是将一个对象序列化成XML文本时,也许就没那么简单了。对象和XML之间序列化和反序列化依赖很多方面,比如文本的编码、映射设置等。
将包含数据的对象序列化成XML文本后,就可以很方便地实现数据的持久化保存。
数据持久化表示数据将脱离应用程序的生存周期,也就是说,当这个应用程序退出或计算机关机,这些数据还将继续存在。因为这些数据已经被保存到永久存储介质上,如硬盘文件系统或关系数据库系统。
关系数据库是最经常使用的存储介质,在以后章节中将讨论结合EJB来使用关系数据库。将XML文件存储到硬盘文件系统中也是一种可选的持久化方案,这种方案的优点就是开发或维护的成本比较低,本项目中将使用硬盘文件系统作为存储介质。
对象的序列化需要很丰富的XML API,最经常使用的就是SAX和DOM,但是在做一些简单的XML操作时,如获取XML中一个数据,首先遍历整个文档的树形结构,在父子或兄弟关系的节点上导航一番,这些都会需要编写很多代码,可见是非常琐碎和麻烦。
JDOM(http://www.jdom.org/)在这方面做得比较好,它用来分析XML文本是非常方便的,在本项目中,可以使用JDOM来读取系统的XML配置文件。
但是,在使用JDOM实现将对象序列化到XML文本时,代码还会涉及到该XML文本的结构。也就是说,在代码中硬编码XML文本的节点名称,这是非常不具备可重用性和拓展性的。
要达到良好的重用性和灵活的扩展性,就必须将一些操作细节封装起来,因此,需要将XML和数据交互操作的细节封装起来,这就会使用到DBO模式。
在讨论DBO模式(Data Bind Object Pattern)之前,首先必须了解一个很重要的概念,就是MVC模式中的Model。它泛指的是一种业务对象模型(Business Object Model),数据对象模型(Data Object Model)是业务对象模型的一种,它包含状态以及操作状态的行为。数据对象也可以被认为等同于经常提到的另外一个名词:值对象(Value Object)。
数据对象是对真实世界中实体软件的抽象。它可以是人、事或地方以及一些商业概念,比如订单、客户这些概念也属于业务对象。
例如“人”可以形成一个数据对象,如下:
public class Person implements java.io.Serializable {
      //人的姓名
   private String name = null;
     // 人的年龄
   private Integer  age = null;
     //没有名字的情况下创建一个人
   public Person() {
      super();
   }
     //以一个给定的名字创建一个人
   public Person(String name) {
      this.name  = name;
   }
     // @return 返回这个人的年龄
   public Integer getAge() {
      return age;
   }
     // @return 返回这个人的名字
   public String getName() {
      return name;
   }
     // 设置这个人的年龄
   public void setAge(Integer age) {
      this.age = age;
   }
     // 设置这个人的名字
   public void setName(String name) {
      this.name = name;
   }
}
在这个数据对象中,定义了人的一些属性。比如他的名字、年龄,而且有一些setXXX getXXX操作这些属性。这个类Person是对现实中“人”对象化的概括。
将这个类序列化成XML文本,将会涉及很多操作细节。使用DBO模式可以封装这些细节,从而达到代码的可重用性。
DBO模式有3个参与角色:
数据对象:将要被序列化到XML或从XML反序列化的对象。
数据绑定对象:这是一个工具型的基本对象,这个基本对象抽象了XML的序列化和XML API的具体使用细节。
XML 序列化 API: 真正实现XML序列化的具体行为,具体实现可以采取JDOM、Castor、JAXB或其他类似工具。
与JDOM相比,Castor XML更好地封装XML序列化过程,使用Castor XML需要亲自编写的代码将更少。也可以说Castor XML其实是DBO模式的具体实现。
Castor(http://castor.exolab.org/)是一种将Java对象和XML自动绑定的开源软件。它可以在Java对象、XML文本、SQL数据表以及LDAP目录之间绑定。
下面CastorHandler类是使用Castor XML将Person对象序列化到XML文本,并直接持久化保存到文件系统:
/**
 * 使用Castor作为XML文件和对象的绑定工具
 * <p>Copyright: Jdon.com Copyright (c) 2003</p>
 * <p>Company: 上海汲道计算机技术有限公司</p>
 * @author banq
 * @version 1.0
 */
public class CastorHandler {
  public final static String module = CastorHandler.class.getName();
  private static PropsUtil propsUtil = PropsUtil.getInstance();

  /**
   * 获得对象和XML之间映射的关系
   */
  public static Mapping getMapping(String MappingFile) {
    Mapping mapping = (Mapping) SimpleCachePool.get(MappingFile);
    if (mapping == null) {
      String pathMappingFile = propsUtil.getConfFile(MappingFile);
      try {
        mapping = new Mapping();
        mapping.loadMapping(pathMappingFile);
        SimpleCachePool.put(MappingFile, mapping);
      } catch (Exception e) {
        Debug.logError("get mapping error " + e, module);
      }
    }
    return mapping;
  }

 

  /**
   * 获得反序列化的对象
   */
  private static Unmarshaller getUnmarshaller(String MappingFile,
                                      String className)
throws Exception {
    Unmarshaller un = (Unmarshaller) SimpleCachePool.get(className);
    if (un == null) {
      try {
        Class c = Class.forName(className);
        un = new Unmarshaller(c);
        un.setMapping(getMapping(MappingFile));
        SimpleCachePool.put(className, un);
      } catch (Exception e) {
        Debug.logError(" getUnmarshaller error:  " , module);
        throw new Exception(e);
      }
    }
    return un;
  }

  /**
   * 从XML文件中读取对象
   */
  public static Object read(String MappingFile, String className,
                            String xmlfile) throws Exception {
    Object object = null;
    try {
      Unmarshaller un = getUnmarshaller(MappingFile, className);
      FileReader in = new FileReader(xmlfile);
      object = un.unmarshal(in);
      in.close();
    } catch (Exception e) {
      Debug.logError(" read " + className + " form file:" + xmlfile + e, module);
      throw new Exception(e);
    }
    return object;
  }

  /**
   * 将对象序列化到XML文件中
   */
  public static void write(String MappingFile, Object object, String outfile) throws
      Exception {
    try {
      FileWriter out = new FileWriter(outfile);
      Marshaller ms = new Marshaller(out);
      ms.setMapping(getMapping(MappingFile));
      ms.setEncoding(propsUtil.ENCODING);
      ms.marshal(object);
      out.close();
    } catch (Exception e) {
      Debug.logError("write object to file :" + e, module);
      throw new Exception(e);
    }
  }
}
调用CastorHandler:
String mappingFile  =  "mapping.xml";
String outfile  =  "d:\data\person.xml";
// 创建一个新的对象
Person person = new Person("板桥里人");
person.setAge(new Integer(33));
CastorHandler.write(mappingFile, person, outfile)
其中mapping.xml是对象和XML之间结构的映射表:
<mapping>
  <description>a map file for the personion>
    <class name="Person
        <field name="name” type="string" />
        <field name="age” type="integer" />
    </class>
</mapping>
这样就把person对象写入到d:\data\person.xml文件中。该CastorHandler是DBO模式中的数据绑定对象;person是数据对象;在CastorHandlet中封装的是关于XML序列化的API。例如: getMapping方法是获取org.exolab.castor.mapping.Mapping的一个实例,而getUnmarshaller是获得一个反序列化的对象等。
遵循DBO模式的CastorHandler可以被用来进行任何对象到XML的序列化或反序列化,与具体的XML文本结构就无任何关系,所以,良好的重用性是使用DBO模式的一个显著优点。当然,因为与XML文本结构的关系定义在mapping.xml配置文件中,使用CastorHandler时就必须配置这样一个mapping.xml,对于一些只有XML的读取操作来说,过于复杂了点。
但是,在本项目中,CastorHandler可以方便地实现内容数据的持久化,其操作的简易性和方便性已经远远超过它的缺点。

2.4  Cache缓存设计

是否有缓冲机制(Cache)是衡量一个J2EE产品是否成熟的重要标志。因为缓冲对于J2EE系统的运行性能有至关重要的作用,特别是在大量用户并行访问时,没有缓冲机制几乎是不可想象的事情。
J2EE作为一个多层结构,每发生一次请求,将可能经过系统的许多层次。这些层次中有的可能位于另外一台服务器上,那么网络连接开销将延迟请求信号的处理时间。使用缓冲可以节约请求信号的处理时间,大大提高系统的整体响应能力。
在J2EE系统运行中,有大量经常使用的对象,如session对象和用户资料对象等,创建这些对象可能需要首先访问数据库或文件系统;而销毁这些对象则需要释放该对象占用的内存,因此,创建和销毁对象的过程可能是复杂的,造成的性能损耗也是非常大的。
为了避免创建和销毁的开销,将那些频繁使用的对象保存在内存缓冲中,这样就能大幅度提高应用系统的性能。
在单个JVM中实现缓冲是比较容易的,应用系统通过一个Singleton接口从内存缓冲中读取数据,如果缓冲中没有所要读取的数据,那么就从存储介质或网络连接中读取,读取后再将此数据保存到缓冲中,由于缓冲内存容量有限,缓冲系统会将访问不频繁的数据逐步从缓冲内存中删除,这就是 LRU (Last Recently Used)算法。
另外,缓冲还有校正的问题,缓冲只是将数据源的数据保存在内存中。在一个分布式环境中,如果数据源被其他用户从其他服务器进行更改,那么必须通知所有有关这个数据源的缓冲进行及时更新。

因此,在一个分布式的集群Cluster(负载平衡和错误恢复)环境中,Cache的设计就比较复杂。综合各种因素,使用JMS(Java Message System)进行这种通知信息提示是一种比较切实可行的方案,带来的性能损失也不是很大,支持分布式环境的不少缓冲产品已经面世。因此,一个系统从单机环境升级到分布式环境,缓冲机制可能要作一定的修改。
在本项目中,所有的数据对象都是以XML存储在文件系统中。文件的频繁读写是非常耗时的,因此需要对数据对象实现缓冲。

详细设计和实现

确定了本项目的整体架构以后,可以针对本项目所要求的具体功能,进行具体详细的设计和实现。
J2EE项目开发的第一个突破口一般是在业务对象建模,有了系统的基本对象后才可以进行数据库设计,进而再实现系统的逻辑处理,最后实现表现层。这就是所谓“Domain First;Persistence Second;Services Third;Clients Last”。

 

 

下页