Publié par

Il y a 8 ans -

Temps de lecture 15 minutes

Spring, Hibernate, DBUnit et Surefire – Parallélisez vos tests

Les DAO (Data Access Object) ou repository des applications contiennent souvent de l’information importante sur la façon dont les données d’une base doivent être consultées. Cette information prend la forme d’une logique métier qui est encodée dans un ou plusieurs langages, souvent un langage déclaratif (SQL, HSQL, JPQL, etc.) et un langage impératif (Java, Groovy, Scala, etc.).
Tester cette logique d’accès polyglotte peut s’avérer complexe et lent car ce type de test se prète mal aux techniques classiques de mock et nécessite plutôt l’écriture de tests d’intégration qui chargent une partie du contexte réel d’exécution. Par conséquent, les tests de cette couche sont parfois délaissés, voire abandonnés.

Cet article se propose de vous montrer comment réaliser de tels tests, avec un niveau d’isolation suffisant pour la parallélisation dans un processus multithread, tout en essayant de trouver le meilleur compromis avec le temps d’exécution de chaque test. Ces tests sont présentés dans une configuration très classique utilisant Spring et JPA/Hibernate.
L’implémentation utilise une base HSQLDB et quelques bibliothèques pour faciliter l’écriture du code, en essayant de rester aussi léger que possible. Les tests sont isolés pour que vous puissiez activer l’exécution parallèle du plugin Surefire de Maven au niveau des classes de test. Vous pourrez facilement dériver l’implémentation nécessaire à isoler vos tests au niveau des méthodes si vous le souhaitez.

Introduction

Un premier réflexe est de réaliser des tests contre une base de donnée existante. L’automatisation de ces tests mène très rapidement à des problèmes de reproductibilité et d’isolation, en particulier quand les traitements testés effectuent des opérations d’écriture dans la base de données, mais également parce que la base utilisée est souvent une base de développement que les développeurs peuvent être amenés à faire évoluer de manière incontrôlée. La solution immédiate est de créer une copie du jeu de données initial et de le recharger dans la base avant chaque test. Cette problématique, et sa conséquence, la gestion des jeux de données ont amené la création d’outils tels que DBUnit.

L’utilisation d’une base de données centralisée, même si elle est spécifique aux tests, amène son propre lot de problèmes : que se passe-t-il si plusieurs développeurs jouent leurs tests en même temps ? Les uns vont insérer leur jeu de données pendant que les autres font une écriture ; les tests ne sont pas isolés. Il faut créer une base de données par développeur.

Deux options s’offrent alors, la première consiste à créer un schéma pour chacun sur le serveur. Cela amène des problèmes de latences réseaux, de charge du serveur et rend impossible le travail en cas de coupure du réseau. Il vaut mieux pencher pour la seconde option et créer une instance sur la machine de chaque développeur. Comme ce sont souvent des machines de bureautique avec des disques lents, un SGBD complet qui n’est finalement presque pas utilisé et qui consomme de précieuses ressouces est mal venu, surtout lorsqu’il faut partager ces ressources avec un IDE, un serveur d’application, … Reste la possibilité d’utiliser une base de données embarquée comme HyperHSQL (HSQLDB), H2, Derby, etc. L’instance est créée par le processus du test et détruite lorsqu’il se termine. Il reste à y charger la structure des tables et le tour est joué.

Ces tests d’intégration joués séquentiellement peuvent encore s’avérer trop lent, surtout dans le cadre d’un build complet qui joue tous les tests. Il convient alors de les paralléliser.

Structure du projet

Partons d’un projet classique utilisant Spring et JPA/Hibernate, packagé avec maven. La structure de projet prend la forme suivante :


Dans le dossier main, on retrouve les entités du modèle de données, les DAOs avec respectivement une interface et une implémentation et le descripteur de l’unité de persistance JPA.

Dans le dossier test, les tests des deux DAOs, les fichiers de configuration XML Spring, un fichier de propriétés pour hsqldb et les deux jeux de données pour les tests au format XML.

Créer les tests avec spring & dbunit

Le code d’un test

AddressDaoTest.java
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({"applicationContext-test.xml"})
@TestExecutionListeners({DependencyInjectionTestExecutionListener.class,
                         DataSetTestExecutionListener.class})
@DataSet(value = "AddressDaoTest.xml")
public class AddressDaoTest {

    @Autowired
    private AddressDao addressDao;

