我的应用程序部署在 WebSphere Liberty 23.0.0.9 上。
在下面的代码片段中,
create
方法创建计时器,cancel
方法取消计时器。 arc
表示唯一标识计时器的值。
@Stateless
public class TimerBean {
@Resource
private TimerService timerService;
public void create(String arc, Date expiration) {
timerService.createSingleActionTimer(expiration, new TimerConfig(arc, true));
}
public void cancel(String arc) {
for (Timer timer: timerService.getTimers()) {
if (arc.equals(timer.getInfo())) {
timer.cancel();
}
}
}
timerService.getTimers()
返回与此 bean 关联的所有活动计时器的列表,但由于在我的应用程序中我可能有数千个计时器,因此这个 for
循环可能会调用 timer.getInfo()
数千次。问题是 timer.getInfo()
大约需要 5 毫秒,因此仅取消一个计时器就可能需要几十秒。似乎每当调用 timer.getInfo()
时,它都会从数据库中获取计时器信息。
我的目标是减少取消一个计时器所需的时间。
鉴于这个目标,我的问题如下:
TimerService
只获取一个计时器?目前我看到获取计时器的唯一方法是使用 timerService.getTimers()
。timerService.getTimers()
,是否有更有效的获取计时器信息的方法?目前我正在使用timer.getInfo()
。不幸的是,EJB API 不提供获取单个计时器的方法。虽然与计时器关联的
info
可能是最接近 unique identity
的东西,但它可以是任何任意对象,因此不能真正存储在可实际查询的列中。此外,EJB 规范要求,如果计时器不再存在,则对计时器的每个方法调用都会导致 NoSuchObjectLocalException
,这通常要求对计时器的每个方法调用都访问数据库。
但是,WebSphere 确实提供了一种机制,可以在接受有关计时器的缓存或陈旧信息时提高效率。请参阅以下文章“缓存计时器服务的数据”。 虽然本文针对的是 WebSphere 传统 9.0.5,但所描述的 JVM 属性也适用于 Liberty(本文的 Liberty 特定版本尚未创建)。对于 Liberty,您可以使用
jvm.options
文件,而不是通过管理控制台配置属性;请参阅“定制 IBM WebSphere Liberty jvm.options 文件”。
com.ibm.websphere.ejbcontainer.allowCachedTimerDataFor
JVM 属性允许您配置哪些 EJB 允许缓存(或全部),甚至配置 Timer
接口上的哪些方法。例如,如果您希望允许 Timer.getInfo()
允许服务器中所有 EJB 缓存数据,那么您可以在 jvm.options
中指定以下内容:
-Dcom.ibm.websphere.ejbcontainer.allowCachedTimerDataFor=*=2
*
表示所有 EJB,数字 2
代表 getInfo
方法。本文提供了有关所有方法或其他方法使用什么数字以及如何将缓存限制为特定 EJB 的更多详细信息。
当为
Timer.getInfo()
启用缓存时,对 TimerService.getTimers()
的调用将在返回的计时器列表中包含其他内部数据。随后对 Timer.getInfo()
的调用将能够使用之前在 getTimers()
期间获得的状态信息,从而避免额外访问数据库。
请注意,启用此属性后,即使调用
getInfo()
可能会返回一个值,但如果计时器上次已过期或被取消,则后续调用 Timer.cancel()
可能会导致 NoSuchObjectLocalException
通过不同的线程。