7

Spring と JSF 2 を使用して Web アプリケーションを作成しています。ビジネス オブジェクトは Spring コンテナーに保持され、次のように @ManagedProperty を使用してマネージド Bean に注入します。

@ManagedBean
@ViewScoped
public class SomeMB implements Serializable {
    private static final long serialVersionUID = 1L;

    @Getter @Setter
    @ManagedProperty("#{someService}")
    private SomeService someService;
    // ...

問題は、NotSerializableExceptionSpring からのクラス ( ServiceLocatorFactoryBean ) がSomeService Bean によって使用されていることを取得し続けていることです。

作成した場合transient、デシリアライズ後に再注入するにはどうすればよいですか?

または、この問題を解決する他の方法は何でしょうか?

ここで同様の質問をいくつか読んでいますが、この問題を正確に扱っているものは見つかりませんでした。

4

4 に答える 4

4

@ManagedProperty(ManagedBean の初期化時に実行される) アノテーションで EL を介して Spring Bean を注入する代わりに、実行時に EL を評価する Bean を取得します。

このアプローチでは、JSF Bean は次のようになります。

@ManagedBean
@ViewScoped
public class SomeMB implements Serializable {
    private static final long serialVersionUID = 1L;

    private static SomeService someService() {
        return SpringJSFUtil.getBean("someService");
    }
    // ...

そして、EL 経由で Bean を取得するユーティリティー・クラスSpringJSFUtil.java :

import javax.faces.context.FacesContext;

public class SpringJSFUtil {

    public static <T> T getBean(String beanName) {
        if (beanName == null) {
            return null;
        }
        return getValue("#{" + beanName + "}");
    }

    @SuppressWarnings("unchecked")
    private static <T> T getValue(String expression) {
        FacesContext context = FacesContext.getCurrentInstance();
        return (T) context.getApplication().evaluateExpressionGet(context,
                expression, Object.class);
    }
}

これにより、Spring Bean プロパティが排除され (EL 評価をさらに数回実行するという代償を払って)、プロパティを最初に配置するというシリアル化の問題がすべて回避されます。

OmniFacesを使用した同じアプローチ:

実際のコードでは、OmniFacesから入手できるユーティリティ クラスevaluateExpressionGet(String expression)のメソッドを使用します。だから、あなたもそれを使っている人のために、これは私のコードが実際にどのように見えるかです:

import static org.omnifaces.util.Faces.evaluateExpressionGet;

@ManagedBean
@ViewScoped
public class SomeMB implements Serializable {
    private static final long serialVersionUID = 1L;

    private static SomeService someService() {
        return evaluateExpressionGet("#{someService}");
    }
    // ...

ここで、メソッドは Spring Bean 名だけでなく、完全な EL ("#{expression}") を取得することに注意してください (または ClassCastException を取得します)。

于 2012-07-16T20:23:22.667 に答える
2

Spring @Service で @Scope(value = BeanDefinition.SCOPE_SINGLETON, proxyMode = ScopedProxyMode.INTERFACES) を試してください。これにより、シリアル化可能なプロキシ オブジェクトがマネージド Bean に注入され、シリアル化解除後のアクセス時にサービスが再配置されます。

于 2013-02-08T13:02:47.470 に答える
0

フォローする人のために-注入されたResourceBundleで同様の問題がありました。BalusC の回答の一部を使用して、次のことを行いました。

@ManagedProperty(value="#{myBundle}")
private transient ResourceBundle myBundle;

private Object readResolve() {
    myBundle = FacesContext.getCurrentInstance().getApplication()
        .evaluateExpressionGet(FacesContext.getCurrentInstance(), "#{myBundle}",
        ResourceBundle.class);
    return this;
}

このようにして、EL はマネージド Bean が逆シリアル化されたときにのみ評価されます。

于 2014-01-10T19:03:33.977 に答える
-1

Spring マニュアル ( spring へのリンク)からこれを覚えておいてください。

コンストラクターベースまたはセッターベースの DI?

コンストラクター ベースとセッター ベースの両方の DI を混在させることができるため、必須の依存関係にはコンストラクター引数を使用し、オプションの依存関係にはセッターを使用することをお勧めします。セッターで @Required アノテーションを使用すると、セッターを必要な依存関係にすることができます。

特にプロパティがオプションの場合、多数のコンストラクター引数が扱いにくくなる可能性があるため、Spring チームは通常、setter インジェクションを推奨しています。また、setter メソッドは、そのクラスのオブジェクトを後で再構成または再注入できるようにします。JMX MBean による管理は、魅力的なユース ケースです。

一部の純粋主義者は、コンストラクター ベースのインジェクションを好みます。すべてのオブジェクトの依存関係を提供するということは、オブジェクトが常に完全に初期化された状態でクライアント (呼び出し元) コードに返されることを意味します。欠点は、オブジェクトが再構成および再注入しにくくなることです。

特定のクラスに最も適した DI を使用します。ソースを持っていないサードパーティのクラスを扱う場合、選択が行われることがあります。レガシー クラスはセッター メソッドを公開しない可能性があるため、コンストラクター インジェクションが唯一の利用可能な DI です。

于 2012-06-06T15:13:08.323 に答える