Agilité, Développement Java, Nouvelles technologies et plus…
  • rss
  • Accueil
  • Management
  • Programmation agile
  • Technologie
  • Linux
  • Evénement
  • App Android
  • Contact
  • A propos de l'auteur
  • English
  • Francais

Une migration Java 11 réussie

Fabian Piau | jeudi 27 décembre 2018 - 11:45
  • Imprimer
  • Twitter
  • LinkedIn
  • Facebook
  • Pocket

 English version available

Cet article résume le travail que nous avons accompli au sein de mon équipe pour migrer nos micro-services de Java 8 à Java 11 pour le site Hotels.com.

En résumé, pour chacun de nos services, nous avons suivi les étapes suivantes:

  • Compiler le code avec Java 11
  • Démarrer le service (compatible Java 11) sur Java 8
  • Démarrer le service sur Java 11

En réalité, nous avons eu quelques étapes supplémentaires. Lorsque nous avons commencé la migration, Java 11 n’était pas encore disponible, nous ne pouvions utiliser que Java 10.
L’hypothèse était la suivante: si le code compile avec Java 10, la migration vers Java 11 ne demandera pas beaucoup de travail, car le changement le plus important à propos de la modularité a été introduit avec Java 9 et le projet Jigsaw. Heureusement, ce fut le cas!


Mise à jour du sabre laser Star Wars...

Mise à jour du sabre laser Star Wars...


1. Compiler le code avec Java 11

C’est la partie qui a pris le plus de temps. En effet, nous avons dû monter en version la plupart des frameworks et des outils que nous utilisions. En particulier, nous avons dû gérer la migration de Spring Boot 1 à 2 et de Spring 4 à 5. S’agissant de versions majeures, nous avons dû prendre en compte quelques modifications importantes.

Spring Boot

Pour Spring Boot 2, les guides de migration officiels de Spring Boot 2.0 et Spring Boot 2.1 sont bien écrits et détaillés.

  • Le chargement des profils a évolué
  • Le relaxed binding des propriétés est un peu moins relaxed
  • Certaines propriétés ont été renommées et d’autres sont indisponibles (par exemple, la propriété security.basic.enabled doit être remplacée par un WebSecurityConfigurerAdapter)
  • Certains endpoints ont été renommés (par exemple, actuator healthchecks)
  • L’overriding de bean est maintenant désactivé par défaut. Comme nous l’utilisions dans nos tests d’intégration, nous avons dû le réactiver avec la nouvelle propriété spring.main.allow-bean-definition-overriding.

Spring

La migration vers Spring 5 était plutôt simple du point de vue du code avec quelques changements mineurs. La partie la plus compliquée était liée au fait que le projet était legacy et que nous devions gérer une configuration Spring en XML complexe et la migration vers Dropwizard Metrics 4.

Divers

Il peut arriver que des frameworks ne soient toujours pas compatibles avec Java 9+ car ils ne sont pas activement maintenus par la communauté. Dans notre cas, nous avons dû trouver une solution de contournement pour Cassandra Unit. Nous ne voulions pas investir de temps dans un changement de framework DB de test car nous prévoyons de passer à DynamoDB.

Nous avons également dû faire face au « Maven dependency hell » car certaines dépendances obligatoires tiraient d’anciennes dépendances non compatibles avec Java 9+. Dans la plupart des cas, l’ajout d’exclusions dans le POM a résolu le problème.

Environnement local

En local, nous avons ajouté quelques alias à notre fichier de profil bash pour passer d’une version de Java à une autre.

alias setjava8="export JAVA_HOME=/Library/Java/JavaVirtualMachines/jdk1.8.0_172.jdk/Contents/Home/"
alias setjava10="export JAVA_HOME=/Library/Java/JavaVirtualMachines/jdk-10.0.2.jdk/Contents/Home/"
alias setjava11="export JAVA_HOME=/Library/Java/JavaVirtualMachines/openjdk-11.jdk/Contents/Home/"

Sous IntelliJ, le changement de version de Java peut être effectué à partir des paramètres du projet (la liste déroulante « Project SDK »).

Environnement IC

