java单例EJB在EJB容器外部的行为应该相同,但不相同
出于开发目的,我在单例bean中实现了一个虚拟数据存储库。SingletonBean的构造函数创建虚拟数据,并且有检索、插入、更新和删除虚拟数据的方法
当我对其进行单元测试时,检查正在插入和更新的对象是否可以在它们插入和更新的相同状态下检索(即,逐个属性相等),单元测试通过。在这个测试中,我只是将单例bean实例化为一个常规对象,即通过它的构造函数。当我通过将单例bean注入@RequestScoped
JSF支持bean(将bean创建留给EJB容器)来实际使用单例bean时,在更新数据项并随后通过其ID检索它之后,更新似乎丢失了,并且使用了旧的字段值。因此,bean在容器内外的行为并不相同。然而,构造函数中有一个System.out.println
只执行一次,因此从这个意义上讲,它似乎只实例化一次
singleton bean的结构如下:
@ConcurrencyManagement(ConcurrencyManagementType.BEAN)
@Singleton
@LocalBean
public class DummyDataRepository {
public DummyDataRepository() {
// Initial dummy data created here.
}
public final synchronized Foo findFooById(int id) {
// Retreive a Foo by ID.
// ...
}
public final synchronized void addFoo(Foo foo) {
// Add the Foo.
// ...
}
public final synchronized void updateFoo(Foo foo) {
// Find the existing Foo by foo.id and replace it with foo.
// ...
}
public final synchronized void deleteFoo(int id) {
// Find the existing Foo by id and delete it.
// ...
}
}
似乎没有任何理由认为bean应该在EJB容器内外产生不同的结果。它不使用任何外部资源。同步是bean管理的(因此在这方面应该是相同的)。bean被声明为singleton。但在容器中,它似乎充当了一个无状态会话bean
我用的是GlassFish 3.1.2.2
更新:
我将bean从@javax.ejb.Singleton
更改为@javax.enterprise.context.ApplicationScoped
(并在需要时通过@javax.inject.Inject
而不是@javax.ejb.EJB
注入它),现在它可以按预期工作。然而,两者之间应该没有区别。它指出,尽管单例EJB只被实例化一次,但它会在方法调用之间以某种方式恢复其状态
# 1 楼答案
单例bean中的公共方法不应声明为
final
。我之所以将它们声明为final,是因为我从构造函数中调用它们,用初始的伪数据集填充集合。当未声明为final时,NetBeans正确地警告不要从基类构造函数调用可能在子类中被重写的方法。当没有声明为final时,我只需从构造函数中调用单例bean自己的公共方法,就得到了一个NullPointerException
。因此,对于非最终方法,必须有某种代理我仍然不确定为什么会出现,好像缓存了最终方法的结果(即获取过时的结果)。但我有我的答案,所以我很高兴