    @Test
    public void testFindByAddressname() {
        Address user = addressDao.findByAddress("a");
        assertNotNull(user);
    }

    @Test
    public void testFindByAbsentAddressname() {
        Address user = addressDao.findByAddress("c");
        assertNull(user);

    }

}

Ce test est exécuté avec SpringJunit4ClassRunner qui créé le contexte Spring avec les fichiers indiqués dans l’annotation @ContextConfiguration et le met en cache.

La mise en cache est un détail important pour l’exécution de plusieurs classes de tests. Si vous avez plusieurs classes de tests, déclarant exactement la même annotation @ContextConfiguration qui sont lancées dans un même processus, seule la première aura besoin d’initialiser le contexte Spring. Les suivantes pourront réutiliser le contexte économisant ainsi : le parsing de la configuration, le scan du classpath à la recherche d’annotations ainsi que les diverses phases d’initialisations des beans utilisés dans le contexte.

L’annotation @TestExecutionListener fournie par spring-test permet d’enregistrer des classes qui peuvent se brancher dans le cycle de vie d’exécution d’un test (before test class, before test method, …). L’utilité des listeners utilisés ici est précisée un peu plus bas.

La configuration

Notre contexte de test contient les éléments standards d’un contexte Spring JPA/Hibernate mais quelques points méritent d’être notés pour que nous puissions revenir dessus.

La déclaration de la datasource hsqldb
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    <property name="driverClassName" value="${ds.driver=org.hsqldb.jdbcDriver}"/>
    <property name="url" value="${ds.url=jdbc:hsqldb:mem:test}"/>
    <property name="username" value="${ds.username=sa}"/>
    <property name="password" value="${ds.password=}"/>
</bean>
La déclaration de la factory JPA/Hibernate
<bean id="jpaVendorAdapter" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
    <property name="databasePlatform" value="${hibernate.dialect}<"/>
</bean>
<bean id="emf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="dataSource" ref="dataSource"/>
    <property name="persistenceUnitName" value="pdbunit"/>
    <property name="jpaVendorAdapter" ref="jpaVendorAdapter"/>
    <property name="jpaProperties">
        <props>
            <prop key="hibernate.dialect">${hibernate.dialect}</prop>
            <prop key="hibernate.hbm2ddl.auto">${hibernate.hbm2ddl.auto=update}</prop>
        </props>
    </property>
</bean>

Les listeners

DependencyInjectionTestExecutionListener

L’utilisation de ce listener défini par l’API spring-test permet simplement d’utiliser les annotations d’injection de dépendance (@Autowired,@Resource,…) sur des éléments de la classe de test. Ainsi, dans le test de DAO vu précédemment l’instance du DAO sera injectée avant l’exécution du test.

DataSetTestExecutionListener

Ce listener est défini dans l’API spring-dbunit et permet l’utilisation de l’annotation @Dataset sur une classe ou sur une méthode de test.

Cette annotation utilise dbunit pour charger un jeu de données avant chaque test et pour le supprimer après chaque test.

Par défaut, cette annotation cherche un fichier nommé dataSet.xml dans le même package que la classe de test qui porte l’annotation. Il est possible de changer le nom du fichier, d’en charger plusieurs, bref de choisir son jeu de données.

Un premier palier

À ce stade, nous avons donc des tests qui chargent leur jeu de données dans une base mémoire avant de s’exécuter. Isolés du monde extérieur ils ne risquent pas d’échouer à cause d’un changement involontaire par une autre personne, d’une perte de connexion réseau ou d’une autre exécution de la suite de test par un second développeur.

Parallèliser les tests dans maven

En l’état actuel, les tests ne peuvent pas être exécutés en multi-thread au sein d’un même processus, ce que sait faire le plugin surefire de maven en charge de l’exécution des tests. Unitairement rapides, la contrainte de les exécuter en séquentiel empêche de profiter pleinement des processeurs multi-cores des ordinateurs modernes. Les tests ne sont utiles que si ils sont exécutés et ils ne sont exécutés que si ils sont suffisamment rapides.

Une base de donnée par thread

Ce qui fait échouer l’exécution en mode multi-thread, ce sont les collisions entre les différents jeux de données manipulés par dbunit (deux jeux de données chargés en même temps peuvent modifier le résultat de certaines requêtes), sans compter les opérations d’écritures potentielles des traitements testés. Il faudrait que chaque test dispose de sa propre base de donnée.

