Java 如何从线程外部以编程方式启动EJB计时器

Java 如何从线程外部以编程方式启动EJB计时器,java,jakarta-ee,timer,ejb,Java,Jakarta Ee,Timer,Ejb,我有一个EJB计时器,每天在一天中的特定时间运行两次。 我希望能够通过网页请求手动启动此计时器,但我不知道如何实现 我不想让它在Web线程中运行,因为计时器可能是一个很长的进程,所以最好让它在后台的EJB进程中运行。我可以在EJB中获得TimerService,但我不能从web上下文访问它 我必须使用计时器,而不是线程。 我正在使用JBoss 7和WebSphere 8.5。我们有3个选项可以在部署应用程序时自动创建计时器 通过调用EJB方法创建计时器:Invokeinitializetime

我有一个EJB计时器,每天在一天中的特定时间运行两次。 我希望能够通过网页请求手动启动此计时器,但我不知道如何实现

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

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

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

  • 通过调用EJB方法创建计时器:Invoke
    initializetime
    在web的
    ServletContextListener
    contextInitialized
    方法中 模块
  • 创建一个servlet并实现init方法来调用EJB 方法创建计时器。设置启动时加载的
    属性
    servlet,用于在web模块运行时自动启动servlet
    开始
  • 使用J2EE容器的专有API使用启动类
  • 下面是一个示例,当应用程序按如下方式部署时,如何使用
    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>
    
    
    TimerWeb.MyLifeCycleEventExample
    
    我们有3个选项可以在部署应用程序时自动创建计时器

  • 通过调用EJB方法创建计时器:Invoke
    initializetime
    在web的
    ServletContextListener
    contextInitialized
    方法中 模块
  • 创建一个servlet并实现init方法来调用EJB 方法创建计时器。设置启动时加载的
    属性
    servlet,用于在web模块运行时自动启动servlet
    开始
  • 使用J2EE容器的专有API使用启动类
  • 下面是一个示例,当应用程序按如下方式部署时,如何使用
    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>
    
    
    TimerWeb.MyLifeCycleEventExample
    
    您能重构和拆分EJB吗

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

    然后,从一个web页面可以有一个简单的servlet,它也知道如何生成消息(一些与EjbTimer共享的代码),该消息由EjbWorker获取。由于消息是异步的,web线程立即返回


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

    您能重构并拆分EJB吗

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

    然后,从一个web页面可以有一个简单的servlet,它也知道如何生成消息(一些与EjbTimer共享的代码),该消息由EjbWorker获取。由于消息是异步的,web线程立即返回


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

    向EJB添加一个方法,该方法具有您现有的超时方法,该方法调用的持续时间很短(可能是10ms?):

    然后从页面控制器调用这个方法


    编辑:@S.Kadakov的解决方案在Java EE 6+环境中更好。

    在EJB中添加一个方法,该方法具有现有的超时方法,该方法调用的持续时间很短(可能是10毫秒?):

    然后从页面控制器调用这个方法

    编辑:@S.Kadakov的解决方案在Java EE 6+环境中更好。

    非常简单:

    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()
    
    这很容易:

    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()