5.8.4. Выполнение кода на старте приложения
Иногда бывает необходимо выполнить некоторый код сразу после старта приложения в момент, когда все механизмы гарантированно работоспособны. Для этого можно воспользоваться слушателем AppContext.Listener.
Рассмотрим следующую задачу: в проекте имеется сущность Employee
(сотрудник компании), которая связана один-к-одному с платформенной сущностью User
(пользователь системы):
Если атрибут name
сущности User
изменяется, например через стандартный экран управления пользователями, необходимо, чтобы изменялся также и атрибут name
связанной сущности Employee
. Это обычная задача для "денормализованных" данных, и решается она, как правило, с использованием entity listeners. В данном случае ситуация осложняется тем, что необходимо отслеживать изменения не проектной, а платформенной сущности User
, и добавить entity listener с помощью аннотации @Listeners невозможно. Однако, можно добавить listener динамически через бин EntityListenerManager
, и сделать это лучше всего на старте приложения.
Для этого создадим в модуле core приложения бин AppLifecycle
, имплементирующий интерфейс AppContext.Listener
, и зарегистрируем его вызовом метода AppContext.addListener()
в конструкторе объекта:
@ManagedBean("sample_AppLifecycle")
public class AppLifecycle implements AppContext.Listener {
@Inject
private EntityListenerManager entityListenerManager;
public AppLifecycle() {
AppContext.addListener(this);
}
@Override
public void applicationStarted() {
entityListenerManager.addListener(User.class, UserEntityListener.class);
}
@Override
public void applicationStopped() {
}
public static class UserEntityListener implements BeforeUpdateEntityListener<User> {
@Override
public void onBeforeUpdate(User user) {
Persistence persistence = AppBeans.get(Persistence.class);
if (persistence.getTools().getDirtyFields(user).contains("name")) {
EntityManager em = persistence.getEntityManager();
TypedQuery<Employee> query = em.createQuery(
"select e from sample$Employee e where e.user.id = ?1", Employee.class);
query.setParameter(1, user.getId());
Employee employee = query.getFirstResult();
if (employee != null) {
employee.setName(user.getName());
}
}
}
}
}
В результате сразу после старта блока Middleware будет вызван метод applicationStarted()
данного бина. В этом методе в качестве entity listener сущности User
регистрируется внутренний класс UserEntityListener
.
Метод onBeforeUpdate()
класс UserEntityListener
будет вызываться перед каждым сохранением изменений экземпляров User
в базу данных. В методе проверяется, есть ли атрибут name
среди измененных, и если да, загружается связанный экземпляр Employee
, и в нем устанавливается это же значение name
.