ThreadUniqueDriverManagerDataSource
public class ThreadUniqueDriverManagerDataSource extends
  DriverManagerDataSource {

 @Override
 public String getUrl() {
  long tId = Thread.currentThread().getId();
  return super.getUrl() + tId;
 }
}

En utilisant cette surcharge de DriverManagerDataSource comme classe d’implémentation pour votre dataSource, chaque thread accédera à sa propre base de données mémoire.

<bean id="dataSource" class="fr.xebia.jdbc.datasource.ThreadUniqueDriverManagerDataSource">
    <property name="driverClassName" value="${ds.driver=org.hsqldb.jdbcDriver}"/>
    <property name="url" value="${ds.url=jdbc:hsqldb:mem:test}"/>
    <property name="username" value="${ds.username=sa}"/>
    <property name="password" value="${ds.password=}"/>
</bean>

Il reste un problème: le contexte Spring n’est chargé et initialisé qu’une seule fois, par conséquent Hibernate ne créé la structure des tables qu’une seule fois. Si nous tentions d’exécuter nos tests, le « premier » – celui dans lequel le contexte Spring est initialisé – réussirait. Les autres échoueraient en se plaignant que les tables nécessaires à l’insertion de leur jeu de données n’existent pas.

Il est possible de forcer le runner de Spring à réinitialiser un contexte pour chaque classe de test, mais cette initialisation est coûteuse et tout ce dont nous avons besoin est de créer les tables dans la base de données, tout le reste fonctionne très bien sans réinitialisation.

Recréer la structure de la base de données dans chaque thread.

Sachant que les listeners de test sont exécutés dans l’ordre de leur déclaration, il nous faut donc un listener qui soit exécuté après la création du contexte mais avant le chargement des données et qui se charge de recréer la structure. Nous avons déjà du code capable de recréer la structure dans Hibernate, il faut donc l’exécuter à nouveau pour chaque nouvelle base. La dernière donnée est le niveau de parallélisation, le maven-surefire-plugin est capable de paralléliser aux niveaux : « classes », « methods », « both ». Il faudra adapter le listener en fonction du niveau choisi.

Dans la suite nous allons chercher à exécuter le code parallélisé au niveau « classes », notre TestListener peut donc s’exécuter « beforeTestClass ».

JpaHibernateDbSetupTestListener

Le code du listener suivant est lié à l’utilisation JPA/Hibernate. Il ne devrait pas être très difficile de dériver un listener pour d’autres solutions de persistance, du moment que l’on sait créer la structure de la base de données.

public class JpaHibernateDbSetupTestListener extends AbstractTestExecutionListener {

    @Override
    public void beforeTestClass(TestContext testContext) throws Exception {
        super.beforeTestMethod(testContext);
        Map<String, EntityManagerFactoryInfo> emfsMap = testContext.getApplicationContext().getBeansOfType(
                EntityManagerFactoryInfo.class);
        for (Map.Entry<String, EntityManagerFactoryInfo> emfByName : emfsMap.entrySet()) {
            EntityManagerFactoryInfo entityManagerFactoryInfo = emfByName.getValue();
            String puName = entityManagerFactoryInfo.getPersistenceUnitInfo().getPersistenceUnitName();
            HibernatePersistenceCacheUnit persistenceInformation = HibernatePersistenceCache.getPersistenceInformation(puName);
            SchemaExport schemaExport = new SchemaExport(persistenceInformation.getHibernateConfiguration(),
                    persistenceInformation.getSettings());
            schemaExport.execute(false, true, false, false);
        }
    }
}

Cette implémentation nécessite des modifications supplémentaires à notre environnement de test. Elle repose sur la présence d’un cache des informations de persistance (HibernatePersistenceCache) dans lequel sont stockées les informations nécessaires à la recréation du SchemaExport.

Les informations de configuration manipulées par SchemaExport ne sont normalement pas accessibles une fois l’initialisation d’Hibernate terminée. Il faut donc les capturer lors de l’initialisation et les ajouter au cache. Pour cela nous allons devoir remplacer l’adaptateur Spring org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter par une implémentation maison.

public class HibernateJpaVendorParallelAdapter extends HibernateJpaVendorAdapter {
  private final PersistenceProvider persistenceProvider = new CachingHibernatePersistence();

  @Override
  public PersistenceProvider getPersistenceProvider() {
    return this.persistenceProvider;
  }

}

Le remplacement se fait dans le fichier de définition du contexte Spring, ce qui explique l’externalisation de la définition du jpaVendorAdapter :

