Patterns J2EE / EJBDate de publication : 01/02/2003 , Date de mise a jour : 14/03/2005
Patterns J2EE / EJB Introduction 1. Le modèle de données 2. Accéder à la base de donnée 3. Local et Remote Interfaces 4. Session Façade 5. Value Objects 6. Service Locator 7. Business Delegate 8. External SC VO Cache 9. L'architecture Références Introduction
« Mon application ne vas pas assez vite! » « J'ai besoin de supporter plus d'utilisateurs simultanés ! » « Ma base de donnée n'est pas suffisamment rapide ! » « Dois-je changer de serveur d'application ? »
Prenez un groupe de développeurs, réunissez-les pour discuter de votre application. La meilleure façon d'attirer l'attention de vos collègues et les faire venir a votre réunion ? Incluez l'un des deux mots magiques suivant : Sécurité et Performance.
Quelle que soit l'application, la performance est toujours une question primordiale. Plus exactement, la question est de savoir comment obtenir un niveau de performance satisfaisant en gardant les coûts minimums.
Lorsque quelqu'un énonce un problème de performance pour son application, une attitude courante est de blâmer son système d'exploitation, son serveur d'application, ou sa base de donnée. Pourquoi ? Parce qu'il est difficile de se blâmer soi-même. Pourtant, un grand nombre de problèmes de performance est dû au développeur ou à l'architecte.
Dans ce document, je présente certains patterns, indispensables au développeur J2EE. Pour nous aider dans cette tâche, supposons que nous essayions de construire un forum, comme celui de www.developpez.com.
1. Le modèle de données
Nous allons utiliser une base de donnée (BD) pour stocker les messages postés par les gentils utilisateurs. Dans un monde idéal :
Notre forum sera amplement plus simple et moins sophistiqué que celui de www.developpez.com, il ne contient que deux types d'objets :
![]()
Le modèle présenté est une façon simple de représenter notre système. Nous avons une relation one-to-many entre POST et FORUM, ce qui signifie qu'un FORUM peut contenir plusieurs POSTs. Un POST à un POST parent, c'est notre façon de représenter un fil (suite de POSTs).
2. Accéder à la base de donnée
L'un des énormes avantages d'utiliser J2EE est la possibilité d'acheter une partie de son système plutôt qu'avoir à le construire soi-même. Il existe deux moyens de réaliser la persistance en utilisant les EJB
La seconde solution (CMP) offre de nombreux avantages, en particulier portabilité, rapidité de développement, performance et robustesse. Préférez-les autant que possible.
3. Local et Remote Interfaces
Il existe deux moyens d'accéder à un EJB, en utilisant :
4. Session Façade
Voici sans doute le pattern J2EE le plus utilisé. Le problème est le suivant : Chaque appel distant est coûteux, il faut trouver un moyen de les limiter. Une Session Façade est un session bean qui a accès aux interfaces locales d'autres beans (parce qu'il vit dans la même JVM). Un appel à une méthode d'un Session Façade entraîne généralement plusieurs appels vers un ou plusieurs autres beans.
Supposons par exemple le cas suivant : Un modérateur veut déplacer un fil (série de POSTs) d'un FORUM vers un autre.
Nous avons ces étapes
Le modérateur ne veut se soucier que du fait qu'il déplace un fil. Notre Session Façade va posséder la méthode deplaceFile qui prend comme argument l'identifiant d'un POST.
![]()
Le réseau se trouve entre le serveur WEB (Servlet Container, ou SC) et la Façade. Les appels entre Façade et POST CMP sont locaux. Notre opération ne requiert qu'un seul appel distant, quel que soit le nombre de POSTs à déplacer.
De façon générale, c'est un bon exercice de ne pas générer d'interfaces distantes pour ses EJB persistants. En d'autres termes, une façade porte bien son nom, un mur entre application et persistance.
Notre façade pourrait faire tout un tas d'autres choses, comme par exemple vérifier l'autorisation de l'utilisateur qui a instancié la requête. Une façade peut aussi appeler d'autres Session Beans ou Message Driven Beans. La leçon à retenir étant qu'il faut limiter le nombre d'appels distants.
5. Value Objects
Le Session Façade Pattern présenté plus haut implique un challenge supplémentaire. Puisque nous n'avons pas de référence directe à notre objet persistent, comment allons-nous lire le contenu d'un objet ? Heureusement, cette limitation à une solution très simple, et qui ajoute même de nombreuses possibilités d'amélioration. Le Value Object n'est autre qu'un objet qui offre une vue figée de notre entité à un moment donné. Voyons un exemple de code :
Le mot clef ici est Serializable. En effet, ce Value Object (VO) est l'objet que nous ferons traverser le réseau. Il est donc nécessaire que l'objet et tous ces membres soient Serializable. Grâce au VO, nous pouvons accéder aux membres de notre entité sans faire d'appels répétés à notre EJB persistant. 8
Un EJB persistant utilise une clef primaire pour identifier une entité, notre VO va utiliser cette même clef pour s'identifier. Une clef primaire pour un EJB à des règles strictes à suivre, dont :
Notre exemple de code est légèrement simplifié, nous verrons plus tard qu'une bonne idée est pour un VO d'implémenter une interface (par exemple nommée VO) qui ne défini aucune méthode ni variable. Nous verrons qu'un VO est un excellent candidat pour être mis en cache, et ainsi démultiplier nos performances. Mais avant ça, il nous reste deux trois points à voir afin de rendre notre application plus solide.
6. Service Locator
Le client, quel qu'il soit : GUI, Servlet container (SC) ou autre a besoin d'un moyen de localiser les objets distants, en l'occurrence notre Session Façade. Le service de nommage couramment utilisé avec J2EE est JNDI, la méthode à suivre est simple et supposée connue. Malgré tout, dans le but de rendre notre système flexible et ré-utilisable, nous définissons un Service Locator, dont le seul but est de servir au client des Home interfaces, par exemple en implémentant un pool. Notre service locator est simple et n'implémente qu'une seule méthode : getPostFacade() : PostFacade
Un Service Locator est un bon candidat pour le Singleton Pattern.
7. Business Delegate
En voilà un joli nom, n'est-ce pas ? Pas de panique, ce pattern n'est autre qu'une adaptation du pattern Wrapper (ou Adapter) bien connu, appliqué au modèle J2EE. Son but est multiple :
Voici un exemple d'implémentation de méthode dans notre Delegate :
La méthode nous retourne le Value Object (VO) dont nous avons parlé plus haut. Elle s'occupe de chercher le cache, loguer les erreurs et transformer l'exception en quelque chose d'acceptable pour notre client. Une servlet par exemple peut maintenant appeler cette fonction et ne jamais savoir tout ce qui se passe derrière le rideau. Ce type d'architecture permet d'efficacement définir les rôles dans une équipe, un développeur pour les EJB, un pour les servlets. Utilisez ce pattern sans modération. 8. External SC VO Cache
À ce stade du design, nous avons un système solide, portable, robuste et flexible. Que demande le peuple ? La performance. Ou comment donner des ailes à cette belle application. La solution n'est pas nouvelle : utiliser un cache. Cela repose sur un fondement simple : la mémoire ne coûte pas cher. Ajouter une barrette de mémoire à votre machine peut diviser par 10 ou 100 le nombre d'appels via JDBC, suivant le type d'application, et d'expérience, une proportion non négligeable des problèmes de performance est due aux très chers appels à la BD. Prenez un cas typique d'application où à chaque visite sur votre site Web, un utilisateur engendre 10 appels à la base de données. Au fur et à mesure que votre site se popularise, lorsque le nombre d'utilisateur est multiplié par 10, le nombre d'appel à la BD est multiplié par 100. À ce rythme, ajouter une machine à votre île de BD n'est qu'une solution très temporaire, même s'il est vrai que la BD elle-même a son propre système de cache. Notre solution consiste à installer un système de cache au niveau de notre Servlet Container (SC). Maintenant, lorsque le nombre d'utilisateur est multiplié par 2, ajoutez un SC. Les SC sont peu chers, beaucoup moins que les BD ou les EJB containers. Nous n'utiliserons nos EJB que si le résultat attendu n'est pas dans le cache. Il est possible que votre vendeur propose déjà ce service, auquel cas, il ne vous est pas nécessaire de l'implémenter.
Que contient le cache ? Le cache peut être aussi simple qu'une Hashtable dont la clef est la clef du VO (Key). Le cache implémente le pattern Singleton (voir remarque plus haut). Nous avons déjà vu brièvement que chaque Value Object devrait implémenter l'interface VO, et chaque Key (comme PostKey) devrait implémenter l'interface Key. Cela va nous permettre de définir la méthode suivante dans notre cache :
Une fois cette méthode implémentée, c'est le moment de la référencer dans notre Business Delegate. Réécrivons notre Business Delegate de la sorte :
Et voila, il ne nous reste plus que deux détails a régler
Limiter la taille de notre cache consiste à utiliser une version améliorée de Hashtable, qui se débarrasse des objets qui n'ont pas servi depuis longtemps, au profit de nouveaux objets. La technique ici est largement variable, et dépend grandement de votre application. Par exemple, faites le ménage à chaque fois que la limite supérieure de taille est atteinte. Ou bien implémenter un système de compteur pour se débarrasser des objets les moins usités.?
Plus délicat est le problème de s'assurer qu'il n'existe pas d'objet invalide dans notre cache. Et voici le challenge : notre cache est sur un SC, distant de notre EJB container. L'EJB n'a aucun moyen d'appeler une méthode sur notre SC. Qu'à cela ne tienne. Nous allons utiliser JMS pour réduire ce problème a néant. Définissons un Topic dans notre EJB containeur. L'EJB persistent va jouer le rôle du Publisher, et placer des messages sur ce Topic, à chaque fois qu'il réalise un update (voir spec. EJB).
Notre cache, elle, va s'inscrire comme Listener de ce Topic, et recevoir des messages d'invalidation, qui, vous l'avez compris, contiennent la clef de l 'objet à invalider. Le cache définit la méthode suivante :Ø
qui ne fait rien d'autre que d'enlever l'objet de notre cache.
9. L'architecture![]() Références
|
Les sources présentées sur cette page sont libres de droits, et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une oeuvre intellectuelle protégée par les droits d'auteurs. Copyright © 2005 Christophe Ludet. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à 3 ans de prison et jusqu'à 300 000 E de dommages et intérêts. Cette page est déposée à la SACD.