8

自分がしていることが間違っているのか、それともどこかで注釈や構成アイテムを見逃しただけなのかわかりません。状況は次のとおりです。

。という名前のセッションスコープのBeanを使用するJSFアプリケーションがありますSessionData。このBeanには、作成時に(タイプの)アプリケーションスコープのBean参照がApplicationData注入されます。これは、セッションが最初に作成されたときに問題なく機能します。依存性注入は、次のようにファイル<managed-bean>内の要素を使用して行わfaces-config.xmlれます。

<managed-bean>
    <managed-bean-name>sessionData</managed-bean-name>
    <managed-bean-class>my.package.SessionData</managed-bean-class>
    <managed-bean-scope>session</managed-bean-scope>
    <managed-property>
        <property-name>applicationData</property-name>
        <property-class>my.package.ApplicationData</property-class>
        <value>#{applicationData}</value>
    </managed-property>
</managed-bean>
<managed-bean>
    <managed-bean-name>applicationData</managed-bean-name>
    <managed-bean-class>my.package.ApplicationData</managed-bean-class>
    <managed-bean-scope>application</managed-bean-scope>
</managed-bean>

SessionDataシリアル化されたときにオブジェクトにオブジェクトを含めることは意味がないため、オブジェクトで参照を一時的なものとしてApplicationDataマークしました。 ApplicationDataSessionData

transient private ApplicationData applicationData;

Webアプリケーションが(私のTomcat 6.xコンテナーで)停止され、セッションがシリアル化されるまで、すべて問題ありません。アプリケーションを再起動してセッションが逆シリアル化されると、への参照がApplicationDataJSFによって再注入されません。デシリアライズは値のない一時的なフィールドを残すことになっていることを私は知っています。このセッションスコープのオブジェクトでは、逆シリアル化後に依存関係を再度設定する必要があることをJSFに通知する方法はありますか?

MyFacesJSF1.2とTomcat6.0.26をWebアプリケーションコンテナとして使用しています。

4

2 に答える 2

6

Bozhoが提供するソリューションは機能する可能性がありますが、現在プロキシオブジェクトを使用していないアプリケーションにプロキシオブジェクトを導入したくありません。私の解決策は理想的とは言えませんが、それで仕事は終わります。

トランジェントフィールドをそのままにしました:

transient private ApplicationData _applicationData;

SessionDataまた、オブジェクトが最初に作成されたときにJSFが最初に参照を設定できるように、セッターをそのままにしておきました。

public void setApplicationData(ApplicationData applicationData) {
    _applicationData = applicationData;
}

私が行った変更は、getterメソッドにありました。オブジェクト内のメソッドはSessionData、フィールドへの直接アクセスを停止し_applicationData、代わりにゲッターを介して参照を取得する必要があります。ゲッターは最初にnull参照をチェックします。nullの場合、管理対象Beanは。を介して取得されFacesContextます。ここでの制約はFacesContext、リクエストの存続期間中のみ利用可能であるということです。

/**
 * Get a reference to the ApplicationData object
 * @return ApplicationData
 * @throws IllegalStateException May be thrown if this method is called
 *  outside of a request and the ApplicationData object needs to be
 *  obtained via the FacesContext
 */
private ApplicationData getApplicationData() {
    if (_applicationData == null) {
        _applicationData = JSFUtilities.getManagedBean(
            "applicationData",  // name of managed bean
            ApplicationData.class);
        if (_applicationData == null) {
            throw new IllegalStateException(
                "Cannot get reference to ApplicationData object");
        }
    }
    return _applicationData;
}

誰かが気にかけているなら、これが私のgetManagedBean()メソッドのコードです:

/**
 * <p>Retrieve a JSF managed bean instance by name.  If the bean has
 * never been accessed before then it will likely be instantiated by
 * the JSF framework during the execution of this method.</p>
 * 
 * @param managedBeanKey String containing the name of the managed bean
 * @param clazz Class object that corresponds to the managed bean type
 * @return T
 * @throws IllegalArgumentException Thrown when the supplied key does
 *  not resolve to any managed bean or when a managed bean is found but
 *  the object is not of type T
 */
public static <T> T getManagedBean(String managedBeanKey, Class<T> clazz)
        throws IllegalArgumentException {
    Validate.notNull(managedBeanKey);
    Validate.isTrue(!managedBeanKey.isEmpty());
    Validate.notNull(clazz);
    FacesContext facesContext = FacesContext.getCurrentInstance();
    if (facesContext == null) {
        return null;
    }
    Validate.notNull(facesContext.getApplication());
    ELResolver resolver = facesContext.getApplication().getELResolver();
    Validate.notNull(resolver);
    ELContext elContext = facesContext.getELContext();
    Validate.notNull(elContext);
    Object managedBean = resolver.getValue(
        elContext, null, managedBeanKey);
    if (!elContext.isPropertyResolved()) {
        throw new IllegalArgumentException(
            "No managed bean found for key: " + managedBeanKey);
    }
    if (managedBean == null) {
        return null;
    } else {
        if (clazz.isInstance(managedBean)) {
            return clazz.cast(managedBean);
        } else {
            throw new IllegalArgumentException(
                "Managed bean is not of type [" + clazz.getName() +
                "] | Actual type is: [" + managedBean.getClass().getName()+
                "]");
        }
    }
}

そして、私の検証呼び出しを選択しないでください。開発が終わったら取り出します!:)

于 2010-09-23T15:45:28.923 に答える
1

メソッドを追加できます。

private void readObject(java.io.ObjectInputStream in)
 throws IOException, ClassNotFoundException {
  in.defaultReadObject();
  applicationData = initializeApplicationData();
}

またinitializeApplicationData、動的プロキシオブジェクトを使用できます。CGLIBまたはjavassistを使用して、各メソッド呼び出しの前に内部フィールド(実数)を設定するプロキシを作成しますApplicationData。の場合はnull、現在のFacesContext(その時点でアクセス可能になります)を取得し、そこからマネージドBeanを取得します。

FacesContext facesContext = FacesContext.getCurrentInstance();
originalApplicationData = (ApplicationData)facesContext.getApplication()
  .createValueBinding("#{applicationData}").getValue(facesContext);

そしてそのメソッドに委任します。

これは醜い回避策ですが、うまくいくと思います。

于 2010-09-23T12:35:10.750 に答える