avril
2008
Avec la multiplication des composants dans les diverses couches d’une application Java EE (EJB dans la couche metier et persistance, Managed Beans dans la couche Web, etc.), on avait pensé à les unifier dans Java EE 6 en un type de composants unique qui est les WebBeans (JSR 299).
Le Spec Lead de cette proposition, Gavin King, a récemment fait une présentation sur l’etat d’avancement actuel des WebBeans en Australie (vidéos disponibles ici).
En se basant sur ces vidéos, ce billet va présenter rapidement les principales fonctionnalités des WebBeans.
Le but des WebBeans est de:
- proposer un modèle de programmation à état ou contextuel compatible avec les EJBs et les managed beans.
- proposer un modèle extensible.
- pouvoir bénéficier de lookups (JNDI), de DI et de résolution via EL.
- un modèle conversationnel pour le web.
- Bénéficier d’interceptors (sous partie d’AOP)
- un modèle evenmentiel.
- Intégration avec JSF, JPA et les servlets.
- Intégration avec la notion de profiles du futur Java EE 6
En ce qui concèrne la compatibilité, les WebBeans devraient permettre de:
- pourvoir transformer un EJB en WebBean par le simple ajout d’une annotation
- pourvoir transformer un Managed Bean en WebBean par le simple ajout d’une annotation
- un WebBean peut intéropérer avec les EJBs
- un EJB devrait interopérer avec les WebBeans
Assez de théorie maintenant, et place à un peu de pratique.
Voici un exemple de WebBean tout simple:
public @Component class Hello { public String hello(String name){ return "Hello "+name; } }
Notez l’annotation @Component (identique à celui de Spring) qui permet d’exposer une classe en tant que WebBean.
Voici maintenant une classe qui utilise le bean qu’on vient de définir (Hello)
public @Component class Printer { @Current Hello hello; public void print(String name){ System.out.println(hello.hello("World")); } }
Tout comme Hello, Printer est un WebBean (@Component) mais qui plus est, bénéficie de DI (Injection de Dépendances) et a son membre hello automatiquement injecté par le conteneur, grâce à l’annotation @Current.
La DI va encore plus loin avec la DI par constructeur, i.e. quand on définit un WebBean sans constructeur par défaut, il conteneur va injecter tous les paramètres du constructeur.
Enfin, y’a aussi la DI via méthode d’initialisation, où on définit les diverses dépendances comme paramètres à une méthode annotée par @Initializer, et le conteneur fera le reste.
Une fois défini, un WebBean peut être nommé pour pouvoir y accéder depuis l’EL par exemple:
public @Component @Named("hello") class Hello { public String hello(String name){ return "Hello "+name; } }
Notez l’annotation @Named pour spécifier le nom,
<h:commandButton action="#{hello.hello}" />
Maitenant, pour ce qui est du lookup, c’est à dire comment laisser le client choisir une implémentation à injecter depuis plusieurs autres, WebBeans y va à coupe de TypeSafety (à la Guice), c’est à dire qu’on utilise des types plutôt que des chaines. => C’est le Type Binding.
Justement, le @Current est un Type Binding, ou plutôt le Type Binding par défaut.
Par exemple, si on définit un nouvelle implémentation de Hello, du genre:
public @Casual @Component class Bonjour extends Hello { public String hello(String name){ return "Bonjour "+name; } }
où @Casual est une annotation qu’on définit soi-même, et que dans le client (Printer) on utilise @Casual au lieu de @Current, alors c’est la classe Bonjour qui se retrouve injectée au lieu de Hello.
Seuelemnt, cette approche nécessite de modifier et de recompiler son code pour changer d’implémentations, entre la phase développpement par exemple et la phase de production.
Ca empire encore dans un grand projet, où on dénombre des centaines/milliers de telles injetions.
C’est là qu’entrent en jeu les Deployment types et le @Current.
Il faut procéder comme suit:
– Annoter toutes ses dépendances par @Current.
– Annoter les implémentations possibles par divers Binding Types, par exemple @Mock lors du développement/test et @Production pour la production.
– Ajouter un framgement XML qui spécifie quels Binding Types utiliser pour résoudre les ambiguités et dans quel ordre le faire.
<web-beans>
<component-types>
<component-type>javax.webbeans.Production</component-type>
<component-type>djo.types.Mock</component-type>
</component-types>
</web-beans>
Place maintenant aux scopes. Comme enoncé plus tôt, les WebBeans peuvent accéder aux scopes web ainsi qu’à d’autres.
Le choix du scope se fait en ajoutant une annotation comme @Dependant (prototype), @RequestScoped, @SessionScoped, et même @conversationScoped pour JSF par exemple. Il y’a aussi la possibilité pour définir ses propores scopes.
Une autre fonctionnalité impressionnante des WebBeans est les producers. Si on annote une méthode un retourne un Objet de type X par @Produces, alors il devient possible d’injecter le résultat d’une telle méthode dans un autre bean, comme si c’etait défini en tant que composant à part entière.
Exemple:
@Produces @SessionScoped public User getConnectedUser() { .... }
Ensuite, dans un autre compsoant:
@Current User user.
Alors le conteneur va appeler la méthode getUser et injecter son résultat dans user.
Voilà, c’etait une présentation rapide des principales fonctionnalités de la proposition WebBeans/JSR 299.