EJB @Schedule 问题
我需要在我的网络应用程序中安排一项任务。该任务需要使用在部署期间初始化的 Servlet
的成员字段。我使用了EJB @Schedule
。然而,当任务被触发时,成员字段为空。我猜原因在于我必须向 servlet 添加 @Stateless 注释才能使 @Schedule 工作,并且我的 Servlet 需要保留它的状态确实如此吗?
如果是,我怎样才能以简单有效的方式启动我的任务?使用 GlassFish 3
这是我的代码的快照
@Stateless // <-- Wrong ??
public class myServlet extends GenericServlet {
private MemberField myMemberField = new MemberField();
@Override
public void init() throws ServletException {
myMemberField.initialize();
}
@Schedule(dayOfWeek = "Mon-Fri", hour = "21", minute = "59", second = "55")
public void myTask() {
System.out.println(myMemberField.toString());
}
// other stuff
}
编辑
Java EE 教程说:
企业 Bean 容器的计时器服务使您能够为除有状态会话 Bean 之外的所有类型的企业 Bean 安排定时通知
所以我的结论是,这种方式不适合在 Servlet 中使用。
编辑2
servlet对于启动CometD Bayeux服务是必需的:请参阅此处为什么。 MyMemberField 代表包装类的唯一实例,该类负责与经纪商 API 的交互(这是一个交易应用程序)。此包装类实例在所有会话和用户中必须是唯一的。我在 Servlet 的 init()
上初始化它。 该包装类向代理发送请求并接收异步应答。也许最好在 Bayeux 配置器之外定义此类,但我不知道如何定义它。作为一个servlet?作为托管 Bean? 最重要的是,我需要使用调度程序才能将计划的消息发送到代理。因此,计划任务应该知道代理的包装类实例。
I need to schedule a task in my web application. The task needs to use a member field of the Servlet
that is initialized during deployment. I have used the EJB @Schedule
. However when the task is fired, the member field is null. I guess that the cause lies in the fact that I had to add the @Stateless
annotation to the servlet in order to make the @Schedule
work, and my Servlet needs to preserve its state indeed?
If yes, how can I fire my task in a simple and efficace way? Using GlassFish 3
Here is a snapshot of my code
@Stateless // <-- Wrong ??
public class myServlet extends GenericServlet {
private MemberField myMemberField = new MemberField();
@Override
public void init() throws ServletException {
myMemberField.initialize();
}
@Schedule(dayOfWeek = "Mon-Fri", hour = "21", minute = "59", second = "55")
public void myTask() {
System.out.println(myMemberField.toString());
}
// other stuff
}
EDIT
The Java EE Tutorial says:
The timer service of the enterprise bean container enables you to schedule timed notifications for all types of enterprise beans except for stateful session beans
So my conclusion is that this way is not suitable for being used in a Servlet
.
EDIT 2
The servlet is necessary for starting the CometD Bayeux service: see here why. MyMemberField represents the unique instance of a wrapper class that cares of the interaction with the API of the broker (this is a trading application). This wrapper class instance must be unique across all sessions and users. I initialize it on init()
of the Servlet.
This wrapper class sends requests to the broker and receives asynchronous answers. Maybe it's better to define this class outside the Bayeux configurator, but I don't know how to define it. As a servlet? As a Managed Bean?
On top on it, I need to work with a scheduler in order to send scheduled messages to the broker. So, the scheduled task should be aware of the broker's wrapper class instance.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
当您为 Servlet 添加 @Stateless 注释时,您就创建了两个 JavaEE 组件:
当servlet处理初始请求时,servlet中的实例字段被初始化。当@Schedule运行时,EJB的实例字段被初始化为不同的东西。
我对如何解决问题的建议取决于实例字段中存储的数据。它是应用程序范围的初始化数据吗?如果是这样,那么我将使用初始化实例数据的 @PostConstruct 创建一个单独的 @Singleton 类,然后将 @Schedule 移动到该类。它是依赖于请求的数据吗?如果是这样,那么我将使用 TimerService.createCalendarTimer 并通过 TimerConfig 的 info 参数将数据传递给计时器方法。
顺便说一句,如果您不需要保证计时器在应用程序停止或 JVM 崩溃时能够“赶上”,那么您可能需要考虑使用非持久计时器。
When you annotate a servlet @Stateless, you have created two JavaEE components:
When the servlet handles the initial request, the instance field in the servlet is initialized. When the @Schedule runs, the instance field of the EJB is initialized to something different.
My recommendation for how to resolve the problem depends on what data is stored in the instance field. Is it application-wide initialization data? If so, then I would create a separate @Singleton class with an @PostConstruct that initializes the instance data, and then move the @Schedule to that class. Is it request-dependent data? If so, then I would use TimerService.createCalendarTimer and pass the data to the timer method via the info parameter of the TimerConfig.
As an aside, if you don't need a guarantee that the timer will "catch up" while the application is stopped or if the JVM crashes, then you might want to consider using a non-persistent timer.
@bkail 一语中的。您正在混合 Servlet 和 EJB 概念。将它们分成两个单独的类。
如果出于某种原因您希望能够在每个 servlet 请求上访问
foo
,那么您应该将其作为@EJB
注入到您的 servlet 中。@bkail hit the nail on the head. You're mixing the Servlet and EJB concepts. Split them into two separate classes.
If you want to be able to access
foo
on every servlet request for some reason, then you should inject it as@EJB
in your servlet.