在集群JEE6环境(Glassfish 3.1.2)中,可以在每个集群节点上创建@Singleton
bean。如果这个Singleton Bean在@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会在不同时间实例化,但这不是问题/问题。)
答案 0 :(得分:3)
首先,确保按照here所述,为外部共享XA数据源设置定时器服务。
过去深入研究过你的问题,我记得邮件列表中的开发人员some explanation,Glassfish的实现如下:
假设您在群集中有节点A,B和C.持久计时器已创建 在节点A处由节点A“拥有”(即计时器事件被传递到 节点A)。如果节点A出现故障,则其定时器可以迁移到另一个实时节点 节点
拥有Glassfish doesn't support群集范围@Singletons
,您最终会获得与initResetTimer()
调用一样多的计时器。此外,每个服务器重新启动/重新部署可能会为每个群集节点创建一个新的计时器实例,此外还有旧的未删除的计时器,所以不要忘记取消以编程方式创建的计时器:)为了避免这种情况,请使用声明式@Schedule(...)
方法和Glassfish将创建计时器 once across cluster ,并希望在失败时自动迁移它们。
希望这有帮助。
更新:
以编程方式创建的计时器(持久性或非持久性)将在其创建的JVM /节点中触发,而不管集群设置与否。您可以粗略总结:独立计时器实例的数量等于timer.createXxxTimer()
答案 1 :(得分:2)
我看了EJB 3.1规范的第18章“定时器服务”。应用程序应根据规范独立于群集运行。
我的理解是,如果在群集中调用createIntervalTimer
一次,则计时器应该独立地触发群集中的节点数。由于每个单例bean(根据您的问题)调用createIntervalTimer
,因此它将执行 n 次。它类似于creating timers in ServletContextListener。
但这是理论。我会仔细检查您定位的特定应用服务器。在glassfish中,cluster-wide timer需要使用外部数据库配置计时器池。
答案 2 :(得分:1)
即使它不是直接的,这也无论如何都有帮助:每个集群环境只配置一个实例的一种方法是将单例ejb暴露为MXbean。 您必须公开一个托管的接口,甚至可能是空的,然后在@PostCostruct标记的方法中将您的ejb注册到jmx服务。最后,您必须提供@PreDestroy挂钩以从jmx服务取消注册。 这是Java冠军Adam Bien建议的方式。