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?