Configuration Tomcat/Spring/Hibernate

Dans nos applications, nous utilisons plusieurs conteneur Spring pour séparer les contextes. Notamment les services disponibles en REST, des couches métiers, DAO, etc... Nous nous sommes aperçu que cela posait problème pour la gestion transactionnelle au niveau des services REST. Le principal problème était que les connexions étaient ouvertes en lecture seule et donc les quelques instructions natives SQL que nous passions ne fonctionnaient pas et résultaient d'un message d'erreurs:
    Write operations are not allowed in read-only mode (FlushMode.NEVER/MANUAL): Turn your Session into FlushMode.COMMIT/AUTO or remove 'readOnly' marker from transaction definition.
Afin de palier ce problème, nous avons déclaré un filter pour chaque appel de nos services web soit précédé d'une instruction permettant de changer le contexte transactionnel d'hibernate. Pour cela, nous avons utilisé le filter OpenSessionInViewFilter que nous avons personnalisé. Il faut tout d'abord créer une classe qui va étendre le filter par défaut de Spring: CustomHibernateSessionFilter
    import org.hibernate.FlushMode;
    import org.hibernate.Session;
    import org.hibernate.SessionFactory;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.dao.DataAccessResourceFailureException;
    import org.springframework.orm.hibernate3.support.OpenSessionInViewFilter;

    public class CustomHibernateSessionFilter extends OpenSessionInViewFilter {

      private static final Logger logger = LoggerFactory.getLogger(CustomHibernateSessionFilter.class);
     
      public CustomHibernateSessionFilter() {
        super();
        logger.info("Initializing CustomHibernateSessionFilter");
      }

      protected Session getSession(SessionFactory sessionFactory)
      throws DataAccessResourceFailureException {
        logger.info("Set flush mode to AUTO");
        Session session = super.getSession(sessionFactory);
        session.setFlushMode(FlushMode.AUTO);
        return session;
      }
     
      protected void closeSession(Session session, SessionFactory factory) {
        logger.info("close session");
        session.flush();
        super.closeSession(session, factory);
      }
    }
De cette façon, à chaque récupération d'une session, le flush mode passera à AUTO et un flush sera automatiquement exécuté à la libération.
Dans le web.xml, nous déclarons ensuite le filter:
    <filter>
       <filter-name>hibernateFilterWeb</filter-name>
       <filter-class>fr.aquasys.dao.utils.CustomHibernateSessionFilter</filter-class>
    </filter>
    <filter-mapping>
       <filter-name>hibernateFilterWeb</filter-name>
       <url-pattern>/web/*</url-pattern>
    </filter-mapping>
    </filter/>

Remarque: 
Sur une configuration Tomcat6/Spring3.0/Hibernate3, nous utilisons avons différencié plusieurs contextes pour les services REST. Certains services sont diponibles via l'url /web/* comme ci-dessus et d'autres sous l'url /services/*. la balise url-pattern permet normalement de lister les url avec une syntaxe de la forme /web/*,/services/*. Or nous nous sommes aperçu que Tomcat n'arrivait pas à associer les url avec ce filter. Il a donc fallu déclarer 2 filters avec 2 url-pattern différents. A tester sur Tomcat 7...

Stéphane Barthon

Aucun commentaire:

Enregistrer un commentaire


Remarque : Seul un membre de ce blog est autorisé à enregistrer un commentaire.