как добавить entity listener программируемый в Hibernate JPA
Я использую spring, hibernate, jpa2. 1. следующим образом:
@Entity
@EntityListeners(DemoListener.class)
public class Demo {
@Id
private Long id;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
}
public class DemoListener {
@PersistenceContext
private EntityManager entityManager;
@PrePersist
public void prePersist(Demo demo){
}
}
Пример хорошо работает, когда я хочу добавить больше слушателя, я должен изменить сущность Demo
, но Demo
находится в другом jar, я не хочу использовать конфигурацию XML, есть ли какой-то способ, как это:
...addListener(Demo.class, new DemoListener());
...addListener(Demo.class, new OtherDemoListener());
1 ответ:
База на hibernate-orm docs и Hibernate-tutorials:
/** * @param <T> one of {@link EventType#baseListenerInterface()} * @see org.hibernate.event.service.spi.EventListenerRegistry */ public interface JpaEventListenerRegistry<T> { /** * add listener for entity class * * @param entityClass can't be null * @param listener can't be null */ void addListener(Class<?> entityClass, T listener); } public class JpaEventListenerRegistryImpl implements JpaEventListenerRegistry<Object> { private Logger logger = LoggerFactory.getLogger(getClass()); private EventListenerRegistry eventListenerRegistry; private Map<EventType, JpaEventListenerRegistry> listeners = new HashMap<EventType, JpaEventListenerRegistry>(); public JpaEventListenerRegistryImpl(EventListenerRegistry eventListenerRegistry) { this.eventListenerRegistry = eventListenerRegistry; initDefault(); } private void initDefault() { listeners.put(EventType.PRE_INSERT, new DomainPreInsertEventListener()); listeners.put(EventType.POST_INSERT, new DomainPostInsertEventListener()); for (Map.Entry<EventType, JpaEventListenerRegistry> entry : listeners.entrySet()) { eventListenerRegistry.appendListeners(entry.getKey(), entry.getValue()); } } @SuppressWarnings("unchecked") public void addListener(Class<?> entityClass, Object listener) { logger.info("add listener {} for entity {}", listener, entityClass.getName()); for (EventType eventType : EventType.values()) { Class<?> listenerInterface = eventType.baseListenerInterface(); if (listenerInterface.isAssignableFrom(listener.getClass())) { JpaEventListenerRegistry registry = listeners.get(eventType); if (registry == null) { logger.warn("the event type {} for listener {} is not supported", eventType, listener); } else { registry.addListener(entityClass, listener); } } } } public static class Abstract<T> implements JpaEventListenerRegistry<T> { private Logger logger = LoggerFactory.getLogger(getClass()); private Map<Class<?>, List<T>> listeners = new HashMap<Class<?>, List<T>>(); public void addListener(Class<?> entityClass, T listener) { logger.info("add listener {} for entity {}", listener, entityClass.getName()); List<T> listeners = this.listeners.get(entityClass); if (listeners == null) { listeners = new ArrayList<T>(); this.listeners.put(entityClass, listeners); } listeners.add(listener); } List<T> findListener(Class<?> entityClass) { for (Map.Entry<Class<?>, List<T>> entry : listeners.entrySet()) { if (entry.getKey().isAssignableFrom(entityClass)) { return entry.getValue(); } } return null; } } public static class DomainPreInsertEventListener extends Abstract<PreInsertEventListener> implements PreInsertEventListener { public boolean onPreInsert(PreInsertEvent event) { return onPreInsert(event, findListener(event.getEntity().getClass())); } private boolean onPreInsert(PreInsertEvent event, List<PreInsertEventListener> listeners) { if (listeners == null) return false; for (PreInsertEventListener listener : listeners) { if (listener.onPreInsert(event)) return true; } return false; } } public static class DomainPostInsertEventListener extends Abstract<PostInsertEventListener> implements PostInsertEventListener { public void onPostInsert(PostInsertEvent event) { onPostInsert(event, findListener(event.getEntity().getClass())); } private void onPostInsert(PostInsertEvent event, List<PostInsertEventListener> listeners) { if (listeners == null) return; for (PostInsertEventListener listener : listeners) { listener.onPostInsert(event); } } public boolean requiresPostCommitHanding(EntityPersister persister) { return false; } } } public class EntityManagerIllustrationTest extends TestCase { private EntityManagerFactory entityManagerFactory; @Override protected void setUp() throws Exception { // like discussed with regards to SessionFactory, an EntityManagerFactory is set up once for an application // IMPORTANT: notice how the name here matches the name we gave the persistence-unit in persistence.xml! entityManagerFactory = Persistence.createEntityManagerFactory("org.hibernate.tutorial.jpa"); SessionFactoryImplementor sessionFactory = entityManagerFactory.unwrap(SessionFactoryImplementor.class); EventListenerRegistry eventListenerRegistry = sessionFactory.getServiceRegistry().getService(EventListenerRegistry.class); JpaEventListenerRegistryImpl jpaEventListenerRegistry = new JpaEventListenerRegistryImpl(eventListenerRegistry); jpaEventListenerRegistry.addListener(EventListener.class, new JpaEventListener()); } private static class JpaEventListener implements PreInsertEventListener, PostInsertEventListener { public boolean onPreInsert(PreInsertEvent event) { Event entity = (Event) event.getEntity(); System.out.println("onPreInsert:" + entity); return false; } public void onPostInsert(PostInsertEvent event) { Event entity = (Event) event.getEntity(); System.out.println("onPostInsert:" + entity); } public boolean requiresPostCommitHanding(EntityPersister persister) { return false; } } @Override protected void tearDown() throws Exception { entityManagerFactory.close(); } public void testBasicUsage() { // create a couple of events... EntityManager entityManager = entityManagerFactory.createEntityManager(); entityManager.getTransaction().begin(); entityManager.persist(new Event("Our very first event!", new Date())); // entityManager.persist(new Event("A follow up event", new Date())); entityManager.getTransaction().commit(); entityManager.close(); // now lets pull events from the database and list them entityManager = entityManagerFactory.createEntityManager(); entityManager.getTransaction().begin(); List<Event> result = entityManager.createQuery("from Event", Event.class).getResultList(); for (Event event : result) { System.out.println("Event (" + event.getDate() + ") : " + event.getTitle()); } entityManager.getTransaction().commit(); entityManager.close(); } }