Les rendez-vous manqués de Spring (une courte histoire de Java EE)

Le 10 décembre 2009, après plus de 3 ans de travail du JCP, les spécifications Java Enterprise Edition 6 sont sorties de leur longue maturation. Cette dernière mouture très prometteuse apporte enfin une solution d’injection de dépendance légère et élégante pour des architectures modernes : la spécification CDI (Context and Dependance Injection) qui permet de travailler avec des « managed beans » (pojos gérés par un conteneur léger) et des EJB 3.1.

Une révolution ? Pas vraiment, puisque depuis près de 6 ans le Framework Spring proposait déjà une solution de ce type. Sachant que Spring source (VMware) est un membre actif du JCP et a participé à l’élaboration certaines JSR, il est légitime de se demander pourquoi l’implémentation de référence de la solution de CDI de Java EE 6 n’est pas Spring. S’agit-il d’une erreur de stratégie de la part de l’éditeur ou d’un calcul délibéré pour rester le challenger d’un standard très proche en terme de simplicité et de fonctionnalités ?

Disclaimer

Avant d’aller plus loin dans mon propos et après être retourné sur des threads enflammés de Spring vs JBoss/Java EE de la belle époque, je voudrais juste préciser que cet article n’est pas une critique du Framework Spring (même si j’ai des réserves dans certains choix d’orientation de l’outil) que nous utilisons beaucoup chez Ippon et qui personnellement m’a amené à adopter de meilleures pratiques dans mes développements. Non, il s’agit plutôt d’une interrogation sur la stratégie de Spring VMWare et sur les objectifs recherchés par l’équipe de Rod Johnson. Dans la mesure où, comme des dizaines de milliers d’entreprises à travers le monde, nous utilisons quotidiennement ce magnifique outil, il me paraît légitime de prendre du recul et analyser la direction prise par l’éditeur.

Pour être honnête je dois dire que j’ai mené dernièrement quelques projets sous EJB3 et Seam (avec un peu de Spring pour l’un d’entre eux) et que cette alternative me paraît tout à fait digne d’intérêt voire plus productive dans certains cas. C’est d’ailleurs le point de départ de ma réflexion sur le sujet et l’origine de cet article.

Désolé pour ceux qui n’aiment pas les flashbacks, mais un historique est indispensable pour comprendre la situation actuelle. En route donc, vers l’âge de bronze de Java : 1999.

La génèse de l’IoC et des conteneurs en Java

Les débuts de J2EE en 1999 furent un peu décevants. Si les spécifications servlet et JSP étaient prometteuses et le concept des EJB plutôt bon, la mise en œuvre de ces derniers était extrêmement lourde et contraignante. Ainsi EJB ne rencontra pas le niveau d’adoption espéré par ses concepteurs et c’est probablement de ce loupé qu’est né le schisme entre serveur d’application J2EE « lourd » et Serveur « léger » (n’implémentant que les spécifications Servlet et JSP).

