带有压缩的Java自定义序列化,用于低网络带宽使用

时间:2012-08-12 18:29:02

标签: java serialization glassfish compression ejb

我目前正在开发客户端/服务器应用程序。应用程序服务器是Glassfish v3,通过远程EJB进行通信。主要问题是序列化对象图时网络带宽的使用。例如,在下一个方法中:

@Stateless
public class MyEJB extends MyRemoteInterface {

   @Override
   public PurchaseOrder savePurchaseOrder( PurchaseOrder po ) { ... }

}

这个方法,当远程调用时,将接收一个PurchesOrder实例,该实例是一个对象图,当通过网络传输时,它将需要大量的KB,返回时也是如此。

我已经管理了这个,现在,改变这个方法的原型:

...

   @Override
   public byte[] savePurchaseOrder( byte[] po ) { ... }

...

我在通过网络传输之前和之后手动解压缩/取消/序列化PurchaseOrder实例。但是我放松了类型安全的方法而且它变得丑陋。

有没有办法在默认的序列化过程中使用java自定义序列化来压缩输出流?例如:

    @Entity
    public class PurchaseOrder implements Serializable {

       private void writeObject(ObjectOutputStream oos) throws IOException {
           // default serialization 
           oos.defaultWriteObject();

           // COMPRESS STREAM HERE (zip or gzip)
       }

       private void readObject(ObjectInputStream ois) 
           throws ClassNotFoundException, IOException {

           // DECOMPRES STREAM HERE 

           // default deserialization
           ois.defaultReadObject();
       }

    }

我需要“DE / COMPRESS STREAM HERE”部分的代码或其他好主意。

提前感谢您的建议。

济。

5 个答案:

答案 0 :(得分:2)

使用自定义序列化的一些建议很好,但根据您的对象可能会有很多工作。你可以使用泛型和包装类来获得“有点”更好的实现。

“简单”实现可能如下所示:

public class ShrinkWrap<E> implements Serializable
{
  private transient E _value;

  public ShrinkWrap(E value) { _value = value; }

  public E get() { return _value; }

  private void writeObject(ObjectOutputStream oos) throws IOException {
    // default serialization 
    oos.defaultWriteObject();

    // compress _value to a byte[] using new ObjectOutputStream(new GZIPOutputStream(new ByteArrayOutputStream()))
    byte[] compValue = ...;

    oos.writeInt(compValue.length);
    oos.write(compValue);
  }

  @SuppressWarnings("unchecked")
  private void readObject(ObjectInputStream ois) throws ClassNotFoundException, IOException {
    // default deserialization
    ois.defaultReadObject();

    byte[] compValue = new byte[ois.readInt()];
    ois.readFully(compValue);

    // decompress _value from byte[] using new ObjectInputStream(new GZIPInputStream(new ByteArrayInputStream()))
    _value = ...;
  }
}

答案 1 :(得分:1)

我建议你需要提供一个能够自动压缩/解压缩流的自定义工厂

尝试阅读http://docs.oracle.com/javase/7/docs/technotes/guides/rmi/socketfactory/index.html

答案 2 :(得分:0)

您可以使用DeflatorOutputStream和InflatorInputStream来压缩流。

如果可以,我建议使用更紧凑的序列化格式,如JSon,Exernalizable或您自己的二进制格式。这是因为默认的Java序列化相对冗长。例如一个整数使用超过80个字节。

答案 3 :(得分:0)

我认为上帝的想法是使用ZipOutputStream and ZipInputStream。您可以选择压缩对象的级别并在一个文件中发送多个对象。

答案 4 :(得分:0)

看看JBoss Serialization,值得一看,也许可以帮到你。