Résumé Cet article discutera avec vous comment combiner la puissance des annotations et des aspects pour fournir des services déclaratifs aux entreprises de manière compatible avec EJB 3.0 tout en fournissant l'indépendance des conteneurs.
1. Introduction
Dans notre recherche conjointe des moyens d'améliorer encore les performances de production du développement de logiciels, nous - en tant que membres de la communauté Java - nous nous tournons généralement vers J2EE pour fournir des problèmes techniques plus difficiles dans le développement des entreprises tels que la gestion des transactions distribuées, la concurrence et les solutions de distribution d'objets. L'idéologie directrice derrière elle - ces services d'entreprise complexes peuvent être implémentés par les fournisseurs de serveurs d'applications et équilibrés par des développeurs commerciaux - est en effet une bonne idée. J2EE, en particulier EJB, a réussi une plate-forme sur laquelle les applications Java d'entreprise sont construites.
Une partie de ce succès est due à la capacité d'effectuer une programmation déclarative - un moyen de développer un programme - dans lequel vous pouvez déclarer des services d'infrastructure au lieu d'être explicitement codés avec une logique métier afin que le code soit réparti partout. EJB a prouvé la valeur de cette approche de programmation - en permettant aux problèmes d'entreprise tels que les transactions et la sécurité soit déclarés avec un descripteur de publication et géré par un conteneur.
Cependant, au cours des dernières années, de plus en plus de développeurs ont réalisé que l'EJB se présente beaucoup de nouveaux défis dans la productivité d'une équipe - chaque EJB doit être accompagné de multiples interfaces, avec une description de descripteur de publication, accessible via JNDI, etc. Les tests unitaires sur EJB en dehors du conteneur apportent également des difficultés supplémentaires.
Veuillez noter que pour lire cet article, vous devez avoir les outils suivants:
· Java 2 SDK 1.5
· Maven 2.0 Beta 2
L'objectif de l'EJB 3.0 est de faciliter le développement des entreprises dans les aspects suivants:
· Implémenter les demandes déclaratives de services d'entreprise en introduisant des annotations de métadonnées
· Implémentez la dépendance / injection de ressources via l'annotation
· Implémentez le découplage des haricots d'entreprise et des interfaces spécifiques à l'EJB
· Simplification du stockage continu grâce à la cartographie légère d'objet-relation
C'est comme une brise de printemps pour les développeurs EJB - ils ont travaillé dur pour développer, tester et maintenir l'EJB. Il est désormais facile d'écrire un Bean Enterprise en utilisant EJB 3.0, tout comme la création d'un POJO (objet Java traditionnel) avec des annotations spécifiques pour le marquer en tant que services d'entreprise EJB et demandes. Voici un exemple de l'EJB dans EJB 3.0 Public Draft:
@Stateful
Classe publique Cartbean implémente ShoppingCart
{
Total flottant privé;
codes de produits vectoriels privés;
public int someshoppingMethod () {...};
...
}
La déclaration EJB 3.0 indique essentiellement que ce dont les développeurs ont besoin n'est pas un poids lourd, une solution "One Release Seutry Everything", mais une solution légère et facile à utiliser - offrant aux développeurs une certaine gamme de services d'entreprise. À cette fin, l'une des méthodes les plus importantes fournies par EJB 3.0 est de découpler les haricots d'entreprise et les API EJB. Et cette solution apporte également des dérivés intéressants - EJB peut désormais s'exécuter non seulement sur différents conteneurs EJB, mais également dans n'importe quel cadre d'application - ces cadres doivent être en mesure de reconnaître EJB 3.0 (JSR 220) et l'annotation normale pour déclarer les services d'entreprise (JSR 250) .
Cet article ne fournit pas une exploration approfondie de la programmation déclarative, des EJB, des aspects ou des annotations. Au lieu de cela, analysez simplement les interrelations entre ces technologies et discutez de la façon de les combiner d'une nouvelle manière pour simplifier le développement d'applications.
Dans cet article, vous apprendrez à rédiger un bean compatible EJB 3.0 et à créer plusieurs aspects simples pour rendre la gestion déclarative des transactions, la sécurité et l'injection de ressources. J'espère que vous pourrez bénéficier de cet exercice:
· Trois applications pratiques dans l'apprentissage (injection de dépendance, sécurité et transaction).
· Familière EJB 3.0 et les idées derrière.
Reconnaissez comment mettre en œuvre le découplage de l'EJB à partir d'API spécifiques pour permettre la mise en œuvre des services compatibles EJB 3.0 à la légèreté plutôt que fournis par EJB uniquement.
2. Exemple de commande de vol d'application
Tout au long de la discussion, vous découvrirez une mise en œuvre d'un système de commande de vol - qui utilise des aspects et des annotations pour mettre en œuvre l'injection de dépendance, la sécurité et la gestion des transactions. L'application remplit seulement deux fonctions: il permet aux utilisateurs de rechercher des vols (figure 1), puis de commander un voyage (figure 2). Les deux opérations seront traitées en toute sécurité pour permettre aux utilisateurs identifiés de les effectuer. De plus, étant donné que l'opération de «voyage de commande» implique de commander deux vols (vols et de retour sur les vols), l'opération doit être créée en tant que transactionnelle - par exemple, les deux commandes réussiront ou échoueront en tant qu'unité de travail.
Figure 1. Requête sur les vols: Premièrement, les utilisateurs recherchent des vols qui répondent à leurs critères spécifiés.
Figure 2. Commande de vol: Ensuite, l'utilisateur commande un vol sortant et un vol de retour. Les deux commandes réussissent ou échouent.
Cette application Web simple contient plusieurs servlets, une apparence de service et une couche DAO (voir figure 3).
Des préoccupations croisées telles que la configuration des ressources, la sécurité et la gestion des transactions seront fournies par des aspects (implémentés avec Aspectj 1.5 M3) pour mettre en œuvre le comportement d'injection déclaré dans Java 5 Annotations.
Figure 3. Architecture du système de commande de vol: Ce système de commande de vol se compose de trois composants principaux - ils se réunissent pour compléter les demandes des utilisateurs. 3. Injection de ressources
Le projet de déclaration EJB 3.0 permet de déclarer les ressources via l'annotation @Resource (cette décision est définie dans le projet de déclaration d'annotation ordinaire) et injectée dans votre EJB par conteneur. L'injection de dépendance est une technique - en utilisant cette technique, une entité en dehors d'un objet plutôt qu'une entité explicitement créée pour cet objet peut fournir (injecter) la dépendance d'un objet. Il est parfois décrit comme un principe hollywoodien - qui plaisante comme "Ne nous appelez pas, nous vous appellerons."
Prenez la classe TravelageCyServiceImpl à titre d'exemple - afin de stocker en continu certaines données, cette classe doit trouver une implémentation de l'interface iflightdao. Traditionnellement, cela est réalisé via une usine, un singleton, un localisateur de service ou une autre solution personnalisée. Parmi eux, une solution possible ressemble à ceci:
classe publique TravelagenServiceImplt implémente ittravelagencyservice
{
public iflightdao flightdao;
Public TravelageCyServiceImpl ()
{FlightDao = FlightDaofactory.getInstance (). GetFlightDao ();
public void booktrip (long sortboundflightid, long returnflightid, int sièges)
lance l'invalideSeatSexception
{
réserveSeats (sort-lighti, sièges);
réserveSeats (returnflightid, sièges);
}
}
Vous avez vu que cette implémentation implique la création d'une classe d'usine spécifique - il est susceptible de lire les informations de configuration stockées quelque part pour comprendre comment la mise en œuvre pour créer iflightdao doit être créée. Si le service ne crée pas explicitement ses dépendances injectées par le conteneur, les détails de la configuration et la création d'objets seront proxés dans le conteneur. Cela permet aux composants d'une application d'être facilement connectés ensemble - avec différentes configurations et élimine beaucoup de singleton et de code d'usine à l'ancienne.
Une implémentation de la classe - qui repose sur une implémentation d'IFlightdao déclarée avec l'annotation des ressources JSR 250 - peut ressembler à ceci:
classe publique TravelagenServiceImplt implémente ittravelagencyservice
{
@Resource (name = "FlightDao")
public iflightdao flightdao;
public void booktrip (long sortboundflightid, long returnflightid, int sièges)
lance l'invalideSeatSexception
{
réserveSeats (sort-lighti, sièges);
réserveSeats (returnflightid, sièges);
}
}
Dans ce cas, le conteneur fournira la mise en œuvre correcte d'une ressource nommée "FlightDao" vers la classe de service. Mais que se passe-t-il si vous souhaitez tirer parti de l'injection de ressources maintenant au lieu d'attendre la version EJB 3.0? OK, vous pouvez prendre un conteneur léger - il est capable de fournir des injections de dépendance telles que le printemps ou le conteneur PICO. Cependant, je ne comprends pas qu'il existe un conteneur léger - il est capable d'utiliser des annotations de ressources JSR 250 pour spécifier les exigences d'injection (bien que j'attends avec impatience certains à cet égard).
Une solution consiste à utiliser des aspects pour implémenter l'injection de dépendance. Si vous utilisez l'annotation @Resource pour cela, votre implémentation sera cohérente avec la manière EJB 3.0 et vers l'avant compatible avec l'implémentation EJB 3.0 - et ce n'est pas une chose très difficile à mettre en œuvre. La liste suivante montre un aspect créé avec AspectJ - il injecte des champs annotés avec @Resource Annotation:
@aspect
Injection de classe publique
{
Private DependencyManager Manager = New DependencyManager ();
@before ("get (@resource * *. *)")
Public Void AbofieldAccesses (joinpoint thisjoinpoint)
lance illégalargumentException, illégalaraccessException
{
FieldSignature Signature = (FieldSignature) thisJoinpoint.getSignature ();
Resource Injectannotation = Signature.getField (). GetAnnotation (ressource.class);
Object Dependency = Manager.Resolve Dependency (signature.getFieldType (), injectannotation.name ());
signature.getfield (). set (thisJoinpoint.getThis (), dépendance);
}
}
Tout ce simple aspect est interrogé la classe d'implémentation à partir d'un fichier de propriété (cette logique est encapsulée dans l'objet DependencyManager) et l'injecte dans les champs annotés avec @Resource Annotation avant d'accéder au champ. De toute évidence, cette implémentation n'est pas complète, mais elle illustre comment vous pouvez fournir une injection de ressources d'une manière compatible JSR 250 sans EJB.
4. Sécurité
En plus de l'injection de ressources, JSR 250 et EJB 3.0 fournissent également une représentation sécurisée de métadonnées via l'annotation. Le package Javax.annotation.Security définit cinq annotations - runas, rôlesallowed, permisall, denyall et rôles référencés - qui peuvent tous être appliqués aux méthodes pour définir les exigences de sécurité. Par exemple, si vous souhaitez déclarer que la méthode Bookflight répertoriée ci-dessus ne peut être exécutée que par les appelants avec le rôle "utilisateur", vous pouvez annoter cette méthode avec les contraintes de sécurité suivantes:
classe publique TravelagenServiceImplt implémente ittravelagencyservice
{
@Resource (name = "FlightDao")
public iflightdao flightdao;
@Rolesallowed ("utilisateur")
public void booktrip (long sortboundflightid, long returnflightid, int sièges)
lance l'invalideSeatSexception
{
réserveSeats (sort-lighti, sièges);
réserveSeats (returnflightid, sièges);
}
}
Cette annotation indiquera que le conteneur est responsable de s'assurer que seul l'appelant du rôle spécifié peut exécuter cette méthode. Alors maintenant, je vais montrer un autre aspect simple - il renforcera encore les contraintes de sécurité sur l'application:
@aspect
Sécurité de la classe publique
{
@around ("EXECUTION (@ javax.annotation.security.Rolesallowed * *. * (..))")
Objet public autour des méthodes sécurisées (procédant à ce que celle-ci)
lance descendant
{
booléen callentauthorized = false;
Rolesallowed roleSallowed = roleSallowedForJoinpoint (thisJoinpoint);
for (String Role: Rolesallowed.Value ())
{
if (callerinrole (rôle))
{callErtauthorized = true;}
}
if (callErauthorise)
{return thisJoinpoint.proceed ();}
autre
{
lancer un nouveau RuntimeException ("l'appelant non autorisé à effectuer une fonction spécifiée");
}
}
rôles privés ont fait des rôles à la hauteur du point de vue (procédure joinpoint thisjoinpoint)
{
Methodsignature MethodsIgnature = (Methodsignature) thisJoinpoint.getSignature ();
Méthode TargetMethod = MethodiSignature.getMethod ();
return TargetMethod.getannotation (Rolesallowed.class);
}
Callerinrole booléen privé (rôle de chaîne)
{...}
}
Cet aspect comprend l'exécution de toutes les méthodes - en vérifiant que l'appelant est l'un des rôles spécifiés dans l'annotation, annotez avec l'annotation @Rolesallowed et s'assurant que l'appelant est autorisé à appeler la méthode. Bien sûr, vous pouvez également utiliser n'importe quel algorithme que vous aimez autoriser l'utilisateur et récupérer son rôle, comme les JAAS ou une solution personnalisée. Dans cet exemple de programme, pour plus de commodité, j'ai choisi de procurer le conteneur servlet.
V. Affaires
Les transactions deviennent un élément important du développement de l'entreprise - car ils facilitent l'intégration des données dans un environnement simultané. À partir d'un niveau élevé, les transactions peuvent assurer cela par le biais d'opérations multiples ou complètes ou incomplètes.
Contrairement aux annotations pour l'injection et la sécurité des ressources, les annotations des transactions sont spécifiques à EJB 3.0 et ne sont pas définies dans les annotations normales JSR 250. EJB 3.0 définit deux annotations associées aux transactions: Transaction Management et TransactionAttribute. L'annotation TransactionManager spécifie si la transaction est gérée par le conteneur ou par le haricot. Dans EJB 3, si cette annotation n'est pas spécifiée, la transaction gérée par le conteneur sera utilisée. L'annotation TransactionAttribute est utilisée pour spécifier le niveau de propagation des transactions de la méthode. Les valeurs valides - y compris obligatoire, requise, requise nouvelle, prise en charge, non prise en charge et jamais prise en charge - sont utilisées pour définir si une transaction existante est requise ou qu'une nouvelle transaction est lancée, etc.
Étant donné que l'opération Bookflight se compose de deux étapes - commandant un vol sortant et un vol de retour, en l'emballant dans une transaction, vous pouvez assurer la cohérence de l'opération. En utilisant des annotations de transaction EJB 3.0, cela ressemblera à ceci:
classe publique TravelagenServiceImplt implémente ittravelagencyservice
{
@Resource (name = "FlightDao")
public iflightdao flightdao;
@Rolesallowed ("utilisateur")
@transactionAttribute (transactionAttributeType.Required)
public void booktrip (long sortboundflightid, long returnflightid, int sièges)
lance l'invalideSeatSexception
{
réserveSeats (sort-lighti, sièges);
réserveSeats (returnflightid, sièges);
}
}
Et vous pouvez appliquer un aspect simple pour définir automatiquement les limites de transaction:
@aspect
Classe publique TransactionAspect
{
@pointcut ("EXECUTION (@ javax.ejb.transactionAttribute * *. * (..))")
public void transactionalthods () {}
@before ("transactionalthods ()")
VOID public Beforetransactionalthods ()
{hibernateutil.begintransaction ();
@Afterreturning ("Transactionalthods ()")
VOID PUBLIQUE APRÈS RETRIMINATIONSTRANSACTIONALLESHODS ()
{HiberNateUtil.CommitTransaction ();
@AfterThrowing ("transactionalthods ()")
Vide public après avoir lancé les Transactionalthods ()
{hibernateUtil.rollBackTransaction ();
}
Cette implémentation est basée sur l'hypothèse que le modèle Hibernate et omniprésent est utilisé pour gérer les sessions Hibernate et les objets de transaction;
6. Résumé
En utilisant les ensembles d'annotation EJB 3.0 et JSR 250, cet article a montré comment les préoccupations transversales telles que la gestion des ressources, la sécurité et les transactions sont mises en œuvre en tant qu'aspects. Bien sûr, il existe de nombreux autres contenus que nous devons apprendre davantage. La première chose à apprendre est le plan fourni par les préoccupations modulaires de coupe croisée en mettant en œuvre ces exemples d'aspects à l'aide d'aspectj. Deuxièmement, nous avons vu de nouvelles idées et concepts derrière la déclaration EJB 3.0 qui émerge maintenant. Enfin, nous voyons également de manière dramatique la liberté qui doit être fournie pour découpler nos objets commerciaux de l'API EJB. À ce stade, tout ce que vous voulez faire de TravelageCyServiceIMPl Une session sans état est d'ajouter une dernière note:
@Stateful
classe publique TravelagenServiceImplt implémente ittravelagencyservice
{...}
Enfin, j'espère vraiment que cette approche gratuite pour fournir des services d'entreprise apportera la concurrence et l'innovation dans l'industrie du cadre / des conteneurs.