Publié par
Il y a 10 années · 10 minutes · Java / JEE

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 :

Erwan Alliaume
Passionné par les technologies Java/JEE depuis sa sortie de l'EPITA, Erwan Alliaume est aujourd'hui consultant chez Xebia. Il intervient depuis 2 ans sur des missions de développement et d'architecture pour l’un des leaders mondiaux de la production et de la distribution de contenus multimédia. Expert technique polyvalent, Erwan a été amené très tôt à prendre des responsabilités sur des projets de taille significative. Il a notamment développé des compétences clé dans la mise en place de socle de développement, la métrologie et les audits de performance et de qualité. Erwan participe également activement au blog Xebia ou il traite aussi bien de sujets d’actualités que de problématiques techniques.

10 thoughts on “JavaRebel – Rechargez vos classes sans redeployer”

  1. Publié par Jawher, Il y a 10 années

    Salut,
    J’ai la chance de disposer d’une licence de JavaRebel, et je dois avouer que je suis sous le charme : j’en use et abuse :D
    Ca marche (presque) partout : dans une application Java SE, dans une application Web (depuis Eclipse), ça marche dans un conteneur OSGi, etc.
    Vous résumez très bien la chose avec : « l’essayer c’est l’adopter. »

    Toutefois, la face caché de l’iceberg est qu’il arrive parfois que JavaRebel cause des bugs bizarres et très difficiles à dépister mais surtout silencieux dans des applications un peu complexes.
    donc, en face d’un truc qui cloche, relancer le test sans JavaRebel peut être le geste qui sauve ;)

    Jawher

  2. Publié par Francois, Il y a 10 années

    Bon, depuis le temps que ça me démange, après un article comme cela, il va vraiment falloir que je test JavaRebel…

    En fait, avec Tapestry 5 (http://tapestry.apache.org/tapestry5/), j’ai pris de mauvaises habitudes, et je ne me rend plus compte à quel point le cycle de développement « modification/compile/package/redéploiement/test » est long et inefficace, en particulier pour la partie UI d’une application, et encore plus dans le ca d’une application Web (vous savez, ces étapes très courante au cours d’un run… « ha, j’aimerais bien un bouton en plus pour ça… Oh, et un peu de Ajax serait plus dans l’air du temps… Ah zut, j’ai pas bien fait mon handler… Et si je rajoutais des tris sur ce tableau… Mince, mon comparateur est à l’envers… »).

    Donc, Tapestry 5 prend en charge le rechargement à chaud des classes qui correspondent aux pages et composants, ce qui permet de lancer son application web dans eclipse, de modifier ses pages (templates et Java) et de simplement recharger la page dans le navigateur pour voir apparaître ses modifications.
    Le développement itératif prend un vrai sens (les Groovy-er me comprendront ici – tiens d’ailleurs, on peut faire du Groovy à la place de Java pour le backend des pages dans T5 – ou du Scala, si on préfère).

    Vous pouvez voir un exemple sur le dernier screencast de Howard (qui traite de AJAX, mais dans lequel on voit la fonctionnalité en question) :
    http://tapestryjava.blogspot.com/2008/11/tapestry-5-ajax-screencast.html

    Y’a plus qu’à tester JavaRebel. Avec Scala, parce que c’est plus marrant que Java :)

  3. Publié par Erwan Alliaume, Il y a 10 années

    J’ai cru comprendre d’un mécanisme similaire était également proposé par RIFE.
    Malheureusement tous les frameworks ne proposent pas ce genre de fonctionnalités.

    D’autres part, dis moi si je me trompe, mais j’ai cru comprendre que le mécanisme de rechargement de tapestry 5 présentait tout de même quelques lacunes :
    – seuls les composants managés par tapestry sont rechargeables (c’est déjà pas mal)
    – le rechargement de code référençant du code non managé peut provoquer certains problèmes (fuite mémoire, ClassCastException, IllegalAccessException …)

    Vous confirmez ?

  4. Publié par Francois, Il y a 10 années

    J’espère bien que T5 n’est en effet pas le seul framework à proposer celà :)
    Mais dans mon expérience limité, il se trouve que c’est le seul que j’utilise quotidiennement :) (note: après vérification, c’est le cas pour RIFE depuis très longtemps, pour Wicket aussi, et sûrement pour d’autres).

    Pour ce qui est des limitations, c’est tout à fait exact, c’est ce que je voulais dire par « [l]es classes qui correspondent aux pages et composants ». Concrètement, T5 gère ses propres classloader afin de pouvoir enrichir le bytecode des classes qui correspondent aux composants/services/mixin (au sens T5), ce qui correspond à aux packages sous « myapp » dans l’organisation de projet conventionnelle visible ici: http://tapestry.apache.org/tapestry5/guide/project-layout.html.

    En gros, dès qu’on touche à des classes de données ou des services externes (Spring…), le live reloading ne fonctionne plus, mais comme ce sont des classes dont les API sont souvent plus stables que les classes d’UI, c’est acceptable – et c’est de toute manière mieux que de toujours devoir recharger l’application.

    (T5 recharge aussi toutes les ressources de type asset (fichier properties pour les traductions, templates, images, etc), mais ceci est beaucoup plus courant).

    Pour les problèmes plus particulier dont vous parlez, je ne les ai jamais rencontré, mais ca ne veut bien sûr en aucun cas dire qu’ils n’existent pas :) Comme pour JavaRebel, le live-reload de T5 est une fonctionnalité qui a pour but principal d’accélérer le développement, rôle qu’elle remplie très bien. En cas de clastCastException, il suffit de revenir à l’ancienne méthode, et de relancer l’application.

    Par contre, se sont des symptômes qui sont fréquents lorsque plusieurs versions de T5 sont présentes dans le même war (ce qui ne devrait pas arriver, mais Maven est parfois capricieux, ou les cleans pas toujours bien faits). Dans ce cas, les différentes versions se battent pour mettre à jours les classes, et ça peut donner des résultats intéressants :)

    Bref, JavaRebel est la bonne solution à terme, parce qu’elle traite le problème là où il doit l’être : au niveau de la JVM (et je trouve comme vous aberrant que Sun n’ait pas proposé cette fonctionnalité depuis des lustres à ce niveau là). Mais JavaRebel à aussi ses contraintes (de licence notamment) qui font que tout le monde ne peut pas se permettre de l’utiliser, et dans ce cadre, la solution proposé dans T5 est mieux que rien, et est tout particulièrement adapté au contexte de la création d’UI, très itérative, mais forcément dans le contexte de l’application complètes (et donc avec des validations par tests unitaires plus difficiles, donc beaucoup de petites erreurs qui prennent moins de temps à être corrigé que le temps de charger l’application).

  5. Publié par Guillaume Carre, Il y a 10 années

    Si on regarde du côté des frameworks MVC les plus utilisés, en général ils ne supportent pas ce re-déploiement à chaud des classes (Struts, Struts2, Spring MVC, JBoss Seam).
    Wicket ne semble pas le supporter non plus, seuls les templates html sont redéployés à chaud (c’est la moindre des choses…).
    Donc Tapestry 5 est bien en avance sur la concurrence sur ce point!

  6. Publié par Nicolas, Il y a 10 années

    Merci pour ton article erwan, il donne envie d’essayer.

    Seam propose un redeploiement leger pratique lorsque l’on travaille uniquement sur la partie vue (xhtml,css) et qu’aucuns beans Seam n’est ajoute.
    Mais ce n’est pas aussi pousse que ce que tu as presente.

    Sinon comme tu l’expliques, on oublie souvent que l’on peut se connecter a un Weblogic en mode debug et recharger une partie de l’application… Combien de developpeur perdent leur temps a tout recompiler ?

  7. Publié par Dominique De Vito, Il y a 10 années

    Une fonctionnalité relativement similaire à JavaRebel fait partie de la JSR-292 « Supporting Dynamically Typed Languages on the Java Platform ».

    On entend plus souvent parler d’une des 2 parties de cette JSR : la fameuse instruction « invokedynamic » ; mais cette JSR a d’autres buts :

    «  »
    * to add a new JVM instruction, invokedynamic, designed to support the implementation of dynamically typed object oriented languages […]
    * also investigate support for hotswapping, the capability to modify the structure of classes at run time.
    «  »

    J’espère que cette JSR fera bien parti de JDK 7…

  8. Publié par Erwan Alliaume, Il y a 10 années

    Bonne remarque ! Pourtant, s’il est probable que cette JSR (JSR-292) fasse effectivement partie du jdk7, il me semble peu plausible que cette fonctionnalité y soit implémentée…

    Sauf erreur de ma part, personne n’a plus parlé de ces améliorations du Hotswap depuis 2006, date de création de la JSR-292. L’early draft de celle-ci, disponible depuis mars dernier, n’en fait d’ailleurs aucune allusion.

    J’en ai profité pour refaire le tour des articles sur le sujet. Danny Coward lui-même (ancien spec lead de la JSR-292, maintenant responsable de la umbrella JSR pour Java 7) avouait ne pas trop savoir comment s’y prendre pour permettre ce genre service. Je suis également tombé sur un article de Gilad Bracha commenté par l’un des contributeurs principaux RIFE enthousiasmé par le rechargement de classes à chaud, fonctionnalité qui différencie justement son framework. Quant à Gilad, également ancien spec lead de la JSR-292, il a préféré s’enfuir dans le monde de la modularité JAM/OSGi avec leur fine grained class loader plutôt que de pousser les évolutions du hotswap. Toute plaisanterie mise à part, à mon avis, ce n’est pas encore demain que la JVM concurrencera ce que nous propose JavaRebel.

    Avez-vous des informations contradictoires ?

    Question bonus : avez-vous un pronostique pour la sortie de la umbrella JSR Java 7 ? Personnellement, j’avais tout misé sur ‘mai dernier’ … :(

  9. Publié par Dominique De Vito, Il y a 10 années

    Tout ce que j’ai trouvé récemment, ce sont des infos datant de Septembre 2008 sur le blog de Charles Nutter : http://blog.headius.com/2008/09/first-taste-of-invokedynamic.html

    Mais il n’invoque pas le hotswap, mais plutôt un pb connexe/sous-jacent qui est celui de la création de (très) nombreuses classes, et de *certaines* modifications dynamiques, création-modification propre aux langages dynamiques. Pour ce faire, il propose un ‘anonymous class loader’. Je n’ai pas regardé plus loin.

    Quant à la sortie de la umbrella JSR Java 7, je n’ai pas d’idée. En fait, cela va sans doute dépendre de ce qu’ils veulent inclure dedans, par ex, avec ou sans closures ? Tous les composants n’ont pas le même degré d’avancement :
    http://tech.puredanger.com/2008/08/02/java7-prediction-update/

    Par ailleurs, j’ai trouvé un autre bon résumé du contenu du JDK 7 : http://tech.puredanger.com/java7

Laisser un commentaire

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