@ApplicationScoped CDI豆和@PersistenceContext - 这是安

2019-08-04 02:50发布

它是安全的做这样的事情与CDI?

@Named
@ApplicationScoped
public class DAO {

   @PersistenceContext
   private EntityManager entityManager;

}

我明白EntityManager本身不是线程安全的,因此不应该在这样一个共同的全球环境中使用@ApplicationScoped 。 但是,由于被注入的对象@PersistenceContext实际上是一个潜在的周围线程感知包装EntityManager ,这是否让这个行吗?

我已经看到了这个问题的其他职位,但一直没能找出一个权威的答案这个特定的情况下。 例如:

Java的CDI @PersistenceContext和线程安全

它看起来像它的安全与使用@Stateless ,例如-但我不知道这是因为方式@Stateless作品,或者是因为一些固有的@PersistenceContext本身。

编辑我混乱的根源在于@PersistenceContext注入EntityManager包装似乎也意识到当前线程,为了弄清楚是否有正在进行的交易。 因此,也许我混淆线程意识与线程安全,他们是两个不同的东西。

Answer 1:

我敢肯定,在这种情况下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()在注射提供商。



文章来源: @ApplicationScoped CDI bean and @PersistenceContext - is this safe?