2012-10-18 26 views
3

我知道在无状态会话bean中使用实例变量是一个流行的讨论主题,并且已经阅读了其中的一些内容,但是我特别需要的是这个主题我的应用程序的实际设计。在无状态的EJB定时器中正确使用实例变量

我的企业应用程序由几个无状态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); 
    } 

} 

然而,当我做了一个小测试手动调用多个计时器,以不同的间隔,eventIDs和serverIPs,我没有从所有的定时器预期的行为(其中一些从未超时等。 )。

上述来源是否适合所需用途,或者我应该如何设计/实施它?如果是的话,你能否提出一些建议?

回答

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注释方法的方法调用。

+0

存储数据的另一种方式是将'name'属性设置为'static',或者如果名称是为每个定时器指定的,则要使用'static Map '并使用'timer.getInfo() .toString()'作为'Map'键。 –