我们在服务器启动或应用程序部署时初始化缓存时遇到问题。初始化缓存涉及
此初始化过程位于启动代码中。所有这些都需要花费大量时间,因为部署需要花费大量时间或服务器启动时间正在增加。
所以我建议在启动时创建一个线程并在其中运行初始化代码。我写了一个示例应用程序来演示它。
它涉及一个ServletContextListener,一个过滤器。在监听器中,我正在创建一个新线程,HeavyProcess将在其中运行。完成后,将触发过滤器将侦听的事件。收到事件后,过滤器将允许传入的http请求。在此之前,过滤器会将所有客户端重定向到默认页面,该页面会显示应用程序正在初始化的消息。
我提出了这种方法,并提出了一些问题。
我的问题是为什么我们不能在Web应用程序中创建这样的线程。
如果这不好,那么最好的方法是什么?
答案 0 :(得分:0)
通常,在Java EE环境中创建非托管线程是个坏主意。您将在非托管线程中放松容器管理事务,用户上下文和更多Java EE概念。此外,如果您的线程处理不合适,非托管线程可能会在关闭时阻止变换器。
您使用的是哪个Java EE版本?也许您可以使用 Servlet 3.0的异步功能?
或者调用异步EJB来完成重启( @PostConstruct )。然后,调用将在其作业完成时设置标志。
答案 1 :(得分:0)
如果您可以使用托管线程,请避免使用托管线程。如果您没有正确终止这些线程,则容器无法控制非托管线程,非托管线程可以重新部署。所以你必须注册非托管线程,并以某种方式终止这些(这也不容易,因为你必须仔细处理竞争条件)。
所以一个解决方案是使用@Startup
,类似这样的事情:
@Schedule(second = "*/45", minute = "*", hour = "*")
protected void asyncInit(final Timer timer) {
timer.cancel();
// Do init here
// Set flag that init has been completed
}
我在这里了解了这个方法:Executing task after deployment of Java EE application
因此,这为您提供了一个异步托管线程,部署不会被@PostConstruct
延迟。请注意timer.cancel()
。
查看您的实际问题:我建议使用支持“热启动”的缓存 。
例如, Infinispan 支持缓存存储,以便缓存内容能够在重新启动后继续存在。如果您有一个集群,那么也有分布式或复制的缓存模式。
JBoss 7嵌入了Infinispan(它是同一JVM中的集成服务),但它也可以独立运行。
另一位候选人 Redis (任何其他具有持久性的键/值商店也会这样做。)