我的应用程序有一个调度程序,需要每10秒运行一次,从数据库中提取新记录。我已经按照运行正常的this guide实现了ejb调度程序服务。没有客户端来命中()方法,它应该仅作为调度程序运行。
仅限单身人士,
@Singleton
@Startup
public class DataFetcherService {
@Schedule(second="*/10", minute="*", hour="*", persistent=true)
public void hit() {
//do some stuff
fetchData();
}
public void fetchData() {
//Fetch new records from the database through DAO objects
}
}
如果我用@stateless替换@singleton会有什么不同吗?请建议
更新:无状态方法,
@Singleton
@Startup
public class DataFetcherService {
@EJB
DataFetcherBean dataFetcherBean;
@Schedule(second="*/10", minute="*", hour="*", persistent=true)
public void hit() {
dataFetcherBean.fetchData();
}
}
@Stateless
public class DataFetcherBean {
public void fetchData() {
//Fetch new records from the database through DAO objects
}
}
答案 0 :(得分:3)
我对你的问题并不完全清楚,但如果我理解你的话,你可以采取这两种方式。如果您愿意,可以在EntityManager
中注入@Singleton
,然后将您的JPA相关商业逻辑放入@Singleton
中可由hit()调用的方法以及任何其他方法这些其他客户会打电话。在这种情况下,客户端访问和调度访问都将以同步方式发生。性能不佳但我猜这是你的架构。
另一个选择是通过将此数据获取业务逻辑放在其自己的@Stateless
EJB中并将该EJB注入到您的@Singleton
中来更松散地耦合。然后,您的@Singleton
可以从hit()和任何其他方法调用此EJB上的方法。因为@Singleton
的默认容器管理并发性是@Lock(LockType.WRITE)
,所以您将有效地序列化注入的EJB的所有访问权限(只要它都通过单例)。这种设计使得事物更松散地耦合,但增加了所涉及的类的数量,并添加了一个无状态的EJB,这将使用更多的资源进行池化。这些是一些权衡。
如果您选择第一个选项并且您需要非同步执行所述biz逻辑,则需要使用@Stateless
EJB重构内容。
还有一件事需要考虑。如果你决定采用@Singleton
唯一的方法,你必须要小心,如果你需要让它的一个方法调用另一个方法。在这种情况下,您将无法使用CMC(容器管理的并发),而是您将使用ConcurrenyManagementType.Bean
并自己处理同步。
根据OP的新评论更新:
@Hello - 如果您将@Singleton
替换为@Stateless
,您也会将@Startup
作为@Singleton
唯一可用的@Schedule
。这对你来说可能有问题,也可能没有关系,尽管它对fetchData();
方法没有任何影响,因为在应用程序部署时会看到并“设置”。
您需要使用bean的代理调用SessionContext
,或者从注入的@Singleton
资源或通过自注入获取。你现在这样做的方法就是调用容器,包括在调用调度方法时启动容器的TX。有时这个问题有时它不会导致细微的错误,这就是为什么通常最好通过代理访问'本地'方法。
最后,如果对@Lock(LockType.WRITE)
使用上述方法,则需要切换到bean托管并发,因为容器不会处理这种类型的方法访问props
方法进入时尚并会给你一个错误(至少这是我在Glasfish的JavaEE6中看到的行为)。
答案 1 :(得分:2)
在您的预定服务中使用@Singleton和@Stateless之间存在一些差异:
如果使用@Stateless,那么执行带注释的方法的bean实例将完全自治,并且不能被应用程序的其余部分引用。容器将在部署时创建计时器,并根据计划调用回调。如果您尝试注入此bean的实例,那么您将获得它的另一个副本(没有正在运行的计划)。
如果使用@Singleton bean,则可以注入它并更改其状态,可能会影响计时器回调的行为。