如何在部署Web应用程序时在启动时运行耗时的任务

时间:2013-08-29 14:16:57

标签: multithreading java-ee webserver

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

  1. 查询数据库以获取项目列表
  2. 为每个项目进行rmi调用
  3. 收听JMS队列/主题上的数据
  4. 构建缓存
  5. 此初始化过程位于启动代码中。所有这些都需要花费大量时间,因为部署需要花费大量时间或服务器启动时间正在增加。

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

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

    我提出了这种方法,并提出了一些问题。

    1. 我们不应该理想地创建一个线程,因为处理线程会很困难。
    2. 我的问题是为什么我们不能在Web应用程序中创建这样的线程。

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

2 个答案:

答案 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 (任何其他具有持久性的键/值商店也会这样做。)