我有一个EJB计时器,它在一天的特定时间每天运行两次。 我希望能够通过网页请求手动触发此计时器,但我不知道如何做到这一点。
我不希望在Web的线程中运行,因为计时器可能是一个很长的进程,所以最好让它在后台运行EJB进程。我可以在EJB中获取TimerService
,但我无法从Web上下文访问它。
我必须使用计时器而不是线程。 我正在使用JBoss 7和WebSphere 8.5。
答案 0 :(得分:0)
我们有3个选项可以在部署应用程序时自动创建计时器。
initializeTimer
在contextInitialized
网络的ServletContextListener
方法中
模块。load-on-startup
属性
servlet在Web模块出现时自动启动servlet
启动。以下示例说明如何在部署应用程序时使用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()