避免在glassfish上删除计时器

我有一个用@Schedule注释的方法,偶尔会被容器调用。

@Schedule(second = "*/5", minute = "*", hour = "*", persistent = false) public void myTimerMethod() throws Exception { ... } 

问题是在某些条件下我希望此方法抛出exception以使正在进行的事务回滚。 但如果我执行此操作超过两次,计时器将被清除,不再调用!

 INFO: EJB5119:Expunging timer ['68@@1359143163781@@server@@domain1' 'TimedObject = MyBean' 'Application = My-War' 'BEING_DELIVERED' 'PERIODIC' 'Container ID = 89072805830524936' 'Fri Jan 25 21:49:30 CET 2013' '0' '*/5 # * # * # * # * # * # * # null # null # null # true # myTimerMethod # 0' ] after [2] failed deliveries 

我知道我可以使用在domain.xml中配置计时器重新安排

  ...   ...      ...   ...  

但我的问题是,我可以在部署应用程序时配置此设置吗?

找不到它:

 glassfish-resources.xml glassfish-ejb-jar.xml glassfish-web.xml 

有没有办法以编程方式进行呢?

(我将配置文件中的服务器配置放在配置文件而不是配置服务器背后的理由是,我的应用程序应该可以直接安装在全新的glassfish上)

我会用不同的方法。

不要直接从调度方法中抛出exception,而是尝试引入一个间接级别,如:

 ... @Inject RealWorkHere realImplementation; @Schedule(second = "*/5", minute = "*", hour = "*", persistent = false) public void myTimerMethod(){ try{ realImplementation.myTimerMethodImpl() }catch (Exception x){ // hopefully log it somewhere } } ... 

其中RealWorkHere是具有实际实现的bean,如:

 @Stateless public class RealWorkHere{ @TransactionAttribute(REQUIRES_NEW) public void myTimerMethod() throws Exception { } } 

这有以下好处:

  • 不在容器启动的事务中抛出exception(从而避免了删除)
  • 更好地记录exception
  • 明确划分“真正的”商业交易

也可以看看

  • ejb-spec#111:如果在执行定时器回调方法期间抛出应用程序exception,请清除容器的行为

如果在执行超时回调方法期间发生应用程序exception ,则当前版本4的Glassfish将清除计时器。

应用程序exception导致回滚当前事务。 在这种情况下,Glassfish再次重试错误自由执行超时回调方法。 如果再次回滚,Glassfish会清除计时器。

我在Glassfish问题跟踪器中提出了一个问题,即在发生重复情况时不要清除计时器。 Glassfish似乎是唯一一个在应用程序exception情况下清除计时器的应用程序服务器。 请参阅glassfish#20749:即使回调方法保留其合同以获取更多详细信息, Glassfish也会清除计时器 。 您是否愿意为我的问题投票。

我还在EJB规范中提出了一个问题,以阐明EJB容器在这种情况下应该如何表现。 请参阅ejb-spec#111:如果在执行计时器回调方法期间抛出应用程序exception以获取更多详细信息, 请清除容器的行为 。