Du côté de l’Intégration Continue (nous utilisons Bamboo), nous avons mis à jour l’agent pour qu’il utilise Java 11.
Nous avons constaté qu’il n’était pas possible d’avoir des versions différentes de l’agent pour les plans de branche et le plan principal (master), car la configuration du plan est globale. Cela signifie que la mise à jour de l’agent vers Java 11 cassera le plan principal si quelqu’un d’autre commite sur master (par exemple, une nouvelle fonctionnalité ou un correctif de bogue totalement indépendant de la migration vers Java 11).
Pour atténuer ce problème et éviter un build rouge, il était important pour nous de nous assurer que le projet était compilable avec Java 11 et que tous les tests passaient localement avant d’effectuer la mise à jour de l’agent, ceci afin de merger rapidement la branche concernant la migration Java. Une autre option consisterait à remettre temporairement l’agent à Java 8 une fois que le plan de branche est vert sur Java 11 sans oublier de le rebasculer sur Java 11 juste avant le merge.


2. Démarrer le service (compatible Java 11) sur Java 8

Une fois que tout a été corrigé, mergé et que le build principal est au vert, nous nous sommes assuré que la version compatible Java 11 fonctionnait correctement dans nos environnements de test. En gros, nous nous assurions que rien ne soit cassé… Nous avions des tests unitaires, d’intégration et des tests end-to-end, autant dire que notre niveau de confiance était assez élevé. Comme on est jamais trop prudent, nous avons effectué des tests exploratoires manuels sur l’API, avec quelques requêtes exotiques et autres cas en marge afin de nous assurer que le service se comportait correctement. Nous avons également consulté les log et les tableaux de bord Grafana pour s’assurer que tout fonctionnait bien.

La prochaine étape consistait à pousser cette nouvelle version en production. Le service fonctionnait toujours avec Java 8, même si le code était compatible (et compilé) avec Java 11, nous ne voulions pas introduire trop de changements en même temps, nous n’aimons pas les versions risquées après tout. Nous avons traité cette version avec un soin supplémentaire en raison de la refactorisation importante et des multiples montées en version. Après avoir examiné les tableaux de bord Grafana pendant quelques jours, en comparant les métriques avant et après la migration, nous avons constaté que tout s’était bien passé.


3. Démarrer le service sur Java 11

Le but était d’exécuter le service sur Java 11. En théorie, ce serait aussi simple que de mettre à jour le fichier Docker pour utiliser l’image Java 11 et pousser l’artifact en production. Cependant, dans la pratique, ce n’était pas si simple…

Tout d’abord, nous avons dû mettre à jour certains arguments de la JVM (le paramètre -d64 est obsolète et empêchera le service de démarrer, nous avons également dû mettre à jour l’argument concernant les logs du Garbage Collector).

Ensuite, nous avons rapidement réalisé que les logs s’étaient volatilisées dans Splunk pour notre environnement de production interne. En fait, elles apparaissaient dans le future alors qu’il n’y avait aucun soucis avec la production sur AWS. Nous avons dû mettre à jour la configuration logback pour corriger cette « distorsion temporelle » ;) en mettant à jour le date pattern de %d{ISO8601} à %d{yyyy-MM-dd'T'HH:mm:ss.SSSZ,UTC}.

Une autre erreur étrange VerifyError: Bad type on operand stack a fait son apparition pendant le déploiement en production. AppDynamics empêchait le démarrage de certaines instances en raison d’une manipulation exotique du bytecode. Pour des raisons encore inconnues, le déploiement échouait aléatoirement sur une des instances après avoir réussi sur plusieurs autres! Nous avons dû désactiver AppDynamics, ce qui nous convenait bien, car nous n’utilisons pas cet outil dans notre équipe.

Après la migration vers Java 11, nous avons également dû mettre à jour certains de nos tableaux de bord Grafana afin de refléter l’utilisation d’un nouveau Garbage Collector – G1.


Conclusion

Aujourd’hui, 3 services fournissant les notifications utilisateur utilisant Spring Boot 2 et 1 service fournissant l’en-tête et le pied de page du site utilisant Spring 5 fonctionnent sur Java 11, cela fait maintenant plusieurs semaines. Ils utilisent le Garbage Collector par défaut G1 et nous n’avons rencontré aucun comportement étrange lié à la mémoire ou à tout autre problème de performance. Aussi, nous n’avons constaté aucune amélioration de nos temps de réponse. Mais maintenant nous utilisons une version Java LTS (support à long terme), la migration a été un succès.

Et après? Java 12 sera publié en mars 2019. A ce jour, nous ne savons toujours pas si nous utiliserons cette version ou attendrons le prochain Java LTS. Cela dépendra probablement des fonctionnalités incluses.

