3

現在、クライアント/サーバー アプリケーションを開発しています。アプリケーション サーバーは 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」部分のコード、または別の良いアイデアが必要です。

アドバイスをいただきありがとうございます。

ザビエル。

4

5 に答える 5

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 = ...;
  }
}
于 2012-08-12T19:31:02.850 に答える
1

ストリームを自動的に圧縮/解凍できるカスタムファクトリを提供する必要があることをお勧めします

http://docs.oracle.com/javase/7/docs/technotes/guides/rmi/socketfactory/index.htmlを読んでみてください

于 2012-08-12T19:01:04.917 に答える
0

私は神の考えが使用していると思いますZipOutputStream and ZipInputStream。圧縮オブジェクトのレベルを選択して、1つのファイルで複数のオブジェクトを送信できます。

于 2012-08-12T19:24:40.883 に答える
0

DeflatorOutputStream と InflatorInputStream を使用して、ストリームを圧縮できます。

可能であれば、JSON、Exernalizable、または独自のバイナリ形式などのよりコンパクトなシリアル化形式を使用することをお勧めします。これは、デフォルトの Java シリアライゼーションが比較的冗長であるためです。たとえば、1 つの整数は 80 バイト以上を使用します。

于 2012-08-12T19:18:57.353 に答える
0

JBoss Serializationをご覧ください。一見の価値があり、多くの場合に役立ちます。

于 2012-08-12T19:48:33.100 に答える