在Java EE应用程序部署后执行任务

20

我有一个Java EE应用程序,应在部署后启动与外部系统的同步过程。

我该如何实现这个需求?


您真的想让进程从“部署”(即新EAR)开始,还是从启动(JEE服务器重新启动)开始? - Matteo
1
看一下这个解决方案,它可能是你需要的。 - loulou
我只是想确保同步过程会在部署后或服务器启动后开始。 - Oliver
4个回答

28

以下列出了在JavaEE应用程序中获取生命周期回调的几种流行方法。

创建一个javax.servlet.ServletContextListener实现

如果您有一个.web组件到您的.ear文件(嵌入式.war)或您的部署是单独的.war文件,您可以将一个 ServletContextListener 添加到您的web.xml并在服务器启动或关闭时获得回调。

例子:

package com.stackoverflow.question

import javax.servlet.ServletContextListener;
import javax.servlet.ServletContextEvent;

public class MyServletContextListener implements ServletContextListener{

   @Override
   public void contextInitialized(ServletContextEvent contextEvent) {
        /* Do Startup stuff. */
   }

   @Override
   public void contextDestroyed(ServletContextEvent contextEvent) {
        /* Do Shutdown stuff. */
   }

}

然后将这个配置添加到您的web.xml部署描述符中。
$WAR_ROOT/WEB-INF/web.xml

<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://java.sun.com/xml/ns/javaee">

    <listener>
      <listener-class>com.stackoverflow.question.MyServletContextListener</listener-class>
    </listener>

</web-app>

创建一个 EJB 3.1 的 @Startup Bean

使用 EJB 3.1 单例方法,从服务器获取启动和关闭回调。

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.ejb.Startup;
import javax.ejb.Singleton;

@Singleton
@Startup
public class LifecycleBean {

  @PostConstruct
  public void init() {
    /* Startup stuff here. */
  }

  @PreDestroy
  public void destroy() {
    /* Shutdown stuff here */
  }

}

1
那个包是错的。为什么没有 @WebListener?你是在为 OP 搜索答案吗? - BalusC
@BalusC 我不知道 @WebListener,我一直使用 web.xml 配置 ServletContextListeners。我不太确定它是如何工作的,所以我不想给出错误的建议。另外,我哪个包搞错了? - Dev
@BalusC 找到了。我不知道怎么错过了那个错误的包名。谢谢你指出来。 - Dev
<listener> 需要闭合标签 </listener> - Marc Bouvier

9
我测试了使用 @Startup@PostConstruct 注解的建议解决方案。结果发现,Glassfish在所有使用@PostConstruct注解的方法完成之前不会完成应用程序的部署。因此,在我的情况下,部署需要几分钟甚至一个小时。
但是我找到了一种实现我想要的不同方式。最好的解决方案似乎是一个定时器回调方法,在执行后取消其计时器。
@Stateless
public class SynchronisationService {
    @Schedule(hour = "*", minute = "*", persistent = false)
    protected void init(Timer timer)
    {
       doTheSync();

       timer.cancel();
    }
 }

使用非持久化计时器可以在应用服务器重新启动时重新创建计时器。

为什么你使用了无状态Bean而不是单例模式?我正在使用单例模式,它能运行但是在工作运行期间每一分钟都会出现时间重试,并抛出错误。 - NimChimpsky

5
您可以使用@Startup@PostConstruct注释在应用程序启动时执行任务。

1
根据我的经验,@PostConstruct注解应该仅用于需要几分钟完成的初始化任务。与外部系统的同步需要更长时间。因此,同步不应绑定到bean本身的初始化上。 - Oliver

0

使用ServletContextListener或在启动时初始化的Servlet。当然,如果您在集群中有多个应用程序部署,并且只想运行此过程一次,则这变得更加困难。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接