我知道在无状态会话bean中使用实例变量是一个很受欢迎的讨论主题,并且已经阅读了其中的一些,但我特别需要从这个主题中得到的是我的应用程序的实际设计。
我的企业应用程序由几个无状态bean组成,它们触发特定事件。在这样的事件中,我想要一些定时器也可以触发并跟踪某些事情(例如,插入数据库中的新数据,特定于原始事件)。
@Stateless
public class SpecificFeedbackImpl implements SpecificFeedback {
@Resource
protected TimerService timerService;
//more injections here
public String name;
public String ip;
@Timeout
public void timeoutHandler(Timer timer) {
if (timer.getInfo().toString().startsWith(name)) {
//search db for data of event with identifier "name"
//if anything found, then send to "ip"
}
}
public void stopTimer() {
for (Object o : this.timerService.getTimers())
if (((Timer) o).getInfo().toString().startsWith(name)){
((Timer)o).cancel();
}
}
@Override
public void startTimer(long interval, String eventID, String serverIP){
this.name = eventID;
this.ip = serverIP;
stopTimer();
TimerConfig config = new TimerConfig();
config.setInfo(name);
config.setPersistent(false);
timerService.createIntervalTimer(interval, interval, config);
}
}
然而,当我做一个手动调用多个定时器的小测试时,使用不同的间隔,eventID和serverIPs,我没有所有定时器的预期行为(其中一些从未超时,等等)。
上述来源是否适合所需用途,或者我应该设计/实施不同的用途?如果是的话,您能否提出一些选择?
答案 0 :(得分:3)
我认为你不应该将状态存储在无状态bean中。替代方法是将其存储在db / em中或将其存储在单例bean中。
编辑如下:
存储在数据库中的一种方法是使用JPA:http://www.vogella.com/articles/JavaPersistenceAPI/article.html
解释为什么在你的ejb中存储状态是一个坏主意:
更改你的超时方法是这样的:
@Timeout
public void timeoutHandler(Timer timer) {
String actualName = timer.getInfo().toString();
System.out.println("actualName=" + actualName + " storedName=" + name);
}
尝试启动一些计时器:
@Singleton
@Startup
public class SingletonBean {
@EJB
LabBean labBean;
@PostConstruct
public void init() {
labBean.startTimer(2000, "123", "1.2.3.4");
labBean.startTimer(2000, "222", "1.2.3.4");
labBean.startTimer(2000, "333", "1.2.3.4");
labBean.startTimer(2000, "444", "1.2.3.4");
labBean.startTimer(2000, "555", "1.2.3.4");
labBean.startTimer(2000, "666", "1.2.3.4");
}
}
您将看到控制台输出显示如下:
INFO: actualName=123 storedName=666
INFO: actualName=555 storedName=666
INFO: actualName=333 storedName=null
INFO: actualName=444 storedName=null
INFO: actualName=666 storedName=666
INFO: actualName=222 storedName=null
原因是当您调用startTimer()时,无状态EJB实例取自EJB池。当startTimer()方法返回时,EJB返回到池中。
当超时发生在2000ms之后,它可能是从池中取出的另一个EJB实例来处理@timeout注释方法的方法调用。