Cependant le besoin d’un conteneur léger pour gérer des composants métiers ou techniques était bien réel et comme aucune solution standard n’existait, des initiatives privées commencèrent à apparaître. Le premier fut probablement le projet Apache Avalon (1999) qui introduisit ces concepts bien avant 2004 et l’article fondateur de Martin Fowler (http://martinfowler.com/articles/injection.html) sur le sujet. Cette même année 2004, Rod Johnson et Juergen Hoeller publiaient le célèbre : « J2EE Development without EJB » et la version 1.0 de Spring voyait le jour. Cette solution rencontra très vite un succès important (preuve de la réalité du besoin et de la malformation congénitale d’EJB) et est encore aujourd’hui la solution phare en la matière.

[Spring vs CDI Timeline](http://www.dipity.com/antoinesd/Java-EE-and-Spring-Timeline/)
### Les frameworks web et leur besoin de « managed beans »

Parallèlement à ces concepts très élaborés, le besoin de disposer de composants plus évolués que de simples classes Java en terme d’interopérabilité ou de cycle de vie, s’est rapidement fait sentir pour les frameworks Web naissant. Les formBeans de Struts, apparu en 2000, constituent probablement la première solution de ce genre. Craig R. McClanahan, le papa de Struts s’embarqua dès 2001 dans la JSR 127 qui devait donner naissance trois ans plus tard au très controversé JSF 1.0 qui fut le premier Framework UI à introduire explicitement la notion de « managed bean » que l’on retrouvera dans Java EE 6 et CDI en 2009.
De son côté Spring, adressa ce besoin dès la version 1.0 (2004) par des classes permettant de mettre à disposition de la couche Web des beans du conteneur. Tout ça devait évoluer plus tard vers Spring MVC qui deviendrait un concurrent sérieux de Struts dès 2005.

Le besoin de persistance et l’arrivée des ORMs

Un autre aspect absent d’EJB 1.X et maltraité par EJB 2.X était la persistance. Ce concept d’association d’Objet à un modèle de base relationnel (Object Relational Mapping), n’était pas nouveau, et avait déjà été pas mal exploré avec des langages comme Smalltalk.

En Java, beaucoup de projets se sont formés pour répondre à ce besoin d’ORM. On peut citer par exemple JDO, iBatis ou Toplink. Mais, l’acteur majeur dans le domaine fut sans conteste Hibernate. A l’instar de Rod Johnson, Gavin King le père d’Hibernate est lui aussi une star du monde open source Java et l’affrontement entre les deux hommes et de leurs disciples, à défaut de leur donner une bonne image, occupa une bonne partie de la communauté des développeurs à partir du moment où Hibernate racheté par JBoss fin 2003 fit le choix d’une stratégie beaucoup plus ambitieuse que Spring pour tenter d’imposer ses outils…

EJB est mort, vive EJB !

C’est fin 2003 que Sun forma le groupe d’expert autour d’EJB 3. A cette occasion, Gavin King et Emmanuel Bernard éminents membres du projet Hibernate rejoignirent le JCP et participèrent à l’Expert Group d’EJB3. Leurs travaux débutèrent mi 2004 pour s’achever le 11 mai 2006.

Cette nouvelle version d’EJB fut une refonte totale (n’ayant en commun avec la version 2.1 que le nom) intégrant les concepts d’injection de dépendance et d’AOP rendus populaires par Spring. Ni Interface21 (la société qui devait devenir Springsource fin 2007), ni Rod Johnson (pourtant membre du JCP suite à sa collaboration à la spécification servlet 2.4) ne furent membre de l’expert group EJB3.
L’une des grosses innovations de cette nouvelle mouture fut la spécification JPA (Java Persistence API). Cette API de persistance totalement calquée sur Hibernate réussi même le tour de force de s’extirper de la spécification EJB3 pour pouvoir être exploitée directement sous Java SE et des frameworks léger comme Spring.

A travers sa participation à l’expert group EJB3, JBoss réussit a promouvoir son Framework Hibernate au rang d’implémentation de référence de JPA et à l’intégrer avec une solution standard et alternative à Spring : EJB3. Belle réussite, mais la moitié du chemin restait à faire pour sérieusement contre-carrer Spring.

Java EE5, une nouvelle ère pour le JCP

Java EE 5 dans lequel s’intègre EJB 3.0, marque un tournant important dans l’approche générale du JCP. L’entité pilotée par Sun intègre maintenant plus d’individus et d’entreprises issues du monde Open Source. La principale conséquence de cette ouverture c’est la création d’implémentations avant les spécifications. Ainsi Hibernate fut adapté au fur et à mesure par JBoss pour devenir à terme l’implémentation de référence de JPA 1.0 et JBoss commença à travailler sur des betas d’EJB3 et de JPA dès octobre 2004 (plus d’un an et demi avant la sortie de la spécification).

Ces premières versions permettent à JBoss de commencer à proposer une alternative à Spring pour exploiter Hibernate. Avec l’arrivée de cette nouvelle solution JBoss ouvre les hostilités en dénonçant la façon dont Spring exploite la session Hibernate et en expliquant qu’avec EJB3 ce sera tellement mieux. De son côté, Spring n’hésite pas à montrer Hibernate du doigt quand des utilisateurs du Framework viennent sur les forums Spring poser des questions au sujet des exceptions de type LazyInitializationException en expliquant que c’est la faute d’Hibernate si ces exceptions surviennent. Ce n’est clairement pas l’objet de cet article de prendre parti, mais on peut dire que côté agressivité et mauvaise foi les deux parties firent match nul. On pourra revoir certaines de ces passes d’armes qui ne font pas franchement l’honneur des deux camps ici : http://houseofhaug.wordpress.com/2005/08/12/hibernate-hates-spring/ ou là http://blog.springsource.com/2007/11/09/a-response-to-ejb-3-and-spring-comparative-analysis/
Sur le fond, avec 5 ans de recul, on peut quand même dire sans trop de subjectivité que l’attitude de JBoss était plutôt offensive et celle de Spring défensive. Ce qui résume plutôt bien le rapport de ces deux compagnies au marché des technologies Java.

Quoiqu’il en soit, il était évident que Spring était de loin une solution plus mature et plus complète pour couvrir toute la pile applicative du front à la persistance en passant par la couche métier. EJB3 de sont côté remplissait le contrat côté couche métier et persistance mais son exploitation à travers une webapp restait assez compliqué de par la différence entre les cycles de vie des EJB3 et ceux des servlets, sans parler du recours systématique à JNDI pour interagir avec les EJB3 qui n’était pas popur faciliter la vie du développeur. Gavin King avait manifestement réalisé cette grosse lacune (même si officiellement il clamait qu’EJB3 remplaçait avantageusement Spring) et décida dès 2005 de se lancer dans la réalisation d’un nouveau framework pour la combler.

Et Seam fut…

A la base Seam est un sacré pari, car l’objectif annoncé du framework était de faciliter l’intégration de deux standards mals aimés du monde Java : JSF et EJB. Nous avons déjà évoqué EJB3 dans les lignes précédentes, mais il faut garder à l’esprit que le nom EJB était (et est encore parfois) associé à la calamité des versions 2.1 et précédentes. Donc EJB3 a mis du temps à percer, handicapé par le fait qu’il partage le patronyme de ses prédécesseurs.

Concernant JSF (Java Server Faces), pour faire court, cette spécification inclus des idées très innovantes (développement d’interface web par composants et programmation événementielle), mais sa version 1 fut entachée par des partis pris malheureux et limitations incompréhensibles qui ont fait couler des flots de haine sur pas mal de blogs comme le célèbre : http://ptrthomas.wordpress.com/2009/05/15/jsf-sucks/. Si on additionne ces ratés à la résistance naturelle de toute communauté au changement, autant dire que JSF fut accueilli froidement par la majorité des développeurs Java et qu’aujourd’hui encore l’image de cette technologie est assez négative parmi une grande partie des développeurs qui ne l’ont jamais utilisé.
Néanmoins, un certain nombre de personnes décidèrent qu’il y avait « du bon en JSF » et qu’on pouvait travailler à en corriger ses défauts sans remette en cause ses principes fondamentaux. Ce fut le cas de Gavin King qui imagina en 2005 un framework pour faciliter l’utilisation des EJB3 avec une application utilisant JSF comme technologie de présentation. JBoss Seam était né.

En route vers la standardisation

Dès le début de Seam (avant la version 1.0), King élargit la portée du Framework. L’histoire ne dit pas vraiment comment c’est arrivé ni si tout ça était prévu dès le départ, mais on peut deviner qu’en essayant de mieux contrôler les managed bean de JSF, Il a étendu Seam au support de composants définis sous forme de simples pojo en plus des EJB et a finalement ajouté le support de la technologie concurrente : Spring. Puis, constatant la polémique autour de JSF et ne voulant pas hypothéquer le succès de son Bébé, il a ouvert Seam à d’autres technologies de front comme les simples JSP puis plus tard, GWT, Flex ou Wicket (pour ce dernier, c’est la communauté Wicket qui étendit Seam pour assurer ce support, JBoss se contenta de l’intégrer officiellement au framework).

La version 1.0 de Seam sort en juillet 2006 mais c’est deux mois avant, en mai 2006 que Redhat (qui a définitivement racheté JBoss en Avril) soumet au JCP le projet de standardisation de Seam sous le nom de Web Beans. C’est le début de la fameuse JSR 299 qui prendra au final le nom de CDI pour sortir en décembre 2009 comme nouveauté dans Java EE 6.

Dès le démarrage de l’Expert Group, Gavin et son équipe commence à travailler sur l’implémentation de référence de CDI sous le nom de Weld.

Pendant ce temps du côté de chez Spring…

Pendant les années 2005 – 2009, Springsource a beaucoup travaillé sur le lancement de nouveaux produits : serveur d’application basé sur Tomcat (tc Server), serveur d’application supportant la technologie OSGI (dm Server), développement d’un atelier logiciel entièrement AOP (Spring Roo), absorption du langage Groovy et du Framework Grails. Plein de choses très intéressantes en fait, mais pour le Framework Spring, rien de très révolutionnaire.

En revanche, le discours de Spring Source concernant JEE (qu’ils continuent à appeler J2EE) ne bouge pas d’un iota. Comme si JEE 5 n’était jamais sorti. Preuve en est cette keynote de Rod Johnson datée du 5 décembre 2009 (5 jours avant la sortie officielle de Java EE 6) dans laquelle il continue à expliquer que JEE c’est compliqué : http://www.infoq.com/presentations/Lessons-Learned-from-Java-EE

Les Rendez-vous manqués de Spring

En déroulant à nouveau toute cette histoire on remarque un certain nombre d’occasions en or manquées par Springsource pour dépasser son statut de standard de fait et devenir un standard tout court. Lors du design d’EJB3 par exemple ou lors du lancement de la spécification CDI, il aurait était facile de faire comme JBoss et venir « imposer » Spring comme implémentation du standard. Au lieu de ça, Rod Johnson et son équipe sont restés sur une attitude très défensive et un discours de moins en moins crédible de dévalorisation du standard JEE au fur et à mesure que celui-ci devenait une alternative de plus en plus réelle à Spring.
Ce qui suit est très subjectif, mais voici les points qui selon moi ont fait défaut à Spring pour pouvoir jouer cette partition :

1. L’adoption tardive des annotations

Spring a attendu sa version 2.5 en novembre 2007 pour commencer à utiliser (et encore partiellement) les annotations introduites par java SE 5.0 en septembre 2004. Soit plus de 3 ans pour adopter ce complément à la pure configuration XML. Je ne vais entrer dans débats XML vs annotations, pour moi les deux sont utiles et ont leur cas d’utilisation. Spring se voulant un Framework ouvert et laissant le choix à ses utilisateurs, ils auraient du adopter les annotations dès la version 2.0. L’absence d’annotation rend les gros projets Spring assez compliqués à appréhender par des nouveaux venus. Le fait d’avoir la configuration séparée du code c’est un peu comme monter un meuble en ayant scotché le plan de montage sur le plafond de la pièce voisine : pas très pratique.

2. La négation d’EJB 3

La première version de Spring supportant EJB3 est la version 2.51 de début 2008. Les versions antérieures ne supportent que EJB 2.X. Quand on sait que les premières versions stables d’EJB3 sont apparues courant 2005, on constate là aussi un décalage de trois ans pour prendre en compte une technologie majeure qui plus est partiellement concurrente. Quand on compare avec les quelques mois qu’il a fallu à JBoss pour intégrer un vrai support Spring à Seam, ça laisse rêveur.

3. La posture anti Stateful

Une grosse différence entre les EJB3 / CDI et Spring c’est l’existence de composants stateful dans EJB3. Sans rentrer dans les détails, l’approche stateful permet de décorréler le cycle de vie du composant de celui de l’application, permettant de créer facilement des contextes différents comme le contexte conversation ou le contexte Business dans Seam. Spring permet d’obtenir à peu près le même résultat mais sans technologie stateful, pourtant l’équipe a passé beaucoup de temps à décrier l’approche d’EJB3 pour valoriser leur produit. S’embarquer dans des débats obscurs et manifestement idéologiques quand on doit donner une lecture claire de sa stratégie et de ses outils ne paraît pas être la meilleure stratégie qui soit.

La stratégie Spring ?

On peut se demander si tous les choix de Springsource participent d’une stratégie et si le fait se tenir à l’écart de JEE est un choix murement réfléchit. On trouve un début de réponse à cette question ici : http://blog.springsource.com/2007/11/09/a-response-to-ejb-3-and-spring-comparative-analysis/

En gros pour résumer ce long échange, Spring ne souhaitait pas s’intégrer dans le JCP pour ne pas figer leur Framework. En effet, vu le rythme de livraison des nouvelles spécifications (en moyenne 3 ans), on pourrait craindre en s’attachant au JCP de ne plus avoir le contrôle sur son produit ou devoir attendre 3 ans avant de faire normaliser ne nouvelle version. L’approche de JBoss avec Hibernate puis Seam montre qu’il est parfaitement possible de jouer sur les deux tableaux en faisant normaliser un sous ensemble de l’outil et en ayant des extensions que l’on eut faire évoluer en dehors de la spécification. Seam 3.0 est un parfait exemple : le framework devient une collection de modules d’extension à CDI pour reproduire ce que faisait Seam 2.X mais sur la base de spécification CDI. Ces modules constituant Seam 3 semblent en théorie pouvoir interagir avec n’importe quelle implémentation de CDI et ne seraient donc pas spécifiques à l’implémentation de référence Weld.

De plus Java EE6 adresse cette problématique de “lenteur” dans le cheminement des spécifications en intégrant désormais la notion de “profiles”. Un profil est grosso-modo est un ensemble de technologie et de framework ou de technologies mis en oeuvre de manière conjointe pour créer un environnement applicatif bien spécifique. La création d’un nouveau profil au sein de Java EE6 se fait indépendamment de l’évolution de la spécification Java EE, on peut donc en quelques mois créer et proposer un nouveau “profile”. Les risque de “figer” son framework pour 3 ou 4 ans en l’intégrant a Java EE disparaît totalement si on intégrer celui-ci dans la logique des “profiles”.

L’équipe Spring n’a manifestement pas envisagé les choses sous cet angle et s’est contentée de rester sur « le standard de fait » sans se donner la peine d’aller plus loin.
En fait il s’avère qu’en la matière Spring ne semble pas avoir de stratégie ou alors une stratégie très brouillée. La meilleure illustration de cet à-peu-près est certainement la péripétie de la JSR 330 (@inject)

La spécification @Inject, panique ou obstruction ?

Petit rappel des faits : en mai 2009 soit 3 mois avant la release de JEE 6, Rod Johnson et Bob Lee (de Google) interpellent le JCP concernant la spécification CDI (démarrée 3 ans auparavant), la décrétant trop lourde et ne prévoyant pas une solution simple d’injection de dépendance. Ils proposent une autre spécification basée sur un ensemble d’annotations simples dont le fameux @Inject pour normaliser l’injection de dépendance en Java. Dans l’absolu, on ne peut évidemment pas leur donner tort : Gavin King a bien mené sa barque et a piloté une spécification très (trop ?) complète allant même jusqu’à intégrer un mécanisme évènementiel pour dispatcher des messages au sein des composants. On est bien au delà de l’injection légère que des frameworks comme Spring ou Google Guice proposent.

Là où l’initiative de Rod Johnson et Bob Lee est franchement discutable, c’est qu’elle intervient 3 mois avant la date de sortie de Java EE 6. Là où la plupart des spécifications de Java EE 6 ont mis trois ans à cheminer. De plus, Google et Spring avaient toute latitude de se joindre à l’expert group de CDI en 2006 plutôt que de débouler avec une spécification express au moment de la livraison.
Le résultat est une spécification @Inject mal ficelée, dont les implémentations risquent de diverger et un retard de 3 mois pour JEE 6. On a évité la catastrophe d’avoir deux spécifications sur l’injection de dépendance incompatibles puisque l’expert group de CDI a accepter de prendre en compte @Inject dans CDI.

Cet épisode qui pourrait être considéré au pire comme du sabotage ou au mieux comme une réaction de panique, n’est vraiment pas très glorieux pour Spring (et Google dans une moindre mesure) et a globalement eu pour effet de jeter le discrédit sur les commentaires négatifs de Rod Johnson concernant Java EE 6.

Spring pas un standard officiel et alors ?

Aujourd’hui, Spring est un standard de facto. Des centaines de milliers de développeurs dans le monde utilisent cet excellent Framework avec beaucoup de succès. Pourquoi se soucier de sa standardisation ?
Le premier point de réponse est lié à l’historique de Spring : cet outil est né pour palier à un gros défaut dans le standard officiel et proposer une vraie solution de conteneur de composants léger. Dés lors que le standard est corrigé, la raison d’être de l’outil s’estompe et même si sa popularité et sa qualité en font toujours un choix de prédilection, il rentre en concurrence avec une solution officielle équivalente, là où il aurait pu être ce standard.

Le deuxième élément est lié à la gouvernance de Spring. Comme on l’a vu la stratégie de Vmware n’est pas très claire et aujourd’hui seule une demi douzaine de cerveaux géniaux contribuent réellement à ce Framework. Tout cela apparaît plutôt fragile et à partir du moment ou une alternative plus universelle existe, il paraît raisonnable de s’y intéresser pour éviter d’être captif d’une société en l’occurrence, VmWare.
En prenant, le problème par l’autre bout on peut s’interroger sur les raisons qui ont pu retenir Spring de prendre cette voie de la standardisation. Franchement, en dehors du boulot énorme que doit représenter l’animation d’une telle spécification, je ne vois que des points positifs : l’évincement d’une solution concurrente, le ralliement des personnes n’ayant pas choisi Spring et la réassurance des utilisateurs existants. Bien sûr en transformant Spring en spécification, la société prenait le risque de voir d’autres implémentations concurrentes apparaître, mais avec l’avance de l’équipe de Rod Johnson, Spring aurait gardé le lead sur cette technologie comme Hibernate reste l’implémentation de JPA la plus utilisée même si eclipse link est l’implémentation de référence de JPA 2.0.

Quel avenir pour Spring ?

Bien sûr, il n’est pas question de prédire la fin de Spring. Le Framework est bien implanté et continu à remplir sa mission avec succès. Néanmoins, il est toujours mauvais signe quand un outil de ce genre n’est pas choisi parce qu’il constitue la meilleure solution mais parce que prendre une autre solution couterait trop cher en formation et en gestion du changement.

Quoiqu’il en soit Java EE 6 et CDI ont beaucoup de chemin à parcourir pour devenir populaire. L’hostilité d’un certain nombre de développeurs aux productions de Redhat et l’inertie naturelle des organisations pour adopter de nouvelles technologies sont ses pires ennemis. Mais il est tout de même fort probable que cette spécification rencontre un beau succès, la taille de la communauté Seam en est la meilleure preuve.
Concernant Spring si CDI parvient à convaincre et commence à prendre de l’ampleur, le Framework de VMware risque d’avoir à s’aligner sur cette spécification pour en devenir une implémentation au risque de se marginaliser. Auquel cas, il perdrait une partie de son leadership et deviendrait suiveur sur une technologie dans laquelle il était l’un des premiers acteurs.

Si CDI reste lettre morte, Spring pourra poursuivre sereinement sa carrière de leader dans le monde des conteneurs légers sous Java. Mais le pari est très risqué et au vu du besoin d’avoir une pile de framework officiels sous Java, Vmware n’est pas du tout assuré de le gagner.

Remerciements

Merci à Emmanuel Bernard (@emmanuelbernard) qui a bien voulu répondre à mes quelques tweets sur la genèse d’EJB3.

Bibliographie

    • Le site du JCP :
    • Présentation Paris JUG JEE6 & Spring (08/12/09) par Antonio Goncalves et Michael Isvy :