java jpa dependency-injection jersey-2.0 hk2

java - ¿Cómo configuro correctamente un EntityManager en una aplicación jersey/hk2?



jpa dependency-injection (1)

Una opción es, en lugar de crear una nueva EntityManagerFactory en EMFactory (que se encuentra en un ámbito de solicitud), podría crear una fábrica de singleton para EntityManagerFactory , luego simplemente inyectar EntityManagerFactory en EMFactory .

public class EMFFactory implements Factory<EntityManagerFactory> { private final EntityManagerFactory emf; public EMFFactory (){ emf = Persistence.createEntityManagerFactory(persistenceUnit); } public EntityManagerFactory provide() { return emf; } ... } public class EMFactory implements Factory<EntityManager> { private final EntityManager em; @Inject public EMFactory (EntityManagerFactory emf){ em = emf.createEntityManager(); } public EntityManager provide() { return em; } ... }

No he probado esta implementación exacta, pero debería verse así. He usado este patrón antes.

register(new AbstractBinder() { @Override public void configure() { bindFactory(EMFFactory.class).to(EntityManagerFactory.class).in(Singleton.class); bindFactory(EMFactory.class).to(EntityManager.class).in(RequestScoped.class); } });

ACTUALIZAR

Una cosa a tener en cuenta sobre el ejemplo anterior es que no limpia los recursos, es decir, el EntityManager debe estar cerca; No se cerrará solo. Hay un método de dispose en la clase Factory que necesitamos anular, pero desde mi experiencia, Jersey nunca lo llama.

Lo que podemos hacer es agregar el EntityManager a un [ CloseableService ] [1]

public class EMFactory implements Factory<EntityManager> { private final EntityManagerFactory emf; private final CloseableService closeService; @Inject public EMFactory (EntityManagerFactory emf, CloseableService closeService){ this.emf = emf; this.closeService = closeService; } public EntityManager provide() { final EntityManager em = emf.createEntityManager(); this.closeService.add(new Closeable(){ @Override public void close() { em.close(); } }); return em; } ... }

De esta forma, se asegura que EntityManager se cierre al final de la solicitud.

Tengo una aplicación jersey-2 / hk2 que utiliza la persistencia JPA. EntityManager está vinculado en el inicio de esta manera

public MyApplication() { // ... register(new AbstractBinder() { @Override public void configure() { bindFactory(EmFactory.class) .to(EntityManager.class) .in(RequestScoped.class); } }); }

con la clase de fábrica siendo

public class EmFactory implements Factory<EntityManager> { private static final String PERSISTENCE_UNIT = "unit"; private EntityManagerFactory emf; private CloseableService closeableService; @Inject public EmFactory(@Named(PERSISTENCE_UNIT) String persistenceUnit, CloseableService closeableService) { emf = Persistence.createEntityManagerFactory(persistenceUnit); this.closeableService = closeableService; } @Override public EntityManager provide() { final EntityManager entityManager = emf.createEntityManager(); closeableService.add(new Closeable() { @Override public void close() throws IOException { if(entityManager.isOpen()) { entityManager.close(); } } }); return entityManager; } @Override public void dispose(EntityManager entityManager) { if(entityManager.isOpen()) { entityManager.close(); } } }

esto funciona pero luego, para cada solicitud, recibo una advertencia en los registros sobre un EntityManager que ya está registrado:

HHH000436: Entity manager factory name (unit) is already registered. / If entity manager will be clustered or passivated, specify a unique / value for property ''hibernate.ejb.entitymanager_factory_name''

¿Qué estoy haciendo mal? ¿Cuál es la forma correcta de inicializar un EntityManager en una aplicación jersey-2 / hk2?