14 novembre 2008
Imprimer ce billet

JavaRebel – Rechargez vos classes sans redeployer

Petit sondage express : ne vous est-il jamais arrivé de constater une erreur juste après un test de déploiement vous obligeant à redéployer votre application plus rapidement que prévu ? Combien de temps votre application met-t-elle à se redéployer ? Avez-vous compté combien de fois vous l’avez redéployée lors de vos derniers développements ?

Non, nous ne présenterons ici aucune méthode magique empêchant les bugs, ni au contraire une quelconque excuse pour bâcler vos tests unitaires et vos tests d’intégration. Le but de cet article est de présenter les mécanismes dont nous disposons pour éviter les pertes de temps liées au redémarrage de vos applications. Ce billet fait suite au dernier XKE (Xebia Knowledge Exchange) du Jeudi 6 Novembre pendant lequel j’ai présenté JavaRebel.

Cet outil vous permet d’optimiser votre cycle de développement en réduisant au minimum les phases de redéploiement de vos applications via un mécanisme avancé permettant le rechargement à chaud des classes.

Ce billet se découpe de la façon suivante :

Comment fonctionne le mode Debug Java ? présentation de JPDA

Java dispose d’une API permettant de fournir des informations aux développeurs qui désirent accéder à l’état d’une machine virtuelle en cours de fonctionnement (locale ou distante). Java Debug Interface (JDI) de son petit nom, offre par exemple un moyen simple et puissant d’introspecter à distance l’ensemble des interfaces, classes, tableaux, types primitifs et instances des différents objets tels qu’ils se trouvent dans la JVM (introspection « en l’état » disponible au runtime). JDI permet également de contrôler l’exécution de la machine virtuelle en permettant l’arrêt et la relance de threads, la mise en place de points d’arrêt, etc.
Ces fonctionnalités sont d’ailleurs les alliées inconditionnelles de la plupart des développeurs : si vous ne connaissiez probablement pas le nom de l’API, vous l’aviez forcément utilisée via l’un de vos IDE préférés et leur fameux mode debug.

JDI désigne en fait la couche la plus haute de l’architecture de débogage de la plateforme Java. (JPDA) qui se découpe de la façon suivante :

  • Java Debug Interface (JDI), dont nous venons de parler
  • Java Debug Wire Protocol (JDWP), le protocole qui définit le format des requêtes et informations circulant entre le processus débogué et son débogueur. C’est une implémentation de JDI.
  • Et, Java Virtual Machine Tools Interface (JVM TI), qui définit les services minimum qu’une machine virtuelle doit fournir pour offrir ce mode debug

Le HotSwap, rechargez le corps de vos méthodes

Autre fonctionnalité indispensable de JPDA , le HotSwap. Si nous n’en avons pas parlé précédemment, c’était pour lui consacrer cette partie dédiée.

Pour mémoire, le HotSwap vous permet de modifier, au runtime, le code du corps de vos méthodes. Le nouveau code est injecté à chaud dans la JVM permettant de modifier le comportement de la méthode en question sans avoir besoin ni de redéployer, ni de redémarrer votre application, qu’elle soit locale ou distante. En résumé, vous êtes en train de déboguer votre programme, vous y trouvez une erreur, vous la corrigez dans la foulée et vous continuez votre exécution comme si de rien n’était.

Ce mécanisme, plus que séduisant, a été largement adopté par les différents IDE. Il comporte pourtant certaines limites : vos modifications seront prises en compte tant que vous ne touchez pas au squelette de vos objets. Vous pouvez toucher au corps de vos méthodes, mais pas aux propriétés ou au découpage de vos classes. En effet, si la plupart des JVM actuelles permet de recharger à chaud les modifications sur le corps des méthodes, aucune ne permet le rechargement de classes dont le squelette a changé. Notez que cette limitation est technique, rien dans les spécifications ne l’empêche. Du coup, il est tout à fait possible de voir arriver dans le futur des JVM disposant de ce genre de fonctionnalité.

Si comprendre le fonctionnement complet du mécanisme n’est pas chose facile, il est pourtant possible de deviner l’une des difficultés bridant ce mécanisme. Les états, instances et définitions des objets sont répartis dans plusieurs zones distinctes de la JVM. S’il est aisé de modifier les objets présents sur le tas, toucher à leur définition est plus complexe. Nous n’aborderons pas ce sujet en détail ici, pour plus de détails sur la gestion mémoire de la JVM, vous pouvez vous référer à cet article que j’ai écrit en début d’année.

Java Rebel, votre class loader devient dynamique

Nous pouvons pourtant dépasser les limites du HotSwap. Comme JPDA ne vous permet pas le rechargement de squelettes de classes, vous pouvez toujours vous orienter vers une solution utilisant l’instrumentalisation et les Agents Java qui vous permettra d’interagir avec le class loader et donc, de contrôler le chargement de vos classes. C’est d’ailleurs ce que nous propose Zero Turnaround avec son produit JavaRebel.

Fonctionnement de JavaRebel

JavaRebel se présente sous la forme d’un agent java (-javaagent). Pour recharger les classes, JavaRebel inspecte les fichiers ‘.class’ sur le système de fichiers via le classpath de l’application et d’autres répertoires spécifiques configurables et les compare avec ceux déjà chargés dans la JVM. À la moindre modification détectée, l’agent Java recharge la classe en conséquence.
Toutes les modifications de structures sont possibles :

  • ajout / suppression de champs et de méthodes
  • ajout d’annotations
  • modification d’interfaces
  • création de classes

En revanche les modifications liées à l’héritage ne fonctionnent pas (déclaration de classe mère et d’interfaces).

