Rappels sur JEE 5

Rappels sur JEE 5

Le codage des EJB a été largement simplifié avec la spécification EJB 3. Les mécanismes de base sont les mêmes : RMI,  JNDI, pas d’invocation directe des méthodes des EJB, cycle de vie de l’EJB géré par le conteneur. Les EJB 3  sont basés  sur de  simples  classes  POJO  (Plain  Old  Java  Object,  objet  de  base  type  JavaBean).  L’interface  Home  de  création  a  disparu  et  le  fichier  XML  ejb-jar.xml  décrivant  le  composant  n’est  plus  obligatoire.  Cette  simplification  est  liée  à  l’évolution  du langage  (apparition  des  annotations  avec  Java  5)  et  aux  bénéfices issus  des  travaux sur les frameworks Spring, Hibernate… Les  différents  services  d’une  application  doivent  pouvoir  se  localiser.  Cette  opération  peut  prendre  de  multiples  formes : ● création d’un objet et utilisation directe de celui­ci ; ● recherche du service en utilisant JNDI ; ● emploi de fabrique pour créer le service ; ● implémentation des services comme singleton. Le  code  client du  service peut, alors, devenir  très vite  significativement dépendant de l’implémentation,  ou  vite  peu  lisible par le codage des recherches. Cette localisation est effectuée classiquement par l’intermédiaire de JNDI sur les  serveurs d’application. Les dépendances peuvent être éliminées en confiant à un tiers le soin de mettre en relation les objets, c’est l’inversion  de contrôle. Les composants sont, alors, reliés automatiquement avant leur utilisation. Pour  bien  comprendre  comment  les  conteneurs  JEE 5  gèrent  le  cycle  de  vie  des  composants,  il  est  primordial  de  comprendre les implémentations possibles du pattern Inversion of Control (IoC), appelé aussi Dependency Injection. L’inversion  de  contrôle  (IoC  ­ Inversion  of  Control)  n’est  en  rien,  une  évolution  du  langage.  C’est  un  modèle  de  conception  qui  propose  de  séparer  les  problématiques  techniques  (aspects)  des  problématiques  métier  dans  une  application. C’est une application tiers, le framework, qui mettra en liaison les objets. 

Les annotations

