如何在 Hibernate JPA 中添加可编程的实体侦听器
Posted
技术标签:
【中文标题】如何在 Hibernate JPA 中添加可编程的实体侦听器【英文标题】:how to add entity listener programmable in Hibernate JPA 【发布时间】:2017-09-20 12:10:32 【问题描述】:我用的是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();
【讨论】:
以上是关于如何在 Hibernate JPA 中添加可编程的实体侦听器的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 Hibernate 为 Spring data JPA 的所有查找方法添加全局 where 子句?
如何在 JPA Hibernate 映射中将 GUID(不是 PK)添加到已经具有 PK(整数)的现有实体
如何强制初始化 Hibernate JPA 代理以在 JSON 调用中使用它
JPA,Hibernate:在现有工作 DTO 中添加新变量时“无法在类上找到适当的构造函数”