在集群JEE6环境(Glassfish 3.1.2)中,可以在每个集群节点上创建@Singleton bean。如果这个Singleton在它的@PostConstruct上注册了一个编程定时器-- @Timeout方法多久执行一次?--只在其中一个单点(每个滴答)上注册,或者对注册那个计时器的每个Singeton (每个滴答)只执行一次?
下面的代码是一个例子,这个问题对这段代码意味着什么。
@Singleton
public class CachedService {
@Resource
private TimerService timerService;
private static final long CACHE_TIMEOUT_DURATION_MS = 60 * 60 * 1000;
@PostConstruct
void initResetTimer() {
this.timerService.createIntervalTimer(CACHE_TIMEOUT_DURATION_MS,
CACHE_TIMEOUT_DURATION_MS,
new TimerConfig("current user cache timeout", false));
}
@Timeout
public void executeResetTimer() {
this.clearCache();
}
}示例:应用程序运行在集群中的3个节点上。假设在每个节点上实例化了Singleton,那么initResetTimer总共执行3次(每个节点一次)。那么问题是:是否每小时在所有节点上清除缓存(**executeResetTimer** )?
(我知道计时器不是同时在所有节点上运行,因为Singleton是在不同的时间实例化的,但这不是问题。)
发布于 2012-07-13 06:56:07
首先,确保您已经设置了外部共享XA数据源的计时器服务,如所述的这里。
在过去深入研究过您的问题之后,我记得一些解释在邮件列表中使用了devs,Glassfish的实现如下:
假设集群中有节点A、B和C。在节点A中创建的持久定时器由节点A“拥有”(也就是说,计时器事件被传递到节点A)。如果节点A失败,则可以将其定时器迁移到另一个活动节点。
有了这个Glassfish 不支持集群范围的@Singletons,您的计时器就会和调用initResetTimer()一样多。此外,每台服务器重新启动/重新部署都可能为每个集群节点创建一个新的计时器实例,除了旧的未取消的计时器之外,所以不要忘记取消以编程方式创建的计时器:)为了避免这一切,使用声明式@Schedule(...)方法和Glassfish将创建计时器http://www.java.net/node/695110,并希望在失败时自动迁移它们。
希望这能有所帮助。
更新:
一个以编程方式创建的定时器,无论是否集群设置,都将在它创建的JVM/节点中触发。您可以大致总结:独立计时器实例的数量等于对timer.createXxxTimer()的调用数。
发布于 2012-07-04 11:53:53
我看了一下EJB3.1规范的第18章“计时器服务”。应用程序应该按照规范行事,而不是集群。
我的理解是,如果在集群中调用一次createIntervalTimer,则定时器应该对集群中的节点数独立地触发一次。因为每个单例bean (根据您的问题)都调用createIntervalTimer,所以它将执行n次。它类似于在ServletContextListener中创建计时器。
不过这是理论。我会再次检查你针对的特定应用服务器。在glassfish中,集群范围计时器需要使用外部数据库配置计时器池。
发布于 2012-07-09 09:06:13
即使它不是一个直接的amswer,这也会有帮助:每一个集群环境只配置一个实例的一种方法是将单例ejb公开为MXbean。您应该公开一个托管的镜像,甚至可以是空的,然后在@PostCostruct标记方法中将ejb注册到jmx服务。最后,您必须提供一个@PreDestroy钩子,以便从jmx服务中取消注册。这是Java冠军Champion的建议。
https://stackoverflow.com/questions/11324514
复制相似问题