如何以编程方式从Thread外部启动EJB Timer

时间:2016-09-06 19:00:00

标签: java java-ee timer ejb

我有一个EJB计时器,它在一天的特定时间每天运行两次。 我希望能够通过网页请求手动触发此计时器,但我不知道如何做到这一点。

我不希望在Web的线程中运行,因为计时器可能是一个很长的进程,所以最好让它在后台运行EJB进程。我可以在EJB中获取TimerService,但我无法从Web上下文访问它。​​

我必须使用计时器而不是线程。 我正在使用JBoss 7和WebSphere 8.5。

4 个答案:

答案 0 :(得分:0)

我们有3个选项可以在部署应用程序时自动创建计时器。

  1. 通过调用EJB方法创建计时器:调用initializeTimercontextInitialized网络的ServletContextListener方法中 模块。
  2. 创建一个servlet并实现init方法来调用EJB 创建计时器的方法。设置load-on-startup属性 servlet在Web模块出现时自动启动servlet 启动。
  3. 使用J2EE容器的专有API使用Startup类。
  4. 以下示例说明如何在部署应用程序时使用ServletContextListener(选项1)自动计划计时器,如下所示:

    public class MyLifeCycleEventExample
        implements ServletContextListener
    {
        ServletContext servletContext;
    
            /* Methods from the ServletContextListener */
        public void contextInitialized(ServletContextEvent sce)
        {
            servletContext = sce.getServletContext();
                try
        {
          Context context = new InitialContext();
          TimerDemoHome timerDemoHome =
              (TimerDemoHome)PortableRemoteObject.narrow(
                  context.lookup("java:comp/env/TimerDemo"),
                  TimerDemoHome.class);
          TimerDemo timerDemo;
    
          // Use one of the create() methods below to
          // create a new instance
          timerDemo = timerDemoHome.create();
          Date firstDate= new java.util.Date();
    
          // Call any of the Remote methods below to access
          // the EJB this code does not check whether the timer
          // has already been scheduled.
          // You should check this for duplicate timers
          timerDemo.initializeTimer( firstDate, 1800000, "MyTimer" );
    
          timerDemo.getTimerInfo();
          //Cancel Timer
          //timerDemo.cancelTimer("MyTimer");
    
        }
        catch(Throwable ex)
        {
          ex.printStackTrace();
        }
    
        }
    
        public void contextDestroyed(ServletContextEvent sce)
        {
        }
    
              protected void log(String msg)
        {
              System.out.println("[" + getClass().getName() +
                                 "] " + msg);
        }
    
    }
    

    但您需要使用以下配置在Web模块的部署描述符(web.xml)中注册侦听器

    <listener>
       <listener-class>
          TimerWeb.MyLifeCycleEventExample
       </listener-class>
    </listener>
    

答案 1 :(得分:0)

你能重构和拆分EJB吗?

EjbTimer基于它的常规计划被调用。 EjbTimer向处理长时间运行进程的MdbWorker发送异步消息。

然后从网页上可以看到一个简单的servlet,它也知道如何生成EjbWorker拾取的消息(一些与EjbTimer共享的代码)。由于消息是异步的,因此Web线程立即返回。

并发长时间运行的实例可以吗?如果没有,那么您应该将MdbWorker设置为仅1个实例(在jboss / WAS配置中的某个位置)。

答案 2 :(得分:0)

向具有现有timeOut方法的EJB添加一个方法,该方法调用javax.ejb.TimerService.createSingleActionTimer(long duration, TimerConfig config)的持续时间很短(可能是10毫秒?):

@Stateless // or @Singleton
public class MyTimerEJB {

    @Resource
    private TimerService timerService;

    @Timeout
    public void existingTimeoutMethod() {
       ...
    }

    public void fireTimeoutAsynchronouslyAlmostImmediately() {
        timerService.createSingleActionTimer(10, new TimerConfig(null, false));
    }

}

然后从页面控制器中调用此方法。

编辑:@S。如果你在Java EE 6+环境中,Kadakov的解决方案会更好。

答案 3 :(得分:0)

这很容易:

import javax.ejb.Asynchronous;
import javax.ejb.Schedule;
import javax.ejb.Stateless;

/**
 *
 * @author s.kadakov
 */
@Stateless
public class TimerBean {

    @Schedule(hour = "*/12", minute = "0", second = "0")
    public void longTermJob() {
        // do something
    }

    @Asynchronous
    public void fireJob() {
        longTermJob();
    }
}

然后将TimerBean注入servlet:

@EJB
private TimerBean timerBean;

...

timerBean.fireJob()