Si vous devez réagir à des événements particuliers dans votre couche de persistance, vous pouvez aussi utiliser l'architecture d'événements d'Hibernate3. Le système d'événements peut être utilisé en supplément ou en remplacement des interceptors.
Essentiellement toutes les méthodes de l'interface Session
sont corrélées à un événement. Vous avez un LoadEvent
, un FlushEvent
, etc (consultez la DTD du fichier de configuration XML ou le paquet org.hibernate.event
pour avoir la liste complète des types d'événement définis). Quand une requête est faite à partir d'une de ces méthodes,
la Session
Hibernate génère un événement approprié et le passe au listener configuré pour ce type. Par défaut, ces listeners implémentent
le même traitement dans lequel ces méthodes aboutissent toujours. Cependant, vous êtes libre d'implémenter une version personnalisée
d'une de ces interfaces de listener (c'est-à-dire, le LoadEvent
est traité par l'implémentation de l'interface LoadEventListener
déclarée), dans quel cas leur implémentation devrait être responsable du traitement des requêtes load()
faites par la Session
.
Les listeners devraient effectivement être considérés comme des singletons ; dans le sens où ils sont partagés entre des requêtes, et donc ne devraient pas sauvegarder des états de variables d'instance.
Un listener personnalisé devrait implémenter l'interface appropriée pour l'événement qu'il veut traiter et/ou étendre une
des classes de base (ou même l'événement prêt à l'emploi utilisé par Hibernate comme ceux déclarés non-finaux à cette intention).
Les listeners personnalisés peuvent être soit inscrits par programmation à travers l'objet Configuration
, ou spécifiés la configuration XML d'Hibernate (la configuration déclarative à travers le fichier de propriétés n'est pas
supportée). Voici un exemple de listener personnalisé pour l'événement de chargement :
public class MyLoadListener implements LoadEventListener { // this is the single method defined by the LoadEventListener interface public void onLoad(LoadEvent event, LoadEventListener.LoadType loadType) throws HibernateException { if ( !MySecurity.isAuthorized( event.getEntityClassName(), event.getEntityId() ) ) { throw MySecurityException("Unauthorized access"); } } }
Vous avez aussi besoin d'une entrée de configuration disant à Hibernate d'utiliser ce listener en plus du listener par défaut :
<hibernate-configuration> <session-factory> ... <event type="load"> <listener class="com.eg.MyLoadListener"/> <listener class="org.hibernate.event.def.DefaultLoadEventListener"/> </event> </session-factory> </hibernate-configuration>
Vous pouvez aussi l'inscrire par programmation :
Configuration cfg = new Configuration(); LoadEventListener[] stack = { new MyLoadListener(), new DefaultLoadEventListener() }; cfg.EventListeners().setLoadEventListeners(stack);
Les listeners inscrits déclarativement ne peuvent pas partager d'instances. Si le même nom de classe est utilisée dans plusieurs
éléments <listener/>
, chaque référence sera une instance distincte de cette classe. Si vous avez besoin de la faculté de partager des instances
de listener entre plusieurs types de listener, vous devez utiliser l'approche d'inscription par programmation.
Pourquoi implémenter une interface et définir le type spécifique durant la configuration ? Une implémentation de listener pourrait implémenter plusieurs interfaces de listener d'événements. Avoir en plus le type défini durant l'inscription rend plus facile l'activation ou la désactivation pendant la configuration.