<bean id="jpaVendorAdapter" class="fr.xebia.test.utils.parallel.jpa.hibernate.HibernateJpaVendorParallelAdapter">
        <property name="databasePlatform" value="org.hibernate.dialect.Oracle10gDialect"/>
</bean>

La capture des informations de configuration peut alors se faire dans CachingHibernatePersistence :

public class CachingHibernatePersistence extends HibernatePersistence {

  @Override
  public EntityManagerFactory createEntityManagerFactory(String persistenceUnitName, Map overridenProperties) {
    Ejb3Configuration cfg = new Ejb3Configuration();
    Ejb3Configuration configured = cfg.configure(persistenceUnitName, overridenProperties);
    cacheConfig(persistenceUnitName, null, overridenProperties, configured);
    return configured != null ? configured.buildEntityManagerFactory() : null;
  }

  @Override
  public EntityManagerFactory createContainerEntityManagerFactory(PersistenceUnitInfo info, Map map) {
    Ejb3Configuration cfg = new Ejb3Configuration();
    Ejb3Configuration configured = cfg.configure(info, map);
    cacheConfig(info.getPersistenceUnitName(),info, map, configured);
    return configured != null ? configured.buildEntityManagerFactory() : null;
  }

  private void cacheConfig(String name, PersistenceUnitInfo info, Map map, Ejb3Configuration configured) {
    if (configured != null) {
      HibernatePersistenceCacheUnit cachedInfo = new HibernatePersistenceCacheUnit(name);
      cachedInfo.setPersistenceUnitInfo(info);
      cachedInfo.setPropertyMap(map);
      cachedInfo.setHibernateConfiguration(configured.getHibernateConfiguration());
      cachedInfo.setSettings(configured.buildSettings());
      HibernatePersistenceCache.addPersistenceInformation(cachedInfo);
    }
  }
}

HibernatePersistenceCacheUnit est un simple conteneur pour les données qui nous intéressent :

public class HibernatePersistenceCacheUnit {

    private final String name;

    private PersistenceUnitInfo persistenceUnitInfo;

    private Map<String, Object> propertyMap;

    private Configuration hibernateConfiguration;

    private Settings settings;

    private SessionFactory sessionFactory;

    //...
}

et enfin le cache lui-même est une implémentation basique utilisant une simple HashMap :

public class HibernatePersistenceCache {

  private static final Map<String, HibernatePersistenceCacheUnit> persistenceInformationMap = new HashMap<String, HibernatePersistenceCacheUnit>();

  public static void addPersistenceInformation(HibernatePersistenceCacheUnit persistenceInformation) {
    assert(persistenceInformation != null);
    assert(persistenceInformation.getName() != null);
    persistenceInformationMap.put(persistenceInformation.getName(), persistenceInformation);
  }

  public static List<HibernatePersistenceCacheUnit> getPersistenceInformations() {
    return new ArrayList<HibernatePersistenceCacheUnit>(persistenceInformationMap.values());
  }

  public static void clearPersistenceInformations() {
    persistenceInformationMap.clear();
  }

  public static HibernatePersistenceCacheUnit getPersistenceInformation(String name) {
    return persistenceInformationMap.get(name);
  }

}

Il ne reste plus qu’à déclarer le listener au bon endroit dans le test :

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({"applicationContext-test.xml"})
@TestExecutionListeners({DependencyInjectionTestExecutionListener.class, JpaHibernateDbSetupTestListener.class, DataSetTestExecutionListener.class})
@DataSet(value = "AddressDaoTest.xml")
public class AddressDaoTest {

    @Autowired
    private AddressDao addressDao;

    @Test
    public void testFindByAddressname() {
        Address user = addressDao.findByAddress("a");
        assertNotNull(user);
    }

    @Test
    public void testFindByAbsentAddressname() {
        Address user = addressDao.findByAddress("c");
        assertNull(user);

    }

}

et à activer la parallélisation des tests lors de l’exécution du plugin surefire

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-surefire-plugin</artifactId>
    <version>2.11</version>
    <configuration>
        <parallel>classes</parallel>
    </configuration>
</plugin>

Vos tests sont maintenant suffisament isolés pour que surefire puisse exécuter vos classes de tests en multi-thread.

Autres pistes de listeners

