5

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

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

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

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

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

4

4 回答 4

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
   }
}

另请参阅:在 Oracle JavaEE 教程上使用计时器服务

于 2013-04-07T08:46:04.550 回答
1

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

}

我希望这有帮助。

于 2013-04-07T08:20:15.397 回答
1

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

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

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

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

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

于 2013-04-07T11:28:18.453 回答