JavaRebel n’utilisant pas le HotSwap, nul besoin de démarrer son application en mode debug pour disposer du rechargement de classes. Par contre, rien ne vous empêche d’activer celui-ci au besoin en complément. Vous pouvez donc analyser le comportement d’une méthode en utilisant le pas à pas du mode debug en simultané avec le rechargement des classes proposé par JavaRebel. Par exemple, cela vous permettra de développer et tester en continu la création d’actions sans avoir besoin de redéployer votre application à chaque changement.

JavaRebel fonctionnant sur une application en cours d’exécution sur une JVM, ce mécanisme de rechargement de classes fonctionne quelque soit le format de déploiement de votre application (WAR éclaté, WAR, EAR, etc.). Il est donc également tout à fait possible de recharger une classe provenant d’un JAR de votre EAR sans à avoir à repackager celle-ci : seule la compilation de votre code Java est nécessaire !

Notez cependant qu’il s’agit d’un mécanisme très gourmand en ressources, destiné à être utilisé durant la phase de développement uniquement.

Plugins JavaRebel

Malheureusement, le rechargement de classes n’est pas toujours suffisant. En effet, de nombreux frameworks disposent de mécanismes bridant son utilisation. Par exemple, le chargement statique de fichiers de configurations, la présence de certains caches vous forceront probablement à redémarrer votre application lors de vos développements : frustrant !

Pour pallier ce problème, JavaRebel dispose d’un système de plugins vous permettant d’effectuer certaines actions après le rechargement de vos classes. Ces plugins, dont voici la liste, permettent ainsi de modifier le comportement de vos frameworks et donc de vous éviter un certain nombre de redéploiements :

  • Plugins de frameworks techniques : Spring (en version de test M2) , Guice (en M1), EJB 2 et 3 (à venir)
  • Plugins de frameworks Web : Struts 2 (en M2), Tapesty 4 (en M1), Spring MVC (en M2)
  • Plugins ORM : Hibernate (à venir), TopLink (à venir), JPA (à venir)

Comme vous l’aurez remarqué, si la liste des plugins prévus est impressionnante, aucun n’est pour le moment sorti en version définitive. Pourtant, certains d’entre eux sont utilisables. Le plugin Spring est de loin le plus abouti, il vous permet de recharger votre configuration (via XML ou annotations), d’ajouter ou supprimer des dépendances et même d’ajouter des Controllers Spring MVC à la volée.

Vous avez également la possibilité de créer vos propres plugins, JavaRebel dispose d’un SDK open-source relativement simple à utiliser. L’idée centrale est d’injecter du code personnalisé juste après le rechargement d’une classe.

En conclusion, un petit retour d’expérience …

J’ai certainement laissé transpirer dans cet article mon enthousiasme à propos de cet outil. Avant d’apporter mon retour d’expérience sur celui-ci, il me semble important de rappeler le contexte dans lequel j’ai effectué ce test. Je n’utilise JavaRebel que depuis très peu de temps (moins d’un mois), je ne dispose d’ailleurs que d’une simple version d’évaluation de ce produit, j’attends la fin de celle-ci pour me procurer une licence. J’ai testé ce produit dans le cadre d’un XKE afin de présenter celui-ci aux autres consultants Xebia France. Du coup, j’ai beaucoup plus utilisé celui-ci sur des projets de petite taille, mais je n’ai pour le moment pas été déçu lors de son utilisation sur des projets de plus grande envergure.

Mon point de vue est qu’il ne faut pas se tromper sur les possibilités de celui-ci. L’overhead engendré par JavaRebel vous le rappelle : il s’agit d’un outil à utiliser durant la phase de développement et uniquement durant celle-ci. Les équipes de JavaRebel ont dans leur roadmap l’idée de pousser celui-ci sur des applications déployées en production, force est de constater qu’ils en sont encore très loin. Pour atteindre cet ambitieux objectif, ils devront probablement remplacer le module détectant les modifications des ‘.class’. Pourquoi ne pas proposer alors un mécanisme qui permettrait de mettre à jour les classes à distance en calquant le fonctionnement du HotSwap ?

Pourtant, l’essayer c’est l’adopter. Cumuler les avantages proposés par le traditionnel mode debug de la JVM (exécution pas à pas, inspection des objets) avec le rechargement par JavaRebel des classes de votre projet, vous permet un gain de productivité non négligeable. Les fonctionnalités offertes par JavaRebel sont à mon sens indispensables et devraient exister depuis bien longtemps. L’idéal serait que celles-ci soient directement intégrées dans la JVM, ce sera peut-être un jour le cas. D’ici là, vous n’avez d’autre choix que d’utiliser le seul outil du marché proposant ces fonctionnalités : JavaRebel.

JavaRevel est compatible sur la plupart des JVM depuis leur version 1.4 et supporte la majorité des serveurs d’applications. Il fonctionne également pour des applications non-web, ainsi que dans un conteneur OSGi.

La plus grosse faiblesse de cet outil réside dans l’état d’avancement de ses plugins. Si la programmation de ceux-ci est relativement aisée, trouver quelles sont les bonnes lignes de codes à injecter demande une maîtrise parfaite des différents frameworks. Les développeurs de JavaRebel avouent d’ailleurs avoir besoin d’utilisateurs expérimentés pour les aider à créer de nouveaux plugins.

Pour finir, le petit calcul marketing pour vous convaincre (Marketing, mais révélateur) :

  • Temps de rechargement de votre application : 1 minute (moyenne basse)
  • Nombre de rechargements : 5 par heure de développement
  • Temps perdu par heure : 5 minutes, soit 8.33% du temps.
  • Temps perdu par semaine : 3h20
  • Temps perdu par année : 21 jours / soit un mois environ

Combien de développeurs il y a-t-il sur votre projet ?
Combien coûte une journée de développement ?

Liens connexes :

Mots-clefs :, , ,