Il existe plusieurs moyens de résoudre le problème du rechargement de la structure de la base de données dans les bases créées en mémoire. Si vous disposez d’un outil de migration comme flyway, ou que votre équipe garde scrupuleusement à jour un fichier avec la totalité de la structure de données de la base, vous pouvez créer votre propre listener pour charger la base à partir de cette référence. Vous pouvez également initialiser une base de données fichier plutôt que mémoire et en créer des copies qui seront utilisées par les différents Threads.

Des bases de données et des dialectes

Utiliser une base de donnée mémoire n’est pas complètement anodin. Chaque SGBD parle son propre ‘dialecte’ de SQL, souvent un sous-ensemble auquel peut s’ajouter des extensions spécifiques de l’éditeur.
L’idée dans cet article est de maximiser les gains obtenus en testant les commandes SQL qui sont partagées entre votre SGBD de production et la base mémoire utilisée. L’utilisation de moteurs ORM comme Hibernate tends à normaliser le sous-ensemble de commandes utilisées, ce qui facilite la compatibilité pour la plupart des requêtes. Il peut néanmoins être nécessaire d’utiliser des requêtes natives pour certaines optimisations ou pour certains cas d’utilisation spécifiques. Même comme ça, les cas d’incompatibilités peuvent être réduit par l’utilisation d’une base mémoire adaptée. Recherchez la base mémoire qui a un dialecte aussi proche que possible de celui de votre moteur de production pour pouvoir tester autant de requêtes que possible.

Le code qui malgré tout restera incompatible pourra être testé dans le cadre de tests d’acceptation sur un environnement complet. Respectez la loi de Pareto en dépensant 20% d’effort pour 80% des gains, et ne modifiez pas une requête optimisée pour votre moteur de production juste pour pouvoir la tester dans un moteur de test.

Code de l’article

Vous retrouverez sur github

  • le projet de démo qui a servi de base au code de l’article
  • un projet contenant l’implémentation du listener et du cache sous forme de librairie maven.

Publié par

Publié par Jean Helou

Jean Helou est un passionné aux opinions tranchées. Il essaye régulièrement de nouvelles approches, outils, patterns et révise ses opinions en fonction. Très curieux il a expérimenté avec un grand nombre de technologies et de modèles applicatifs. Jean est convaincu que les machines sont au service de l'homme, pas l'inverse. Il essaye toujours de faire en sorte que les logiciels qu'il développe reflètent cette conviction.

Commentaire