Articles similaires

java-9QCon London 2016 – Projet Jigsaw dans JDK 9 – La modularité arrive sur Java springQCon London 2016 – Spring Framework 5 – Preview et Roadmap Java EE vs SpringJava EE & CDI vs. Spring devoxxDevoxx UK 2018 – Jour 1
Commentaires
3 Commentaires »
Catégories
Programmation agile
Tags
java, migration
Flux rss des commentaires Flux rss des commentaires

QCon London 2016 – Projet Jigsaw dans JDK 9 – La modularité arrive sur Java

Fabian Piau | jeudi 14 avril 2016 - 21:09
  • Imprimer
  • Twitter
  • LinkedIn
  • Facebook
  • Pocket

 English version available

Simon Ritter a donné une présentation sur le futur JDK 9 à QCon London.

QCon London 2016 - Projet Jigsaw dans JDK 9 - La modularité arrive sur Java

QCon London 2016 - Projet Jigsaw dans JDK 9 - La modularité arrive sur Java


La politique de compatibilité de Java

Il a commencé avec un fait intéressant: depuis longtemps, Java a une politique de compatibilité permanente.
Si une application utilise uniquement des API prises en charge par une version N de Java, elle devrait parfaitement fonctionner sur la version N+1, sans même devoir être recompilée.
Voilà pourquoi, à ce jour, il y a:

  • 23 classes, 18 interfaces et 379 méthodes qui ont été dépréciées
  • Et rien qui n’a été supprimé.


JDK 9 apporte des incompatibilités

Le JDK est devenu de plus en plus lourd au fil des années. Les choses vont changer avec la version 9.

  • Un petit nombre d’API actuellement supportées sera supprimé
  • La structure binaire du JRE et JDK va changer (voire les détails ci-dessous)
  • Il est interdit d’utiliser le caractère underscore _ pour nommer une variable. C’est maintenant un mot-clé réservé.
  • Il y aura un nouveau système de versionnage de sorte qu’il sera plus facile de faire la distinction entre les versions majeures, mineures, ou les mises à jour liées à la sécurité ; par exemple, Java 9.1.2.1. Le format de versionnage actuel est difficile à comprendre, par exemple les versions 8u51 et 8u60 ne sont pas très explicites.

La structure du JDK va changer. Le dossier JRE est supprimé, tools.jar et rt.jar ne seront plus présents, ces JARs contenaient pas mal de duplication.

Structure pre-JDK 9

Structure Pre-JDK 9

Pour mieux comprendre la structure pre-JDK 9, vous pouvez lire JDK 8 and JRE File Structure.

Structure JDK 9

Structure JDK 9

La structure du JDK 9 est beaucoup plus propre.

JEP 260 proposal est au coeur du JDK 9 et Jigsaw.

L’idée est de rendre la plupart des API internes du JDK inaccessibles par défaut, mais en en laissant tout de même quelques-unes (celles qui sont largement utilisées et sont donc critiques) jusqu’à ce qu’elles soient remplacées.

Le but est d’encapsuler toutes les API dépréciées dans un module, et finalement de s’en débarrasser plus tard (JDK 10?).

Depuis la version 8 du JDK, un outil en ligne de commande existe pour analyser les dépendances de votre JAR ou de vos classes: jdeps. Essayez-le! Il peut être utile pour savoir si vous utilisez encore des API internes du JDK. Vous devriez éviter d’utiliser de telles dépendances, car elles peuvent être supprimées dans une future version du JDK.


Jigsaw et les modules

Nous parlons de module, mais qu’est-ce que c’est en fait?
Jigsaw apporte de la modularité au JDK. Il rend Java plus évolutif et flexible, tout en améliorant la sécurité, la maintenabilité et la performance.
Le JDK est divisé en modules, l’idée est de prendre seulement ce dont on a besoin.

Module

Un module est un regroupement de code (collection de packages), il peut également contenir:

  • Du code natif
  • Des ressources
  • Des données de configuration

Mon premier module

Pour définir un module, vous devez créer un fichier module-info.java, qui contiendra (par exemple):

module com.company.mymodule { 
  requires com.company.myothermodule; 
  requires java.sql; 
}

Vous pouvez avoir des dépendances transitives (un peu comme dans Maven) grâce au mot-clé public.

