Рубрики
Без рубрики

Спящие перехватчики

Краткое и практическое руководство по созданию перехватчиков гибернации.

Автор оригинала: baeldung.

1. Обзор

В этом обсуждении мы рассмотрим различные способы перехвата операций в рамках Hibernate реализация абстрактного реляционного отображения.

2. Определение перехватчиков Гибернации

Перехватчик Hibernate-это интерфейс, который позволяет нам реагировать на определенные события в Hibernate.

Эти перехватчики регистрируются как обратные вызовы и обеспечивают связь между сеансом Hibernate и приложением. С помощью такого обратного вызова приложение может перехватывать основные операции гибернации, такие как сохранение, обновление, удаление и т. Д.

Существует два способа определения перехватчиков:

  1. реализация org.hibernate.Перехватчик интерфейс
  2. расширение org.hibernate.EmptyInterceptor класс

2.1. Реализация интерфейса перехватчика

Реализация org.hibernate.Перехватчик требует реализации около 14 сопутствующих методов . Эти методы включают onLoad, OnSave, OnDelete, find Dirty, и еще несколько.

Также важно убедиться, что любой класс, реализующий интерфейс перехватчика, сериализуем ( реализует java.io.Serializable ).

Типичный пример будет выглядеть так:

public class CustomInterceptorImpl implements Interceptor, Serializable {

    @Override
    public boolean onLoad(Object entity, Serializable id, 
      Object[] state, String[] propertyNames, Type[] types) 
      throws CallbackException {
        // ...
        return false;
    }

    // ...

    @Override
    public String onPrepareStatement(String sql) {
        // ...   
        return sql;
    }

}

Если особых требований нет, настоятельно рекомендуется расширить класс EmptyInterceptor и переопределить только необходимые методы.

2.2. Расширение EmptyInterceptor

Расширение org.hibernate.Класс EmptyInterceptor обеспечивает более простой способ определения перехватчика. Теперь нам нужно только переопределить методы, относящиеся к операции, которую мы хотим перехватить.

Например, мы можем определить наш Пользовательский перехватчик как:

public class CustomInterceptor extends EmptyInterceptor {
}

И если нам нужно перехватить операции сохранения данных до их выполнения, нам нужно переопределить метод OnSave :

@Override
public boolean onSave(Object entity, Serializable id, 
  Object[] state, String[] propertyNames, Type[] types) {
    
    if (entity instanceof User) {
        logger.info(((User) entity).toString());
    }
    return super.onSave(entity, id, state, propertyNames, types);
}

Обратите внимание, как эта реализация просто выводит сущность – если это Пользователь .

Хотя можно вернуть значение true или false , рекомендуется разрешить распространение события unsafe , вызвав super.OnSave() .

Другим вариантом использования было бы предоставление контрольного журнала для взаимодействия с базой данных. Мы можем использовать метод onFlushDirty () , чтобы узнать, когда изменяется сущность.

Для объекта User мы можем решить обновить его свойство last Modified date всякий раз, когда происходят изменения в сущностях типа User .

Этого можно достичь с помощью:

@Override
public boolean onFlushDirty(Object entity, Serializable id, 
  Object[] currentState, Object [] previousState, 
  String[] propertyNames, Type[] types) {
    
    if (entity instanceof User) {
        ((User) entity).setLastModified(new Date());
        logger.info(((User) entity).toString());
    }
    return super.onFlushDirty(entity, id, currentState, 
      previousState, propertyNames, types);
}

Другие события, такие как delete и load (инициализация объекта), могут быть перехвачены путем реализации соответствующих методов OnDelete и onLoad соответственно.

3. Регистрация перехватчиков

Перехватчик гибернации может быть зарегистрирован как Session -scoped или SessionFactory-scoped .

3.1. Перехватчик с областью действия сеанса

Перехватчик с областью действия Session связан с конкретным сеансом. Он создается, когда сеанс определяется или открывается как:

public static Session getSessionWithInterceptor(Interceptor interceptor) 
  throws IOException {
    return getSessionFactory().withOptions()
      .interceptor(interceptor).openSession();
}

В приведенном выше примере мы явно зарегистрировали перехватчик с определенным сеансом гибернации.

3.2. Перехватчик с областью действия SessionFactory

A SessionFactory – перехватчик с областью действия регистрируется перед созданием SessionFactory. Обычно это делается с помощью метода apply Interceptor на экземпляре SessionFactoryBuilder :

ServiceRegistry serviceRegistry = configureServiceRegistry();
SessionFactory sessionFactory = getSessionFactoryBuilder(serviceRegistry)
  .applyInterceptor(new CustomInterceptor())
  .build();

Важно отметить, что перехватчик SessionFactory- с областью действия будет применяться ко всем сеансам. Следовательно, мы должны быть осторожны, чтобы не хранить конкретное состояние сеанса, так как этот перехватчик будет использоваться разными сеансами одновременно.

Для конкретного поведения сеанса рекомендуется явно открыть сеанс с другим перехватчиком, как показано ранее.

Для перехватчиков SessionFactory -scoped нам, естественно, необходимо убедиться, что он потокобезопасен. Это может быть достигнуто путем указания контекста сеанса в файле свойств:

hibernate.current_session_context_class=org.hibernate.context.internal.ThreadLocalSessionContext

Или добавив это в наш файл конфигурации XML:


    org.hibernate.context.internal.ThreadLocalSessionContext

Кроме того, для обеспечения сериализуемости перехватчики SessionFactory с областью действия должны реализовать метод readResolve интерфейса Serializable .

4. Заключение

Мы видели, как определить и зарегистрировать перехватчики гибернации либо как Session -scoped, либо как SessionFactory -scoped. В любом случае мы должны убедиться, что перехватчики сериализуемы, особенно если мы хотим сериализуемый сеанс.

Другие альтернативы перехватчикам включают события гибернации и обратные вызовы JPA.

И, как всегда, вы можете проверить полный исходный код на Github .