0

我们面临在服务器启动或应用程序部署时初始化缓存的问题。初始化缓存涉及

  1. 查询数据库以获取项目列表
  2. 对每个项目进行 rmi 调用
  3. 侦听 JMS 队列/主题上的数据
  4. 构造缓存

这个初始化过程在启动代码中。所有这些都需要大量时间,因为部署需要大量时间或服务器启动时间正在增加。

所以我的建议是在启动时创建一个线程,并在其中运行初始化代码。我编写了一个示例应用程序来演示它。

它涉及一个 ServletContextListener,一个过滤器。在侦听器中,我正在创建一个新线程,HeavyProcess 将在其中运行。当它完成时,将触发过滤器正在侦听的事件。收到事件后,过滤器将允许传入的 http 请求。在此之前,过滤器会将所有客户端重定向到默认页面,该页面显示应用程序正在初始化的消息。

我提出了这种方法,很少有人提出担忧。

  1. 理想情况下,我们不应该创建线程,因为处理线程会很困难。

我的问题是为什么我们不能在 Web 应用程序中创建这样的线程。

如果这不好,那么最好的方法是什么?

4

2 回答 2

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(任何其他具有持久性的键/值存储也可以)。

于 2013-08-29T18:25:09.583 回答
0

通常,在 Java EE 环境中创建非托管线程是一个坏主意。您将在非托管线程中丢失容器托管事务、用户上下文和更多 Java EE 概念。此外,如果您的线程处理不合适,非托管线程可能会在关闭时阻塞容器。

您使用的是哪个 Java EE 版本?也许您可以使用Servlet 3.0 的异步功能

或者调用异步 EJB 在启动时执行繁重的工作(@PostConstruct)。然后,该调用将在其工作完成时设置一个标志。

于 2013-08-29T14:55:53.780 回答