Ответ 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()
у введенного поставщика.