module java.sql { 
  requires public java.logging; 
}

Cela signifie que si j’ai une dépendance sur le module java.sql, je vais avoir accès à toutes les classes incluses dans java.logging (tout du moins tous les types marqués public).

Nous avons maintenant un graphe de dépendances des modules.

Visibilité d’un package

Avec l’utilisation du mot-clé exports.

module com.company.myothermodule { 
  exports com.company.myothermodule.alpha;  
  exports com.company.myothermodule.beta; 
}

Ce qui est exporté est visible, ça ne l’est pas par défaut!

Avec Java 9 et l’arrivée des modules, nous devons redéfinir le mot-clé public. Il a maintenant plusieurs significations:

  • Public à tout le monde
  • Public, mais seulement à des modules particuliers
  • Public, uniquement à l’intérieur d’un module

Public ne signifie plus nécessairement accessible, c’est un changement fondamental.
Vous pouvez lire la spécification de Jigsaw pour en savoir plus.

Compilation et exécution avec le « module path »

Oubliez le classpath, il y a un nouveau paramètre modulepath (ou -mp) disponible avec la commande javac / java. Sa valeur contient un ou plusieurs répertoires qui contiennent les modules nécessaires pour compiler / exécuter votre application.

Enfin, notez qu’il y aura des modules par défaut pour les fichiers JAR qui ne sont pas encore modularisés (module automatique).

Articles similaires

Java 11Une migration Java 11 réussie IT jobsPanorama simplifié des métiers de l’informatique Java EE vs SpringJava EE & CDI vs. Spring springQCon London 2016 – Spring Framework 5 – Preview et Roadmap
Commentaires
Pas de Commentaires »
Catégories
Evénement
Tags
java, jigsaw, qcon
Flux rss des commentaires Flux rss des commentaires
Page 1 sur 512345
Télécharger l'app CarmaBlog

Flux RSS

  • Flux RSS RSS - Articles
  • Flux RSS RSS - Commentaires

Articles les plus vus

  • Changer la langue de Firefox - 116 369 vues
  • Réaliser un sondage en ligne avec Google Forms / Drive / Docs - 64 395 vues
  • FAQ – Sondage en ligne avec Google Forms / Drive / Docs - 56 229 vues
  • Personnaliser Gnome 3 (Shell) - 30 805 vues
  • La signification d’URL, URI et URN - 18 403 vues
  • Java EE & CDI vs. Spring - 15 984 vues
  • Open Street Map, une meilleure carte que Google Maps? - 15 796 vues
  • Comparaison NoSQL: Couchbase et MongoDB - 14 690 vues
  • API, REST, JSON, XML, HTTP, URI… Vous parlez quelle langue en fait? - 13 728 vues
  • Une première approche du Camel d’Apache - 13 590 vues

Commentaires récents

  • Fabian Piau sur FAQ – Sondage en ligne avec Google Forms / Drive / DocsOui, dans Google Forms, vous pouvez empêcher les p…
  • BENECH Fabien sur FAQ – Sondage en ligne avec Google Forms / Drive / DocsBonjour, J'ai crée 1 questionnaire via Forms,…
  • SANKARA TIDIANE sur Formation en ligne gratuite sur MongoDBJ'aimerai suivre
  • Pauline sur FAQ – Sondage en ligne avec Google Forms / Drive / DocsMerci Fabian, mais le but étant que nos clients pu…
  • Fabian Piau sur FAQ – Sondage en ligne avec Google Forms / Drive / DocsProbablement mais ces options sont en général paya…

Articles récents

  • Comment écrire un article de blog? En tout cas à ma façon! - Il y a 2 ans et 5 mois
  • Attaques de robots: vous n’êtes pas seul… - Il y a 4 ans et 3 semaines
  • Flagger – Monitorer vos déploiements Canary avec Grafana - Il y a 4 ans et 10 mois
  • Flagger – Déploiements Canary sur Kubernetes - Il y a 4 ans et 11 mois
  • Flagger – Premiers pas avec Istio et Kubernetes - Il y a 5 ans et 2 semaines
  • CoderDojo Expedia à Londres - Il y a 5 ans et 9 mois
  • Etre bénévole à Devoxx4Kids - Il y a 6 ans et 1 semaine
  • Une migration Java 11 réussie - Il y a 6 ans et 4 mois
  • Conseils pour sécuriser votre site WordPress - Il y a 6 ans et 7 mois
  • Devoxx UK 2018 – Jour 2 - Il y a 6 ans et 11 mois
  • Devoxx UK 2018 – Jour 1 - Il y a 6 ans et 11 mois
  • Wise, Revolut et Monzo, une petite révolution dans le monde des expatriés et voyageurs - Il y a 7 ans et 3 mois
  • Autocomplétion pour Git - Il y a 7 ans et 11 mois
  • Swagger, la documentation API automatisée - Il y a 8 ans et 2 mois
  • Architecture Microservices – Les bonnes pratiques - Il y a 8 ans et 7 mois