Le  système des annotations est une des évolutions importantes apportées par Java 5, puis enrichies par Java 6.  C’est une véritable alternative aux fichiers de configuration XML et aux outils tiers tels que XDoclet. La maintenance  est  largement  simplifiée  car  la  prise  en  compte  des  changements  dans  le  code  source  est,  directement,  sous  la  responsabilité des outils du langage, ou des conteneurs, sans avoir à synchroniser un fichier XML ou à réeffectuer  une compilation avec XDoclet. Les annotations sont des métadonnées ajoutées au code. Le développeur ajoute les annotations au code source et  elles peuvent se propager jusqu’à l’exécution. Il  existe,  dans  la  spécification  des  annotations,  des  « super  annotations »  :  les  méta­annotations,  qui  permettent  d’annoter les annotations. Ces méta­annotations sont situées dans le package java.lang.annotation. L’ensemble  des  annotations  (et  méta­annotations)  utilisables  avec  le  JDK 6  héritent  de  l’interface  java.lang.annotation.Annotation. Les conteneurs, dont JBoss, ajoutent leur propre jeu d’annotations. Méta­annotation Objectif @Documented Indique à l’outil javadoc qu’il doit prendre en compte  cette annotation. @Inherited Permet l’héritage entre annotations. @Retention Détermine la politique de propagation de  l’annotation. @Target Détermine la cible de l’annotation.  La méta­annotation @Retention permet de fixer le mode de propagation de l’annotation. RetentionPolicy.SOURCE : les annotations ne seront pas enregistrées dans le  fichier  *.class. Elles sont utilisables  par les outils manipulant les fichiers sources (compilateur, javadoc…). Exemple : l’annotation standard @Overrides. RetentionPolicy.RUNTIME  :  les  annotations  sont  enregistrées  dans  le  fichier  *.class  et  sont  accessibles  par  la  machine  virtuelle,  lors  de  l’exécution.  Ces  annotations  sont  utilisées  via  l’API  de  réflexion.  Les  annotations  JBoss  (comme @LocalBinding) sont du type RetentionPolicy.RUNTIME. RetentionPolicy.CLASS : les annotations sont enregistrées dans le fichier *.class. Elles ne sont pas utilisées par la  machine virtuelle, mais peuvent l’être par les outils manipulant les fichiers *.class. L’injection  de  dépendance  utilise les  annotations  et la  réflexion.  Un  exemple  simple  permet  de mieux  comprendre  comment les conteneurs peuvent injecter dans les membres de nos classes les ressources voulues (EJB, source de  données…). L’ensemble des fichiers sources qui suivent sont téléchargeables sur le site ENI, sous le projet Annotations. Il nous faut d’abord créer notre propre annotation : package fr.eni.editions.jboss.annotations; import java.lang.annotation.*; @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.FIELD}) public @interface Message { String value(); } Le type de notre annotation Message est @interface. Il possède une méthode value() qui représente un attribut de  notre annotation. Nous pouvons, maintenant, utiliser notre annotation dans la classe TestMessage : package fr.eni.editions.jboss.annotations; public class TestMessage { @Message(« Hello world ») private String monMessage; public void afficher() { System.out.println(« Valeur du message : « +monMessage); } } Il  n’y a qu’une  seule méthode dans notre annotation :  value(). Nous pouvons donc éviter de préciser le nom de  l’attribut de Message. Si cela n’avait pas été le cas, nous aurions dû avoir : @Message(value= »Hello world ») private String monMessage; L’objectif  de  l’utilisation  de  notre  annotation  est  donc,  d’injecter  la  valeur  de  l’attribut  value  de  Message  dans  la  propriété  monMessage  de  TestMessage.  Cette  injection  est  effectuée  par  une  application  tiers,  en  général  un  framework. Dans notre exemple il s’agira d’une simple classe. Nous devons donc maintenant, coder l’injection : package fr.eni.editions.jboss.annotations; import java.util.*; import java.lang.reflect.*; public class MessageProcess { // code permettant l’injection de dépendance public static void injecter(Object obj) throws Exception { for(Field field : obj.getClass().getDeclaredFields()) La méthode injecter(Object obj) de la classe MessageProcess permet de réaliser cette injection. Pour chaque champ  field de l’instance obj, il y a vérification de la présence de l’annotation. Si c’est le cas, la valeur de l’attribut value de  l’annotation est récupérée pour mettre à jour le champ. C’est l’application qui mettra en œuvre l’injection : package fr.eni.editions.jboss.annotations; public class Main { public static void main(String[] args) throws Exception { TestMessage test = new TestMessage(); MessageProcess.injecter(test); test.afficher(); } } Cet exemple permet de mieux comprendre comment les conteneurs compatibles avec les spécifications JEE 5 peuvent  automatiquement utiliser les annotations pour mettre des ressources dans un contexte JNDI, injecter des ressources  du contexte JNDI vers les membres de nos classes. 2. Injection par proxy La journalisation, les messages de debug, les autorisations, les transactions sont des problématiques récurrentes en  programmation. Si nous prenons l’exemple d’une journalisation, il nous faut une classe qui permette la journalisation,  appelée ici Logger, et une qui utilise la journalisation, Service. Les méthodes ayant besoin de journaliser appelleront  les méthodes de la classe Logger. Cela sera identique pour toute classe utilisant la journalisation. package fr.eni.editions.jboss.aop; public class Logger { public void debutLog() { System.out.println(« début de journalisation »); } public void finLog() { System.out.println(« fin de journalisation »); } } package fr.eni.editions.jboss.aop; public class Service { Logger logger = new Logger(); public void executer() { logger.debutLog(); System.out.println(« >> Méthode ’executer()’ »); logger.finLog(); Cette illustration peut être appliquée à l’authentification, les transactions, etc. Nous voyons ainsi notre code émaillé  d’appels vers des méthodes de classes qui n’ont rien à voir avec notre code métier. Ces appels peuvent nuire à la  lisibilité de nos méthodes métier. Une dépendance est  créée entre des  classes qui a priori n’ont  rien  à  voir  entre  elles. Les services de journalisation, authentification… sont des services transversaux à notre application. Pour  supprimer  les  dépendances  entre  ces  classes,  un  des moyens  est  de  déléguer  à  un  framework  l’appel des  méthodes.  Nous  illustrerons  ceci  par  l’exemple  de  la  mise  en  place  d’un  proxy,  dont  la  méthode  invoke()  sera  appelée avant la méthode executer() de notre classe Service.

Formation et coursTélécharger le document complet

Télécharger aussi :

Laisser un commentaire

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