Подтвердить что ты не робот

@ApplicationScoped CDI bean и @PersistenceContext - это безопасно?

Можно ли сделать что-то подобное с CDI?

@Named
@ApplicationScoped
public class DAO {

   @PersistenceContext
   private EntityManager entityManager;

}

Я понимаю, что EntityManager сам по себе не является потокобезопасным и поэтому не должен использоваться в глобальном глобальном контексте, таком как @ApplicationScoped. Однако, поскольку введенный объект с @PersistenceContext на самом деле является обертки, ориентированной на поток, вокруг базового EntityManager, делает ли это это нормально?

Я видел другие сообщения по этому вопросу, но не смог найти авторитетный ответ для этого конкретного случая. Например:

Java CDI @PersistenceContext и безопасность потоков

Похоже, что он безопасен для использования с @Stateless, например, но я не уверен, работает ли это из-за способа @Stateless или из-за чего-то собственного @PersistenceContext.

ИЗМЕНИТЬ Источником моей путаницы является то, что обертка @PersistenceContext, введенная EntityManager, кажется, знает о текущем потоке, чтобы выяснить, есть ли уже транзакция. Поэтому, возможно, я путаю нить-осведомленность с безопасностью потоков, и это две разные вещи.

4b9b3361

Ответ 1

Я уверен, что в этом случае CDI не создает контекстный прокси для менеджера сущностей. В конце концов, в какой сфере он будет? Вы можете захотеть нечто похожее на гипотетический @ThreadScoped или просто @RequestScoped, но @PersistenceContext не является аннотацией CDI, а CDI не изменяет его семантику.

Итак, что происходит здесь, это вставка "управляемая bean" платформы Java EE 6, которая аналогична инъекции диспетчера сущностей в 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;
    }

}

Внесите это в bean, где вы ранее ввели менеджера сущностей:

@Named
@ApplicationScoped
public class DAO {

   @Inject
   private EntityManagerProvider entityManagerProvider;

}

Это даст вам уникальный диспетчер объектов для каждого запроса. Вы также можете легко превратить это в метод продюсера, поэтому вам не нужно вызывать getEntityManager() у введенного поставщика.