我需要在我的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;
}
}
如果没有,还有什么其他解决方案?
答案 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。
编辑刚看到布尔已更新为对象,已调整示例