1

同じ JSF リクエストに対して、PhaseListener の beforePhase() メソッドと afterPhase() メソッドの間で属性を共有する必要があります。

次のスニペットはスレッドセーフですか?

public class MyPhaseListener implements PhaseListener {

  private MyObject o = null;

  @Override
  public void beforePhase(PhaseEvent event) {
    if (condition) {
      o = new MyObject();
    }
  }

  @Override
  public void afterPhase(PhaseEvent event) {
    if (o != null) {
      o.process();
      o = null;
    }
  }

  @Override
  public PhaseId getPhaseId() {
    return PhaseId.RESTORE_VIEW;
  }

}

そうでない場合、他の解決策は何ですか?

4

2 に答える 2

3

これは間違いなくスレッドセーフではありません。複数のリクエスト間で共有されるアプリケーション全体のフェーズ リスナー インスタンスは 1 つだけです。基本的に、フェーズ リスナーは@ApplicationScopedマネージド Bean のようなものです。

コンテキスト属性として設定するだけです。

public class MyPhaseListener implements PhaseListener {

  @Override
  public void beforePhase(PhaseEvent event) {
    if (condition) {
      event.getFacesContext().setAttribute("o", new MyObject());
    }
  }

  @Override
  public void afterPhase(PhaseEvent event) {
    MyObject o = (MyObject) event.getFacesContext().getAttribute("o");
    if (o != null) {
      o.process();
    }
  }

  @Override
  public PhaseId getPhaseId() {
    return PhaseId.RESTORE_VIEW;
  }

}
于 2013-10-04T10:21:48.620 に答える
0

これを使用することもできますがThreadLocal、名前を付けると、さまざまなクラスローダーを持つ環境で問題が発生する傾向があります:メモリ リーク。指定された環境でそれを確認してください...

beforePhase()また、とafterPhase()メソッドの間で処理が中断される可能性がある場合 (例: 例外...)、をThreadLocal適切に処理する必要があることを確認する必要があります...

これは次のようになります。

public class MyPhaseListener implements PhaseListener {

  //if null is a valid value, no initial setting is needed
  private ThreadLocal<Object> myStateObject = new ThreadLocal<Object> ();

  @Override
  public void beforePhase(PhaseEvent event) {

    //might be needed, to guarrantee no residue from an aborted processing is in there
    myState.set(null); 
    if (condition) {
      myState.set(<Object representing the state>);
    }
  }

  @Override
  public void afterPhase(PhaseEvent event) {
    try {
        Object stateObject = myState.get();
        if (stateObejct!=null) {
          //do what you have to 
        }
    } finally {
       //to be sure
       myState.remove();
    }
  }
}

この記事では、著者も ThreadLocal を使用しています...

また、この記事も目を見張るものがあり、変更可能なインスタンス レベルの情報を共有しない理由を説明しています。

ただし、PhaseListener インスタンスはアプリケーション全体のシングルトンである JSF ライフサイクルによって参照されるアプリケーション全体のシングルトンであることに注意してください。

編集は、ブール値がオブジェクトに更新され、例を調整したことを確認しました

于 2013-10-04T08:31:30.320 に答える