8

シングルトン スコープの依存関係を、逆シリアル化された後、プロトタイプの Spring Bean に再注入したいと考えています。

リポジトリ Bean に依存する Process Bean があるとします。リポジトリ Bean はシングルトンとしてスコープされますが、プロセス Bean はプロトタイプ スコープです。定期的にプロセスをシリアル化し、後で逆シリアル化します。

class Process {
   private Repository repository;
   // getters, setters, etc.
}

リポジトリをシリアライズおよびデシリアライズしたくありません。また、プロセス内の参照を保持するメンバー変数、ある種のプロキシへの参照、またはリポジトリとして宣言されたプレーンな古いメンバー変数以外のものに「一時的」を配置したくありません。

私が欲しいと思うのは、プロセスがその依存関係を、(一時的な参照を使用して) リポジトリを指すシリアライズ可能なプロキシで満たすことであり、デシリアライズ時にリポジトリを再び見つけることができるということです。それを行うためにSpringをどのようにカスタマイズできますか?

のように、プロキシを使用して依存関係の参照を保持できると思います。その正確なテクニックを使用できればいいのにと思います。しかし、Spring が生成するのを見たプロキシはシリアライズ可能ではなく、ドキュメントによると、それをシングルトン Bean で使用すると例外が発生します。

おそらく、カスタム スコープの Bean を要求されたときに常にプロキシを提供するカスタム スコープをシングルトン Bean で使用できます。それは良い考えですか?他のアイデア?

4

6 に答える 6

3

プロキシなしで、代わりにこれを使用しました:

public class Process implements HttpSessionActivationListener {
    ...
    @Override
    public void sessionDidActivate(HttpSessionEvent e) {
        ServletContext sc = e.getSession().getServletContext();
        WebApplicationContext newContext = WebApplicationContextUtils
            .getRequiredWebApplicationContext(sc);
        newContext.getAutowireCapableBeanFactory().configureBean(this, beanName);
    }
}

この例は、アプリケーション サーバーがセッションをシリアル化するときの Web 環境用ですが、どの ApplicationContext でも機能するはずです。

于 2011-09-14T01:37:30.953 に答える
3

Spring は、この問題の解決策を提供します。

春のドキュメントhttp://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/aop.html#aop-atconfigurableをご覧ください。

7.8.1 AspectJ を使用して、Spring でドメイン オブジェクトに依存性を注入する

...

このサポートは、コンテナーの制御外で作成されたオブジェクトに使用することを目的としています。ドメイン オブジェクトは、多くの場合、new 演算子を使用してプログラムで作成されるか、またはデータベース クエリの結果として ORM ツールによって作成されるため、このカテゴリに分類されます。

秘訣は、ロードタイムウィービングを使用することです。-javaagent:path/to/org.springframework.instrument-{version}.jar で jvm を開始するだけです。このエージェントは、インスタンス化されたすべてのオブジェクトを認識し、@Configurable で注釈が付けられている場合、そのオブジェクトを構成 (@Autowired または @Resource 依存関係を注入) します。

Process クラスを次のように変更するだけです。

@Configurable
class Process {

   @Autowired
   private transient Repository repository;
   // getters, setters, etc.
}

新しいインスタンスを作成するたびに

Process process = new Process();

spring は依存関係を自動的に注入します。これは、Process オブジェクトが逆シリアル化されている場合にも機能します。

于 2012-02-07T20:44:07.117 に答える
1

Beanをシリアル化してから、依存関係の再注入を強制するというアイデアは、最良のアーキテクチャではないと思います。

代わりに、シングルトンになる可能性のあるある種のProcessWrapperBeanを使用するのはどうでしょうか。リポジトリが挿入され、プロセスの逆シリアル化を管理するか、プロセスのセッターがあります。新しいプロセスがラッパーに設定されるとsetRepository()、プロセスが呼び出されます。プロセスを使用するBeanは、ラッパーによって新しいBeanに設定するか、プロセスに委任するProcessWrapperを呼び出すことができます。

class ProcessWrapper {
   private Repository repository;
   private Process process;
   // getters, setters, etc.

   public void do() {
      process.do();
   }

   public void setProcess(Process process) {
      this.process = process;
      this.process.setRepository(repository);
   }
}
于 2010-08-12T21:03:24.593 に答える
1

私自身の質問に答えます。これまでに問題を解決した方法は、安価な小さなプロキシを使用してシリアル化および逆シリアル化する基本クラスを作成することです。プロキシには、Bean の名前のみが含まれます。

グローバルを使用して Spring コンテキストにアクセスしていることに注意してください。より洗練されたソリューションでは、コンテキストをスレッドローカル変数に保存することができます。

public abstract class CheaplySerializableBase 
   implements Serializable, BeanNameAware {

    private String name;

    private static class SerializationProxy implements Serializable {

        private final String name;

        public SerializationProxy(CheaplySerializableBase target) {
            this.name = target.name;
        }

        Object readResolve() throws ObjectStreamException {
            return ContextLoader.globalEvilSpringContext.getBean(name);
        }

    }

    @Override
    public void setBeanName(String name) {
        this.name = name;
    }

    protected Object writeReplace() throws ObjectStreamException {
        if (name != null) {
            return new SerializationProxy(this);
        }
        return this;
    }
}

結果のシリアル化されたオブジェクトは 150 バイト程度です (私の記憶が正しければ)。

于 2010-09-29T18:39:31.447 に答える
1

オブジェクトを逆シリアル化するときに、アスペクトを使用して注入ステップを追加するのはどうですか?

これには AspectJ などが必要です。これは、Spring の @Configurable 関数と非常によく似た動作をします。

たとえば、「private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException」メソッドに関するアドバイスを追加します。

次の記事も役立つ場合があります: http://java.sun.com/developer/technicalArticles/Programming/serialization/

于 2010-08-12T21:48:11.647 に答える