3.8. Intégration à un serveur d'application J2EE

Hibernate possède les points suivants d'intégration à l'infrastructure J2EE :

En fonction de votre environnement, vous devrez peut être mettre l'option de configuration hibernate.connection.aggressive_release à vrai si le serveur d'application affiche des exceptions de type "connection containment".

3.8.1. Configuration de la stratégie transactionnelle

L'API de la Session Hibernate est indépendante de tout système de démarcation des transactions qui peut être présent dans votre architecture. Si vous laissez Hibernate utiliser l'API JDBC directement via un pool de connexion, vous devrez commencer et terminer vos transactions en utilisant l'API JDBC. Si votre application tourne à l'intérieur d'un serveur d'application J2EE, vous voudrez peut être utiliser les transactions gérées par les beans (BMT) et appeller l'API JTA et UserTransaction lorsque cela est nécessaire.

Pour conserver votre code portable entre ces deux environnements (et d'autres éventuels) nous vous recommandons d'utiliser l'API optionnelle Transaction d'Hibernate, qui va encapsuler et masquer le système de transaction sous-jacent. Pour cela, vous devez préciser une classe de fabrique d'instances de Transaction en positionnant la propriété hibernate.transaction.factory_class.

Il existe trois choix standards (fournis) :

net.sf.hibernate.transaction.JDBCTransactionFactory

délègue aux transactions de la base de données (JDBC). Valeur par défaut.

org.hibernate.transaction.JTATransactionFactory

délègue à CMT si une transaction existante est sous ce contexte (ex: méthode d'un EJB session), sinon une nouvelle transaction est entamée et une transaction gérée par le bean est utilisée.

org.hibernate.transaction.CMTTransactionFactory

délègue à aux transactions JTA gérées par le conteneur

Vous pouvez également définir votre propre stratégie transactionnelle (pour un service de transaction CORBA par exemple).

Certaines fonctionnalités d'Hibernate (i.e. le cache de second niveau, l'association automatique des Session à JTA, etc.) nécessitent l'accès au TransactionManager JTA dans un environnement "managé". Dans un serveur d'application, vous devez indiquer comment Hibernate peut obtenir une référence vers le TransactionManager, car J2EE ne fournit pas un seul mécanisme standard.

Tableau 3.10. TransactionManagers JTA

Fabrique de Transaction Serveur d'application
org.hibernate.transaction.JBossTransactionManagerLookup JBoss
org.hibernate.transaction.WeblogicTransactionManagerLookup Weblogic
org.hibernate.transaction.WebSphereTransactionManagerLookup WebSphere
org.hibernate.transaction.WebSphereExtendedJTATransactionLookup WebSphere 6
org.hibernate.transaction.OrionTransactionManagerLookup Orion
org.hibernate.transaction.ResinTransactionManagerLookup Resin
org.hibernate.transaction.JOTMTransactionManagerLookup JOTM
org.hibernate.transaction.JOnASTransactionManagerLookup JOnAS
org.hibernate.transaction.JRun4TransactionManagerLookup JRun4
org.hibernate.transaction.BESTransactionManagerLookup Borland ES

3.8.2. SessionFactory associée au JNDI

Une SessionFactory Hibernate associée au JNDI peut simplifier l'accès à la fabrique et donc la création de nouvelles Sessions. Notez que cela n'est pas lié avec les Datasource associées au JNDI, elles utilisent juste le même registre.

Si vous désirez associer la SessionFactory à un nom JNDI, spécifiez un nom (ex. java:hibernate/SessionFactory) en utilisant la propriété hibernate.session_factory_name. Si cette propriété est omise, la SessionFactory ne sera pas associée au JNDI (c'est particulièrement pratique dans les environnements ayant une implémentation de JNDI en lecture seule, comme c'est le cas pour Tomcat).

Lorsqu'il associe la SessionFactory au JNDI, Hibernate utilisera les valeurs de hibernate.jndi.url, hibernate.jndi.class pour instancier un contexte d'initialisation. S'ils ne sont pas spécifiés, l'InitialContext par défaut sera utilisé.

Hibernate va automatiquement placer la SessionFactory dans JNDI après avoir appelé cfg.buildSessionFactory(). Cela signifie que vous devez avoir cet appel dans un code de démarrage (ou dans une classe utilitaire) dans votre application sauf si vous utilisez le déploiement JMX avec le service HibernateService présenté plus tard dans ce document.

Si vous utilisez SessionFactory JNDI, un EJB ou n'importe quelle autre classe peut obtenir la SessionFactory en utilisant un lookup JNDI.

Nous recommandons que vous liiez la SessionFactory à JNDI dans les environnements managés et que vous utilisiez un singleton static si ce n'est pas le cas. Pour isoler votre application de ces détails, nous vous recommandons aussi de masquer le code de lookup actuel pour une SessionFactory dans une classe helper, comme HibernateUtil.getSessionFactory(). Notez qu'une telle classe est aussi un moyen efficace de démarrer Hibernatevoir chapitre 1.

3.8.3. Association automatique de la Session à JTA

Le moyen le plus simple de gérer les Sessions et transactions est la gestion automatique de session "courante" offerte par Hibernate. Voir détail à Section 2.5, « Sessions Contextuelles ». En utilisant le contexte de session "jta" session context, s'il n'y a pas de Session associée à la transaction JTA courante, une session sera démarrée et associée à la transaction JTA courante la première fois que vous appelez sessionFactory.getCurrentSession(). Les Sessions obtenue via getCurrentSession() dans une contexte "jta" seront automatiquement flushées avant la validation de la transaction, fermées une fois la transaction complétée, et libéreront les connexions JDBC de manière aggressive après chaque statement. Ceci permet aux Sessions d'être gérées par le cycle de vie de la transaction JTA à la quelle est sont associées, laissant le code de l'utilisateur propre de ce type de gestion. Votre code peut soit utiliser JTA de manière programmatique via UserTransaction, ou (ce qui est recommandé pour la portabilité du code) utiliser l'API Transaction API pour marquer les limites. Si vous exécutez sous un conteneur EJB, la démarcation déclarative des transactions avec CMT est recommandée.

3.8.4. Déploiement JMX

La ligne cfg.buildSessionFactory() doit toujours être exécutée quelque part pour avoir une SessionFactory dans JNDI. Vous pouvez faire cela dans un bloc d'initialisation static (comme celui qui se trouve dans la classe HibernateUtil) ou vous pouvez déployer Hibernate en temps que service managé.

Hibernate est distribué avec org.hibernate.jmx.HibernateService pour le déploiement sur un serveur d'application avec le support de JMX comme JBoss AS. Le déploiement et la configuration sont spécifiques à chaque vendeur. Voici un fichier jboss-service.xml d'exemple pour JBoss 4.0.x:

<?xml version="1.0"?>
<server>

<mbean code="org.hibernate.jmx.HibernateService"
    name="jboss.jca:service=HibernateFactory,name=HibernateFactory">

    <!-- Required services -->
    <depends>jboss.jca:service=RARDeployer</depends>
    <depends>jboss.jca:service=LocalTxCM,name=HsqlDS</depends>

    <!-- Bind the Hibernate service to JNDI -->
    <attribute name="JndiName">java:/hibernate/SessionFactory</attribute>

    <!-- Datasource settings -->
    <attribute name="Datasource">java:HsqlDS</attribute>
    <attribute name="Dialect">org.hibernate.dialect.HSQLDialect</attribute>

    <!-- Transaction integration -->
    <attribute name="TransactionStrategy">
        org.hibernate.transaction.JTATransactionFactory</attribute>
    <attribute name="TransactionManagerLookupStrategy">
        org.hibernate.transaction.JBossTransactionManagerLookup</attribute>
    <attribute name="FlushBeforeCompletionEnabled">true</attribute>
    <attribute name="AutoCloseSessionEnabled">true</attribute>

    <!-- Fetching options -->
    <attribute name="MaximumFetchDepth">5</attribute>

    <!-- Second-level caching -->
    <attribute name="SecondLevelCacheEnabled">true</attribute>
    <attribute name="CacheProviderClass">org.hibernate.cache.EhCacheProvider</attribute>
    <attribute name="QueryCacheEnabled">true</attribute>

    <!-- Logging -->
    <attribute name="ShowSqlEnabled">true</attribute>

    <!-- Mapping files -->
    <attribute name="MapResources">auction/Item.hbm.xml,auction/Category.hbm.xml</attribute>

</mbean>

</server>

Ce fichier est déployé dans un répertoire META-INF et est packagé dans un fichier JAR avec l'extension .sar (service archive). Vous devez également packager Hibernate, les librairies tierces requises, vos classes persistantes compilées et vos fichiers de mapping dans la même archive. Vos beans entreprise (souvent des EJBs session) peuvent rester dans leur propre fichier JAR mais vous pouvez inclure ce fichier JAR dans le jar principal du service pour avoir une seule unité déployable à chaud. Vous pouvez consulter la documentation de JBoss AS pour plus d'information sur les services JMX et le déploiement des EJBs.