如何在JavaEE中实现持续运行的进程

时间:2013-04-07 07:55:24

标签: java java-ee ejb jboss7.x

您如何建议在JavaEE中实现以下内容:

  1. 我需要在app服务器(我正在考虑有状态会话bean)中有一个后台进程,它会持续监视“某些东西”,如果某些条件适用,它会对数据库进行操作。

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

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

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

4 个答案:

答案 0 :(得分:7)

您可以将无状态会话或单例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

答案 1 :(得分:1)

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

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

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

  2. 有一个运行EJB的应用程序服务器。 JBoss是一个不错的选择,Glassfish是另一个不错的选择。通过安装JBoss和JBoss Tools插件,您将能够快速构建和运行基本应用程序。
  3. 编辑:一个完整​​的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
    
    }
    

    我希望这会有所帮助。

答案 2 :(得分:1)

答案 3 :(得分:1)

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

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

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

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

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