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

这绝对不是线程安全的。应用程序范围内只有一个阶段侦听器实例在多个请求之间共享。基本上,阶段监听器就像一个@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()andafterPhase()方法之间被中断(例如异常......),则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 生命周期引用,而 JSF 生命周期本身就是应用范围的单例。

编辑刚刚看到布尔值更新为对象,调整示例

于 2013-10-04T08:31:30.320 回答