【问题标题】:How to implement a constantly running process in JavaEE如何在 JavaEE 中实现一个不断运行的进程
【发布时间】:2013-04-07 07:55:24
【问题描述】:

您建议如何在 JavaEE 中实现以下功能:

  1. 我需要在应用服务器中有一个后台进程(我在想一个有状态的会话 bean),它不断地监视“某事”,如果某些条件适用,它会对数据库进行操作。

  2. 最重要的是,它必须由各种客户端远程操作。

因此,基本上,我需要一个能够持续运行、保持其状态并为许多远程客户端的方法调用开放的进程。

由于我是 JavaEE 新手,所以我有点困惑使用哪种方法/“技术”。我们将不胜感激。

【问题讨论】:

    标签: java jakarta-ee ejb jboss7.x


    【解决方案1】:

    您可以将无状态会话或单例 bean 与 EJB 计时器和计时器服务结合使用。 bean 将成为远程客户端用来控制后台进程的接口。计时器服务会定期回调 bean 上的方法来验证条件。计时器由 EJB 容器自动持久化,因此当您的 bean 客户端断开连接时,它们将完成其工作。

    这是一个草图:

    @Singleton
    ...
    public TimerMangerbean implements TimerManager {
    
       @Resource
       private TimerService timerService;
    
       public void startMonitoring() {
          //start in 5 sec and timeout every 10 minutes
          Timer timer = timerService.createTimer(5000, 60000, "MyTimer");
       }
    
       public void stopMonitoring() {
          Collection<Timer> timers = timerService.getTimers();
          for(Timer timer : timers) {
             //look for your timer
             if("MyTimer".equals(timer.getInfo())) {
                timer.cancel();break;
             }
          }
       }
    
       //called every 10 minutes
       @Timeout
       public void onTimeout() {
          //verify the condition and do your processing
       }
    }
    

    另请参阅:Using the timer service on Oracle JavaEE tutorial

    【讨论】:

    • 感谢您的回答,但我希望有一种更基本的方法,您建议的解决方案看起来更像是一个技巧。是否有另一种更基本的解决方案适用于更广泛的连续过程及其操作问题。
    • 不,不是骗局,TimerServiceTimer(s) 是 JEE 中控制和执行重复流程的标准方式。它们不会将您与特定类型的问题联系起来。您认为这种方法有哪些限制?正如你所说,这个问题似乎是一个完美的匹配。
    • +1 Java EE 中不直接支持长时间运行的后台进程。相反,他们支持周期性计时器,TimerService.
    【解决方案2】:
    【解决方案3】:

    正如您自己所说,您有两个要求:1) 定期执行一些后台作业,以及 2) 响应客户端请求。

    对于 1),您可以使用 TimerService 或使用 ServletContextListener 生成线程。第二个不完全符合,但有效。如果您使用计时器,您可以创建一个周期性计时器(正如@dcernahoschi 所指出的那样),或者一个重新安排自身的独特计时器:

    @Timeout
    public void onTimeout() {
         //do something
         // create a new timer
     }
    

    如果您的定期计时器每 10 秒触发一次,并且您处理最后一个表单的时间超过 10 秒,那么您可能会遇到问题。如果处理时间不固定,那么拥有一个可以自行重新安排的计时器会更好。

    对于 2) 您可以使用无状态或 staefull EJB,这正是他们的目的。

    【讨论】:

      【解决方案4】:

      Java EE 是解决方案。您需要按照以下步骤操作:

      1. 构建一个 Java EE 应用程序,一个包含 EJB 的 jar:

        1.1 你需要一个 IDE:Eclipse Juno 是我的最爱, 1.2 网络上有很多tuto。搜索EJB3,你会发现,

      2. 有一个应用程序服务器来运行您的 EJB。 JBoss 是一个不错的选择,Glassfish 是另一个不错的选择。安装 JBoss 和适用于 Eclipse 的 JBoss Tools 插件后,您将能够快速构建和运行基本应用程序。

      编辑:一个完整​​的 Timer EJB 类(如果需要,可以自动重新加载)

      package clouderial.saas.commons.utils;
      
      import java.util.Map;
      
      import javax.annotation.PreDestroy;
      import javax.annotation.Resource;
      import javax.ejb.ScheduleExpression;
      import javax.ejb.Timeout;
      import javax.ejb.Timer;
      import javax.ejb.TimerConfig;
      import javax.ejb.TimerService;
      import javax.inject.Inject;
      
      import jmcnet.libcommun.exception.ExceptionTechnique;
      import jmcnet.libcommun.utilit.mail.MailException;
      
      import org.apache.commons.configuration.event.ConfigurationEvent;
      import org.apache.commons.configuration.event.ConfigurationListener;
      import org.slf4j.Logger;
      import org.slf4j.LoggerFactory;
      
      import clouderial.saas.commons.email.EmailSender;
      import clouderial.saas.commons.jpamongo.JPAMongoBasePersistenceContextAccessor;
      
      /**
       * A base class for a periodic process
       * @author jmc
       *
       */
      public abstract class PeriodicProcessBase extends JPAMongoBasePersistenceContextAccessor implements ConfigurationListener {
          private static Logger log = LoggerFactory.getLogger(PeriodicProcessBase.class);
      
          @Resource
          private TimerService timerService;
      
          @Inject
          protected GlobalConfiguration _config;
      
          @Inject
          protected EmailSender _emailSender;
      
          private Timer _timer=null;
      
          private String _processName=null;
          private Logger _log = null;
      
          protected void initTimer(String processName, Logger log) {
              if (processName != null) _processName = processName;
              if (log != null) _log = log;
      
              String second    = _config.getString("timer."+_processName+".second","0");
              String minute    = _config.getString("timer."+_processName+".minute","0");
              String hour      = _config.getString("timer."+_processName+".hours","4");
              String dayOfWeek = _config.getString("timer."+_processName+".dayOfWeek","*");
      
              ScheduleExpression scheduleExp =
                      new ScheduleExpression().second(second).minute(minute).hour(hour).dayOfWeek(dayOfWeek);
      
              cancelTimer();
              if (timerService != null) { 
                  _timer = timerService.createCalendarTimer(scheduleExp, new TimerConfig(_processName, false));
                  _log.info("{} : timer programmed for '{}'h, '{}'m, '{}'s for days '{}'.", _processName, hour, minute, second, dayOfWeek);
              }
              else _log.error("{} : no timer programmed because timerService is not initialized. (Normal during tests)", _processName);
      
              // Listen to change
              _config.addModificationListener(this); // on timer modification, configurationChanged is called
          }
      
          @PreDestroy
          private void cancelTimer() {
              if (_log != null) _log.info("Stopping timer for '{}'", _processName);
              if (_timer != null) _timer.cancel();
              _timer = null;
          }
      
          @Override
          public void configurationChanged(ConfigurationEvent event) {
              if (_log != null) _log.info("Configuration have change. Reloading config for ProcessBilling.");
              _config.removeModificationListener(this);
              initTimer(null, null);
          }
      
          @Timeout
          private void run(Timer timer) {
              runProcess(timer);
          }
      
          /**
           * The entry point for runner the process. Must be overriden by super class
           * @param timer
           */
          protected abstract void runProcess(Timer timer); // do the job here
      
      }
      

      我希望这会有所帮助。

      【讨论】:

      • 是的,我实际上使用 JBoss 工具运行 JBoss 7.1.1 和 Eclipse Juno。问题是要使用哪个特定的 API,以便进程不断运行,例如,一旦客户端断开连接 (SLSB) 就不会被销毁。
      • OK 让我们检查上面的完整响应以在 JBoss 7.1.1 中实现 TimerEJB
      猜你喜欢
      • 2023-03-10
      • 1970-01-01
      • 2012-07-31
      • 2021-10-15
      • 2017-10-23
      • 1970-01-01
      • 2012-09-18
      • 2016-03-08
      • 2013-10-21
      相关资源
      最近更新 更多