Offre moi un café

Langue

  • Français
  • English

Suivez-moi!

Suivez-moi sur Linkedin
Suivez-moi sur Twitter
Suivez-moi sur Stackoverflow
Suivez-moi sur Github
Suivez-moi sur Rss
Link to my Contact

Abonnement email

Saisissez votre adresse email pour être informé des nouveaux articles.

Étiquettes

.net agile agilité android bash blog bonnes pratiques cache cloud conférence css devoxx docker développeur eclipse extreme programming firefox flagger google helm hibernate informatique intégration continue istio java jug kubernetes londres mobilité informatique métier outil panorama partage performance plugin programmeur script société spring sécurité tdd test ubuntu windows wordpress

Liens

  • Blog Ippon Technologies
  • Blog Publicis Sapient
  • Blog Zenika
  • Classpert
  • CommitStrip
  • Coursera
  • Le Touilleur Express
  • Les Cast Codeurs Podcast
  • OCTO talks !
  • The Twelve-Factor App

Catégories

  • Evénement (15)
  • Linux (3)
  • Management (8)
  • Programmation agile (29)
  • Technologie (45)

Archives

  • décembre 2022 (1)
  • avril 2021 (1)
  • juin 2020 (1)
  • mai 2020 (2)
  • juillet 2019 (1)
  • mai 2019 (1)
  • décembre 2018 (1)
  • octobre 2018 (1)
  • juin 2018 (1)
  • mai 2018 (1)
  • janvier 2018 (1)
  • mai 2017 (1)
  • mars 2017 (1)
  • octobre 2016 (1)
  • avril 2016 (2)
  • mars 2016 (1)
  • novembre 2015 (1)
  • mai 2015 (1)
  • février 2015 (1)
  • décembre 2014 (1)
  • novembre 2014 (1)
  • septembre 2014 (2)
  • août 2014 (1)
  • juillet 2014 (2)
  • juin 2014 (1)
  • avril 2014 (1)
  • mars 2014 (1)
  • février 2014 (2)
  • janvier 2014 (1)
  • décembre 2013 (1)
  • novembre 2013 (1)
  • octobre 2013 (3)
  • septembre 2013 (5)
  • juillet 2013 (1)
  • juin 2013 (1)
  • mai 2013 (1)
  • avril 2013 (1)
  • mars 2013 (2)
  • février 2013 (1)
  • janvier 2013 (2)
  • décembre 2012 (2)
  • octobre 2012 (1)
  • septembre 2012 (1)
  • juillet 2012 (1)
  • mai 2012 (1)
  • avril 2012 (1)
  • mars 2012 (1)
  • février 2012 (1)
  • janvier 2012 (2)
  • décembre 2011 (1)
  • novembre 2011 (2)
  • octobre 2011 (2)
  • septembre 2011 (1)
  • juillet 2011 (1)
  • juin 2011 (2)
  • avril 2011 (1)
  • mars 2011 (1)
  • février 2011 (1)
  • janvier 2011 (2)
  • novembre 2010 (2)
  • septembre 2010 (1)
  • août 2010 (1)
  • juillet 2010 (1)
  • juin 2010 (1)
  • mai 2010 (1)
  • avril 2010 (1)
  • mars 2010 (1)
  • février 2010 (1)
  • décembre 2009 (1)
  • novembre 2009 (1)
  • octobre 2009 (2)
  • septembre 2009 (2)
  • août 2009 (3)
  • juillet 2009 (1)
  • juin 2009 (2)
Suivez-moi sur Twitter
Suivez-moi sur Linkedin
Suivez-moi sur Stackoverflow
Suivez-moi sur Rss
Link to my Contact
Suivez-moi sur Github
 
Fabian Piau | © 2009 - 2025
Tous droits réservés | Haut ↑