Jakarta ee EJB调度器服务无状态与单例

Jakarta ee EJB调度器服务无状态与单例,jakarta-ee,scheduler,ejb-3.1,Jakarta Ee,Scheduler,Ejb 3.1,我的应用程序有一个调度程序,需要每10秒运行一次,才能从数据库中提取新记录。我已经通过以下方式实现了ejb调度器服务,该服务运行良好。没有client to hit()方法,它应仅作为计划程序运行 单例方法 @Singleton @Startup public class DataFetcherService { @Schedule(second="*/10", minute="*", hour="*", persistent=true) public void hit() {

我的应用程序有一个调度程序,需要每10秒运行一次,才能从数据库中提取新记录。我已经通过以下方式实现了ejb调度器服务,该服务运行良好。没有client to hit()方法,它应仅作为计划程序运行

单例方法

@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
    }
}
@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
    }
}
如果我用@stateless替换@singleton,有什么区别吗?请建议

更新:无状态方法

@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
    }
}
@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
    }
}

我不完全清楚你的问题,但如果我理解正确,你可以用两种方法来解决这个问题。如果愿意,您可以将
EntityManager
插入
@Singleton
中,然后将与JPA相关的业务逻辑放入
@Singleton
中的方法中,该方法将由hit()调用,其他客户机将调用任何其他方法。在这种情况下,客户端访问和计划访问都将以同步方式进行。性能不是很好,但我想这就是你的架构

另一种选择是将这个数据获取业务逻辑放在自己的
@Stateless
EJB中,并将该EJB注入到您的
@Singleton
中,从而实现更松散的耦合。然后,您的
@Singleton
可以从hit()和任何其他方法调用此EJB上的方法。因为
@Singleton
的默认容器管理并发是
@Lock(LockType.WRITE)
,所以您将有效地序列化注入EJB的所有访问(只要所有访问都通过Singleton)。这种设计使事情更加松散耦合,但增加了涉及的类的数量,并添加了一个无状态EJB,该EJB将被池化,从而使用更多的资源。这是一些权衡

如果您选择第1个选项,并且您需要对所述业务逻辑进行非同步执行,那么您需要使用
@Stateless
EJB来重构

还有一件事要考虑。如果您决定使用
@Singleton
唯一的方法,那么如果您需要让它的一个方法调用另一个方法,您必须小心。在这种情况下,您将无法使用CMC(容器管理的并发性),而是需要使用
ConcurrenyManagementType.Bean
并自己处理同步

根据OP的新评论更新:

@您好-如果您将
@Singleton
替换为
@Stateless
,您还将失去
@Startup
,因为它仅在
@Singleton
bean上可用。这可能对您有影响,也可能对您没有影响,尽管这对
@Schedule
方法没有任何影响,因为它将在应用程序部署时看到并“设置”

您需要调用
fetchData()使用bean的代理,从注入的
SessionContext
资源或通过自注入获取。您现在的操作方式是在调用调度方法时启动容器,包括TX。有时这很重要,有时不重要,但可能会导致微妙的错误,这就是为什么通常最好确保您通过代理访问“本地”方法


最后,如果对
@Singleton
使用上述方法,则需要切换到bean管理的并发,因为容器不会以可重入方式处理对
@Lock(LockType.WRITE)
方法的这种方法访问,并且会给您一个错误(至少这是我在Glasfish上的JavaEE6中看到的行为)。

在计划服务中使用@Singleton和@Stateless有几个区别:

  • 如果您使用@Stateless,那么执行带注释方法的bean实例将是完全自治的,不能被应用程序的其余部分引用。容器将在部署时创建计时器,并根据计划调用回调。如果您尝试注入此bean的实例,则您将获得其他副本(无运行计划)

  • 如果您使用@singletonbean,那么您可以注入它并更改它的状态,这可能会影响计时器回调的行为


@Lock(LockType.WRITE)
.NBW,我已经更新了帖子。你能看一下吗?我有两个问题:上述方法(集装箱管理类型)有问题吗?我们可以用无状态注释替换singleton吗?@Hello-更新了我对您的问题的回答并进行了更改。我在EJB3.2/Java EE 7中遇到了一个编译时错误,带有字符串文字。@Tiny-很公平,我已经更新了我的帖子来解决这个问题。谢谢。