2012-03-29 80 views
4

我的EJB 3定时器有一些问题,它不止一次启动。 而不是在注释中配置计时器,我使用程序化配置,如许多博客中的解释。这里是我的代码:EJB 3定时器多次执行

@Singleton 
@Startup 
public class AutoAssignTask extends AbstractDirectoryMonitor { 

    @Resource 
    private TimerService timer; 

    @Inject 
    @PropertyResource(name = "timer.hour", resource = "/DL4/app.conf") 
    private String hour; 
    @Inject 
    @PropertyResource(name = "timer.minute", resource = "/DL4/app.conf") 
    private String minute; 
    @Inject 
    @PropertyResource(name = "timer.second", resource = "/DL4/app.conf") 
    private String second; 

    @EJB 
    private AutoAssignService autoAssignService; 

    @PostConstruct 
    public void init() { 
      // initializing with an expression. 
     this.initSchedule(); 
    } 
    protected void initSchedule() { 
     ScheduleExpression exp = new ScheduleExpression(); 
     if (!StringUtils.isEmpty(this.getHour())) { 
      exp.hour(this.getHour()); 
     } 
     if (!StringUtils.isEmpty(this.getMinute())) { 
      exp.minute(this.getMinute()); 
     } 
     if (!StringUtils.isEmpty(this.getSecond())) { 
      exp.second(this.getSecond()); 
     } 
     this.getTimer().createCalendarTimer(exp); 
    } 

    @Timeout 
    public void process() { 
     // do something 
     AutoAssignTask.LOG.info("starting job."); 
    } 

现在让我们假设我配置定时器每分钟,当我看着我的日志我获得两倍的“开始工作”日志,证明它两次启动作业。

有什么不对?

+0

这是EJB 3.1代码,不是3.0 - 相应地更改了标签。 – 2012-10-30 20:51:52

回答

1

的一点想法:

  1. 更新的代码,以显示initSchedule()方法。问题可能在ScheduleExpression
  2. 你永远不能排除服务器错误。检查以确保您的@PostConstruct不会被调用两次,如果您的服务器创建了两个单例(共同竞争条件问题),则会发生这种情况。
  3. 由于您有一些子类,请确保您知道如果AutoAssignTask被进一步子类化,AutoAssignTask@PostConstruct仍将被调用。更简单地说,还调用了EJB超类的@PostConstruct方法 - 最早的父进程。

对于2号和3,一个简单的静态的AtomicInteger和日志语句将工作:

公共类AutoAssignTask扩展AbstractDirectoryMonitor {

private static final AtomicInteger instances = new AtomicInteger(); 

@PostConstruct 
public void init() { 
    System.out.println("AutoAssignTask instance "+instances.incrementAndGet()); 
    //.... 
} 
+0

感谢您的线索。 我添加了实例计数器只是为了确认没有计时器被实例化两次。 重新启动我的GF服务后,我不再有问题了。在发布之前,我多次重启我的服务器很奇怪。的确,在某些时候,我手动杀死了Java进程,并且当服务器重新启动时,GF重用了定时器,超时被启动两次。重新加载应用程序修复了一切。 我会继续监视我的服务器并隔离问题。 – Rwanou 2012-03-30 10:00:26

+0

当然,定时器默认是持久的。我不能相信我错过了这个可能的原因!感谢您的跟进。请注意,如果需要,您可以将计时器更改为非持久性 - 可以很好地进行开发。 – 2012-03-30 19:19:07

+0

好的,我们发现了GlassFish的行为。当服务器重新启动时,现有的监视器将被保留,因此会创建一个新的监视器。相反,当您重新部署应用程序或重新加载应用程序时,将更换显示器。 – Rwanou 2012-04-26 08:00:31

3

的问题可能是很老,但它看起来(至少对于JBoss EAP 7),定时器以XML格式存储在%JBOSS_HOME%\ standalone \ data \ timer-service-data中。所以很可能它从那里读取多个ScheduleExpression。至少这是为我的情况。删除所有的XML并重新部署应用程序解决了这个问题。

+0

删除计时器文件夹的内容为我工作。看起来每次部署应用程序时,JBoss都会添加一个新的计时器。我一次有53个计时器,第一个计时器在部署完成后立即启动。重新部署或取消部署应用程序时,定时器不会被删除。 – homaxto 2017-03-21 16:51:47

+0

它看起来像TimerService.createTimer()创建持久计时器,每个部署创建一个新的。两种解决方案为我工作。 1.在创建一个新的之前调用TimerService.getAllTimers并取消它们。 2.使用TimerService。createIntervalTimer并将持久性设置为false。 – homaxto 2017-03-21 17:06:16

+0

我在Wildly 10.1.0中遇到了同样的问题。按建议删除XML文件修复了它。非常感谢。 – Boomer 2017-06-16 08:51:36