如何为下面这样的JPA存储库确定合适的CDI范围?
@Transactional
public class CategoryRep extends EntityRepository<Integer, Category> {
private static final long serialVersionUID = 856370976984333182L;
public List<Category> getAllCategories() {
// TODO
}
public List<Post> getAllPostsOfCategory(Integer categoryId) {
// TODO
}
@Transactional(value = TxType.REQUIRES_NEW, rollbackOn = RuntimeException.class)
public void createCategory(final String name, final String description)
throws DaoJpaException {
// TODO
}
}
我只能想到两个CDI范围:
- @SessionScope:对我来说,这似乎是最合适的范围,因为单个实例专用于活动会话
- @依赖:这也是合理的,因为这样的实例将适合于将被注入的对象的生命周期
在我看来,所有其他CDI范围都不合适:
- @ApplicationScoped:由于应用程序范围的存储库每次只创建一次,因此类似于:
entityManager.clear()
的调用将导致所有当前会话的所有实例也将分离。此外,这个单独的存储库必须处理所有传入的请求。这个范围是否适合只读存储库 - @RequestScope:我认为不需要为每个传入的请求创建一个新的存储库实例
- @ConversionScoped:转换通常在GUI层强制执行。如果我希望存储库在转换结束后消亡,我可以将其定义为
@Dependent
那么,对于这个问题,有什么已知的最佳实践吗?
描述的所有选项
- 会话范围实际上没有意义,因为您的存储库应该是无状态的,因此会话对它没有任何意义(尽管它可以解决并发问题
- 从属作用域可能是一个不错的选择,但它可能会导致内存泄漏(您永远无法确定将从内存中删除哪些从属对象)
- 会话范围也没有任何意义,它与会话范围的情况相同
所以我会选择
- 请求范围——我认为这是最好的选择,它本质上是无状态的,因此可以避免任何并发问题。也不用担心性能,在新JVM中非常非常快地创建新对象
- 应用程序范围也是一个不错的选择,但是您需要担心并发问题(多个客户端同时调用同一方法)
所以,如果我是你,我会选择请求范围存储库,这是最简单的选择,你可以通过这种方式避免所有问题。
您应该使用@ApplicationScoped。
每个请求都应使用EntityManager,而不应重复使用。
在请求时,您创建entityManager,当它完成提交或回滚时。
@Dependent将具有与其"host"相同的作用域,如果将其注入@RequestScoped,则bean将具有相同的作用。
@SessionScoped应仅用于小数据(如用户登录和权限)。