10 réponses pour " Spring, Hibernate, DBUnit et Surefire – Parallélisez vos tests "

  1. Publié par , Il y a 8 ans

    Merci pour ce retour. Je cherchais justement un article sur ce sujet. Je vais donc pouvoir le lire en détails et faire des tests dès que possible.

    Sinon, je me pose actuellement la question comment on peut faire des tests unitaires avec des transactions (par exemple avec Spring/Hibernate et annotation @Transactional). Si tu as des idées ou des liens, je suis preneur.

  2. Publié par , Il y a 8 ans

    Par définition un test unitaire ne peut pas tester une transaction, ca devient un test d’integration non ?

  3. Publié par , Il y a 8 ans

    @Sanlaville : oui les tests présentés fonctionnent également avec @Transactionnal. Il suffit d’ajouter l’annotation sur les tests de DAO, mais le niveau d’isolation de @Transactionnal n’est malheureusement pas toujours suffisant et le temps manque parfois pour réécrire les éléments pour lesquels ce n’est pas suffisant. D’autre part la technique peut être utile pour des tests d’intégration complets qui manipulent les transactions.

    @Ugo : Sanlaville parlait d’utiliser @Transactionnal pour obtenir des tests parallélisables. dans tous les cas les tests présentés sont déjà des tests d’intégration : ils démarrent une base de données, hibernate et spring ..ça commence à faire :)

    @Jean-Michel : je préfèrerai également travailler en ruby que j’ai pratiqué sur des projets personnels. En ce moment je suis passé à scala qui permet lui aussi des dsl bien plus concis, le typage fort en plus. Mais le nombre de projets dans ces technologies en france reste faible :)

  4. Publié par , Il y a 8 ans

    Je suis de plus en plus confronté avec de la persistance et je me demande comment on peut faire du TDD sur cette couche pour ne pas avoir que des tests intégrés. En effet, le fait de faire du TDD me permet d’être plus claire sur ce que je souhaite faire dès le début et de mieux structurer mon code (cf. Single Responsability principle). De plus les tests intégrés n’ont pas que des avantages (cf. Integrated Tests are a Scam (Part 1-2-3) de J.B. Rainsberger).

    Du coup, je suis à la recherche d’informations pour faire du TDD lorsqu’on souhaite faire de la persistance qui a des impacts non seulement sur les DAO mais aussi sur les managers/services spring (car les @Transactionnal sont souvent sur eux).

  5. Publié par , Il y a 8 ans

    Bonjour,
    Est-ce que l’utilisation d’Hibernate dispense de tester les DAOs?

  6. Publié par , Il y a 8 ans

    Bonjour,

    Le but de l’article est de montrer comment tester des DAOs hibernate, la réponse prévisible est donc que, non, utiliser Hibernate ne dispense pas de tester les DAOs :)

    Les tests doivent tester le code écrit par le développeur, pas le code du framework. La requête JPQL ou HQL fait partie du code écrit par le développeur mais son comportement ne peut pas être testée indépendamment du framework qui va la traduire. L’objet des tests de DAO sera souvent de vérifier que la requête exprime bien la même chose que la requête SQL effectivement exécutée.

    Les DAOs implémentés au-dessus d’hibernate héritent souvent d’une classe abstraite qui expose les opérations de CRUD qui sont identiques pour tous les objets persistants : find, persist, merge, remove. Sur un DAO que j’implémente, je ne m’amuserai pas à tester ces méthodes héritées, cela reviendrait à tester le framework.
    Par contre pour la méthode de recherche que je vais ajouter dont la requête JPQL fait 4 lignes et comporte 5 conditions dont 2 optionnelles : oui je vais écrire un test (plusieurs en fait) et construire le ou les datasets associés. Les autres développeurs verront ainsi plus facilement l’objet de cette méthode et je sera rassuré sur le fait d’avoir bien exprimé la requête que je voulais réellement.

    Est-ce que cela répond à votre question ?

  7. Publié par , Il y a 8 ans

    Bonjour,

    Tout d’abord merci pour votre article il est bien expliqué même pour quelqu’un qui débute avec l’utilisation de ces outils.
    Cependant j’aurai une question à vous poser. J’ai bien compris que la suppression des données insérées par les jeux de données se faisait automatiquement grâce à DbUnit. Mais alors qu’en est-il des données qui seraient insérées par un test de création par exemple ?? Pour l’instant je les supprime en utilisant les méthodes adéquates dans le test de création mais j’aurais aimé savoir s’il y avait une astuce moins contraignante svp ?

    Merci d’avance.

  8. Publié par , Il y a 7 ans

    j’utilise hibernate 4.1.6.Final

    Dans JpaHibernateDbSetupTestListener
    pour la classe SchemaExport ici http://docs.jboss.org/hibernate/orm/4.1/javadocs/org/hibernate/tool/hbm2ddl/SchemaExport.html
    je n’ai pas trouvé la signature org.hibernate.tool.hbm2ddl.SchemaExport( org.hibernate.cfg.Configuration, org.hibernate.cfg.Settings)

    Dans CachingHibernatePersistence
    de même org.hibernate.cfg.Settings org.hibernate.ejb.Ejb3Configuration.buildSettings()
    ici http://docs.jboss.org/hibernate/orm/4.1/javadocs/org/hibernate/ejb/Ejb3Configuration.html

    et org.hibernate.ejb.Ejb3Configuration et org.hibernate.cfg.Configuration sont des classes déprécié ou prévu pour l’être, l’idée je pense c’est de passer par l’intermédiaire du conteneur spring directement pour afin d’avoir un EntityManagerFactory pour en récupérer les infos pour construire le cache de persistence, pour ce qui est du listener je pense d’après le javadoc c’est d’utiliser une factory(BootstrapServiceRegistry)… par contre je ne suis pas connaisseur la plomberie d’Hibernate corriger ça dans la minute, mais ça m’interresse

    Sinon un gros merci pour cette article fort fort intéressant

  9. Publié par , Il y a 7 ans

    Merci pour ce super article!!
    Par contre tout comme Abou_Imran je suis passer en Hiberante4. Va faloir que je fouille un peu pour mettre tout ca en place. Mais les pistes sont super interressantes.

  10. Publié par , Il y a 3 ans

    mrc bcp c’est vrmt intéressant

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Nous recrutons

Être un Xebian, c'est faire partie d'un groupe de passionnés ; C'est l'opportunité de travailler et de partager avec des pairs parmi les plus talentueux.