5.4.4.6. Entity Listeners
Entity Listeners предназначены для реакции на события жизненного цикла экземпляров сущностей на уровне Middleware. См. пример использования в сборнике рецептов.
Слушатель представляет собой класс, реализующий один или несколько интерфейсов пакета com.haulmont.cuba.core.listener
. Слушатель будет реагировать на события типов, соответствующих реализуемым интерфейсам.
- BeforeDetachEntityListener
-
Метод
onBeforeDetach()
вызывается перед отделением объекта от EntityManager при коммите транзакции.Данный слушатель можно использовать, например, для заполнения неперсистентных атрибутов сущности перед отправкой ее на клиентский уровень.
- BeforeAttachEntityListener
-
Метод
onBeforeAttach()
вызывается перед введением объекта в персистентный контекст при выполнении операцииEntityManager.merge()
.Данный слушатель можно использовать, например, для заполнения персистентных атрибутов сущности перед сохранением ее в базе данных.
- BeforeInsertEntityListener
-
Метод
onBeforeInsert()
вызывается перед выполнением вставки записи в БД. В данном методе возможны любые операции с текущимEntityManager
. - AfterInsertEntityListener
-
Метод
onAfterInsert()
вызывается после выполнения вставки записи в БД, но до коммита транзакции. В данном методе нельзя модифицировать текущий персистентный контекст, однако можно производить изменения в БД с помощью QueryRunner. - BeforeUpdateEntityListener
-
Метод
onBeforeUpdate()
вызывается перед изменением записи в БД. В данном методе возможны любые операции с текущимEntityManager
. - AfterUpdateEntityListener
-
Метод
onAfterUpdate()
вызывается после изменения записи в БД, но до коммита транзакции. В данном методе нельзя модифицировать текущий персистентный контекст, однако можно производить изменения в БД с помощьюQueryRunner
. - BeforeDeleteEntityListener
-
Метод
onBeforeDelete()
вызывается перед удалением записи из БД (или в случае мягкого удаления - перед изменением записи). В данном методе возможны любые операции с текущимEntityManager
. - AfterDeleteEntityListener
-
Метод
onAfterDelete()
вызывается после удаления записи из БД (или в случае мягкого удаления - после изменения записи), но до коммита транзакции. В данном методе нельзя модифицировать текущий персистентный контекст, однако можно производить изменения в БД с помощьюQueryRunner
.
Entity Listener должен являться управляемым бином, поэтому в нем можно использовать инжекцию:
@Component("sample_MyEntityListener")
public class MyEntityListener implements
BeforeInsertEntityListener<MyEntity>,
BeforeUpdateEntityListener<MyEntity> {
@Inject
protected Metadata metadata;
@Override
public void onBeforeInsert(MyEntity entity, EntityManager entityManager) {
Foo foo = metadata.create(Foo.class);
...
entity.setFoo(foo);
entityManager.persist(foo);
}
@Override
public void onBeforeUpdate(MyEntity entity, EntityManager entityManager) {
Foo foo = entityManager.find(Foo.class, entity.getFoo().getId());
...
}
}
Все слушатели кроме BeforeAttachEntityListener
выполняются внутри транзакции. Это значит, что если внутри слушателя выбрасывается исключение, текущая транзакция откатывается и все изменения в базе данных теряются.
Если вам необходимо выполнить некоторые действия после успешного завершения транзакции, используйте callback-интерфейс TransactionSynchronization
фреймворка Spring для того чтобы отложить выполнение до нужной фазы транзакции. Например:
package com.company.sales.service;
import com.company.sales.entity.Customer;
import com.haulmont.cuba.core.EntityManager;
import com.haulmont.cuba.core.listener.BeforeInsertEntityListener;
import com.haulmont.cuba.core.listener.BeforeUpdateEntityListener;
import org.springframework.stereotype.Component;
import org.springframework.transaction.support.TransactionSynchronizationAdapter;
import org.springframework.transaction.support.TransactionSynchronizationManager;
@Component("sales_CustomerEntityListener")
public class CustomerEntityListener implements BeforeInsertEntityListener<Customer>, BeforeUpdateEntityListener<Customer> {
@Override
public void onBeforeInsert(Customer entity, EntityManager entityManager) {
printCustomer(entity);
}
@Override
public void onBeforeUpdate(Customer entity, EntityManager entityManager) {
printCustomer(entity);
}
private void printCustomer(Customer customer) {
System.out.println("In transaction: " + customer);
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
@Override
public void afterCommit() {
System.out.println("After transaction commit: " + customer);
}
});
}
}
- Регистрация entity listeners
-
Entity Listener может быть задан двумя способами:
-
Статически - имена бинов слушателей указываются в аннотации @Listeners на классе сущности:
@Entity(...) @Table(...) @Listeners("sample_MyEntityListener") public class MyEntity extends StandardEntity { ... }
-
Динамически - имя бина слушателя передается в метод
addListener()
бинаEntityListenerManager
. Пример динамического добавления слушателя рассматривается в разделе рецептов разработки: Выполнение кода на старте приложения.
Для всех экземпляров некоторого класса сущности создается один экземпляр слушателя определенного типа, поэтому слушатель не должен иметь состояния.
Если для сущности объявлены несколько слушателей одного типа (например, аннотациями класса сущности и его предков, плюс динамически), то их вызов будет выполняться в следующем порядке:
-
Для каждого предка, начиная с самого дальнего, вызываются его динамически добавленные слушатели, затем статически назначенные.
-
После всех предков вызываются динамически добавленные слушатели данного класса, затем статически назначенные.
-