Intercepteurs Hibernate

Intercepteurs Hibernate

1. Vue d'ensemble

Dans cette discussion, nous examinerons différentes manières d'intercepter des opérations dans l'implémentation de mappage relationnel abstrait deHibernate’s.

2. Définition des intercepteurs Hibernate

L'intercepteur Hibernate est une interface qui nous permet de réagir à certains événements dans Hibernate.

Ces intercepteurs sont enregistrés en tant que rappels et fournissent des liens de communication entre la session et l’application d’Hibernate. Avec un tel rappel, une application peut intercepter les opérations principales d'Hibernate telles quesave, update, delete, etc.

Il existe deux manières de définir les intercepteurs:

  1. Interface deimplementing the org.hibernate.Interceptor

  2. Classeextending the org.hibernate.EmptyInterceptor

2.1. Implémentation d'une interfaceInterceptor

Implementing org.hibernate.Interceptor requires implementing about 14 accompanying methods. Ces méthodes incluentonLoad, onSave, onDelete, findDirty, et quelques autres.

Il est également important de s'assurer que toute classe qui implémente l'interface Interceptor est sérialisable (implements java.io.Serializable).

Un exemple typique ressemblerait à ceci:

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;
    }

}

S'il n'y a pas d'exigences particulières, la classeextending the EmptyInterceptor et ne remplaçant que les méthodes requises est fortement recommandée.

2.2. Extension deEmptyInterceptor

L'extension de la classeorg.hibernate.EmptyInterceptor fournit un moyen plus simple de définir un intercepteur. We now only need to override the methods that relate to the operation we want to intercept.

Par exemple, nous pouvons définir nosCustomInterceptor comme:

public class CustomInterceptor extends EmptyInterceptor {
}

Et si nous devons intercepter les opérations de sauvegarde des données avant qu'elles ne soient exécutées, nous devons remplacer la méthodeonSave:

@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);
}

Remarquez comment cette implémentation imprime simplement l'entité - s'il s'agit d'unUser.

Bien qu'il soit possible de renvoyer une valeur detrue oufalse, il est conseillé d'autoriser la propagation de l'événementonSave en appelantsuper.onSave().

Another use-case would be providing an audit trail for database interactions. Nous pouvons utiliser la méthodeonFlushDirty() pour savoir quand une entité change.

Pour l'objetUser, nous pouvons décider de mettre à jour sa propriété de datelastModified chaque fois que des modifications se produisent sur des entités de typeUser.

Ceci peut être réalisé avec:

@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);
}

D'autres événements tels quedelete etload (initialisation d'objet) peuvent être interceptés en implémentant respectivement les méthodesonDelete etonLoad correspondantes.

3. Enregistrement deInterceptors

Un intercepteur Hibernate peut être enregistré en tant queSession-scoped ouSessionFactory-scoped.

3.1. Session-scoped Interceptor

Un intercepteur de portéeSession est lié à une session spécifique. Il est créé lorsque la session est définie ou ouverte comme:

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

Dans ce qui précède, nous avons explicitement enregistré un intercepteur avec une session de veille prolongée particulière.

3.2. SessionFactoryà portée sInterceptor

Un intercepteurSessionFactory-scoped est enregistré avant de construire unSessionFactory. Cela se fait généralement via la méthodeapplyInterceptor sur une instanceSessionFactoryBuilder:

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

Il est important de noter qu’un intercepteur à portéeSessionFactory-era appliqué à toutes les sessions. Par conséquent, nous devons veiller à ne pas stocker d’état spécifique à une session car cet intercepteur sera utilisé simultanément par différentes sessions.

Pour un comportement spécifique à une session, il est recommandé d'ouvrir explicitement une session avec un autre intercepteur comme indiqué précédemment.

Pour les intercepteurs à portéeSessionFactory, nous devons naturellement nous assurer qu'ils sont thread-safe. Ceci peut être réalisé en spécifiant un contexte de session dans le fichier de propriétés:

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

Ou en ajoutant ceci à notre fichier de configuration XML:


    org.hibernate.context.internal.ThreadLocalSessionContext

En outre, pour garantir la sérialisation, les intercepteurs à portéeSessionFactory doivent implémenter la méthodereadResolve de l'interfaceSerializable.

4. Conclusion

Nous avons vu comment définir et enregistrer les intercepteurs Hibernate en tant queSession-scoped ouSessionFactory-scoped. Dans les deux cas, nous devons nous assurer que les intercepteurs sont sérialisables, surtout si nous voulons une session sérialisable.

Hibernate Events et les rappels JPA sont d'autres alternatives aux intercepteurs.

Et, comme toujours, vous pouvez consulter lessource code over on Github complets.