如何在PhaseListener的beforePhase()和afterPhase()方法之间线程安全地共享属性?

时间:2013-10-04 08:10:25

标签: multithreading jsf phaselistener

我需要在我的PhaseListener的beforePhase()和afterPhase()方法之间共享一个属性,以获得相同的JSF请求。

以下代码段是否可以线程安全?

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;
  }

}

如果没有,还有什么其他解决方案?

2 个答案:

答案 0 :(得分: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;
  }

}

答案 1 :(得分: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();
    }
  }
}

this article中,作者也使用了ThreadLocal ......

此外,this article is also a great eye-opener解释了为什么不共享可变的实例级信息:

  

要记住的一件事是,PhaseListener实例是JSF生命周期引用的应用程序范围的单例,它本身就是一个应用程序范围的Singleton。

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