它是安全的做这样的事情与CDI?
@Named
@ApplicationScoped
public class DAO {
@PersistenceContext
private EntityManager entityManager;
}
我明白EntityManager
本身不是线程安全的,因此不应该在这样一个共同的全球环境中使用@ApplicationScoped
。 但是,由于被注入的对象@PersistenceContext
实际上是一个潜在的周围线程感知包装EntityManager
,这是否让这个行吗?
我已经看到了这个问题的其他职位,但一直没能找出一个权威的答案这个特定的情况下。 例如:
Java的CDI @PersistenceContext和线程安全
它看起来像它的安全与使用@Stateless
,例如-但我不知道这是因为方式@Stateless
作品,或者是因为一些固有的@PersistenceContext
本身。
编辑我混乱的根源在于@PersistenceContext
注入EntityManager
包装似乎也意识到当前线程,为了弄清楚是否有正在进行的交易。 因此,也许我混淆线程意识与线程安全,他们是两个不同的东西。
我敢肯定,在这种情况下CDI不会创建实体管理器上下文代理。 毕竟,它会在什么范围? 您可能需要一个类似于一个假想的@ThreadScoped
或只是@RequestScoped
,但@PersistenceContext
不是CDI注释和CDI不会修改它的语义。
因此,这里发生了什么是Java EE 6平台“托管bean”注入,这类似于在Servlet中注入实体管理器。 这两种情况下给你的是不是线程安全的,直接使用实例。
它看起来像它的安全与@Stateless使用,例如 - 但我不知道这是因为@Stateless作品的,或者是因为一些固有的@PersistenceContext自己的方式。
这是由于的方式@Stateless
工作。 每一个请求(调用)的方法无状态bean是由容器路由到一个唯一的实例。 该容器保证没有两个线程都在同一个bean曾经被激活。
随着CDI可以通过封装在请求实体管理范围的bean,并注入到这一点的应用范围的一个让每个请求类似的效果:
import javax.enterprise.context.RequestScoped;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
@RequestScoped
public class EntityManagerProvider {
@PersistenceContext
private EntityManager entityManager;
public EntityManager getEntityManager() {
return entityManager;
}
}
注入到您先前注入实体管理器豆这样的:
@Named
@ApplicationScoped
public class DAO {
@Inject
private EntityManagerProvider entityManagerProvider;
}
这会给你每次请求一个独特的实体管理器。 您可以轻松地把它变成一个生产者方法为好,这样你就不必调用getEntityManager()
在注射提供商。