Comment configurer correctement un EntityManager dans une application jersey / hk2?
j'ai une application jersey-2 / hk2 qui utilise la persistance JPA. Le EntityManager
est lié au démarrage comme ceci
public MyApplication() {
// ...
register(new AbstractBinder() {
@Override
public void configure() {
bindFactory(EmFactory.class)
.to(EntityManager.class)
.in(RequestScoped.class);
}
});
}
, la classe d'usine étant
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();
}
}
}
cela fonctionne mais ensuite pour chaque requête je reçois un avertissement dans les logs au sujet d'un EntityManager étant déjà enregistré:
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'est-ce que je fais de mal? Quelle est la bonne façon d'initialiser un EntityManager dans un jersey-2 / hk2 application?
1 réponses
une option est de créer une nouvelle EntityManagerFactory
dans le EMFactory
(qui est dans une requête scope), vous pouvez créer une usine singleton pour le EntityManagerFactory
, puis juste injecter le EntityManagerFactory
dans le 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;
}
...
}
N'a pas testé cette implémentation exacte, mais ça devrait ressembler à ça. J'ai utilisé ce modèle avant.
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);
}
});
mise à JOUR
une chose à noter à propos de l'exemple ci-dessus est qu'il ne nettoie pas les ressources, c.-à-d. le EntityManager
devrait être proche; il ne se fermera pas lui-même. Il y a une méthode dispose
dans la classe Factory
que nous devons passer outre, mais d'après mon expérience, ce N'est jamais appelé par Jersey.
ce que nous pouvons faire est d'ajouter le EntityManager
à 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 cette façon le EntityManager
est assuré pour être fermé à la fin de la demande.