为了开发目的,我在单例bean中实现了一个虚拟数据存储库。单例bean的构造函数创建虚拟数据,并且有检索,插入,更新和删除虚拟数据的方法。
当我对它进行单元测试时,检查插入和更新的对象是否可以在插入和更新的相同状态下检索(即逐个属性),单元测试通过。在这个测试中,我只是将单例bean实例化为常规对象,即通过其构造函数。当我实际使用单例bean时,将它注入@RequestScoped
JSF支持bean(将bean创建留给EJB容器),在更新数据项并随后通过其ID检索它之后,更新似乎丢失了并使用旧的字段值。因此,bean在容器内外的行为不同。然而,构造函数中有一个System.out.println
只执行一次,所以在这种意义上它似乎只实例化了一次。
单例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只被实例化一次,但它会以某种方式在方法调用之间恢复其状态。
答案 0 :(得分:1)
单例bean中的公共方法不应声明为final
。我已将它们声明为final,因为我是从构造函数中调用它们来使用初始虚拟数据集填充集合。当未被声明为final时,NetBeans正确地警告过从基类构造函数中调用可以在子类中重写的方法。当没有声明为final时,我只是通过从构造函数中调用singleton bean自己的公共方法来获得NullPointerException
。因此,非最终方法必须存在某种代理。
我仍然不确定为什么出现,好像最终方法的结果被缓存(即获得陈旧的结果)。但我有我的答案,所以我很开心。