Injection de dépendances Java: XML ou annotations
Annotations devenant populaires. Spring-3 les supporte. Le CDI en dépend fortement (i ne peut pas utiliser le CDI avec des annotations, non?)
ma question Est pourquoi ?
j'ai entendu plusieurs questions:
-
"il aide à se débarrasser de XML". Mais qu'est-ce qui est mauvais avec xml? Les dépendances sont de nature déclarative, et XML est très bon pour les déclarations (et très mauvais pour la programmation impérative). Avec un bon IDE (comme idea), il est très facile d'éditer et de valider xml, n'est-ce pas?
-
"dans de nombreux cas, il n'y a qu'une seule implémentation pour chaque interface". Ce n'est pas vrai! Presque toutes les interfaces de mon système ont une implémentation simulée pour les tests.
autres questions?
et maintenant mes avantages pour XML:
-
vous pouvez injecter n'importe quoi n'importe où (pas seulement le code qui a des annotations)
-
Que dois-je faire si j'ai plusieurs implémentations d'une interface? Utiliser des qualificatifs? Mais ça force ma classe à savoir de quel type d'injection elle a besoin. Il n'est pas bon pour le design.
basé sur XML DI fait mon code clair: chaque classe a aucune idée de l'injection, donc je peux le configurer et de l'unité de test en quelque sorte.
Qu'en pensez-vous?
10 réponses
Je ne peux parler que d'expérience avec des conseils, mais voici mon avis. Le plus court est que la configuration basée sur l'annotation réduit considérablement la quantité que vous avez à écrire pour connecter une application ensemble et rend plus facile de changer ce qui dépend de quoi... souvent sans même avoir à toucher les fichiers de configuration eux-mêmes. Elle le fait en rendant les cas les plus courants absolument insignifiants aux dépens de certains cas relativement rares un peu plus difficile à gérer.
je pense que c'est un problème d'être trop dogmatique sur le fait que les classes n'ont"aucune idée de l'injection". Il ne doit pas y avoir de référence au récipient d'injection dans le code d'une classe. Je suis absolument d'accord avec ça. Cependant, nous devons être clairs sur un point: les annotations ne sont pas un code . Par eux-mêmes, ils ne changent rien au comportement d'une classe... vous pouvez toujours créer une instance d'une classe avec les annotations si ils n'étaient pas là du tout. Donc, vous pouvez arrêter d'utiliser un conteneur DI complètement et laisser les annotations là et il n'y aura aucun problème que ce soit.
lorsque vous choisissez de ne pas fournir d'indices de métadonnées sur l'injection dans une classe (c.-à-d. des annotations), vous jetez une source précieuse d'information sur les dépendances que la classe exige. Vous êtes forcé soit de répéter cette information ailleurs (dans XML, par exemple), soit de vous fier à une magie peu fiable comme l'autowiring qui peut conduire à des problèmes inattendus.
pour répondre à certaines de vos questions spécifiques:
il aide à se débarrasser de XML
beaucoup de choses sont mauvaises à propos de la configuration XML.
- c'est terriblement verbeux.
- ce n'est pas sûr sans outils spéciaux.
- il impose l'utilisation d'identificateurs de chaîne. Encore une fois, pas sûr sans support d'outil spécial.
- ne tire aucun avantage des caractéristiques de la langue, exigeant toutes sortes de constructions laides pour faire ce qui pourrait être fait avec une méthode simple en code.
cela dit, je sais que beaucoup de gens ont été en utilisant XML pour assez longtemps qu'ils sont convaincus que c'est tout simplement parfait et je n'ai pas vraiment s'attendre à changer leurs esprits.
dans de nombreux cas, il n'y a qu'une seule implémentation pour chaque interface
Il n'y a souvent qu'une seule implémentation de chaque interface pour une seule configuration d'une application (par ex. production). Le fait est que lorsque vous démarrez votre application, vous n'avez généralement besoin de lier une interface qu'à une seule implémentation. Il peut alors être utilisé dans de nombreux autres composants. Avec la configuration XML, vous devez dire à chaque composant qui utilise cette interface d'utiliser cette liaison particulière de cette interface (ou "bean" si vous le souhaitez). Avec configuration basée sur annotation, vous déclarez juste la reliure une fois et tout le reste est pris en charge automatiquement. Ceci est très significatif, et réduit considérablement la quantité de configuration que vous devez écrire. Cela signifie également que lorsque vous ajoutez une nouvelle dépendance à un composant, vous n'avez pas à changer quoi que ce soit à propos de votre configuration!
que vous avez des implémentations simulées d'une interface n'est pas pertinent. Dans l'unité vous testez Généralement, il suffit de créer la moquerie et passer en vous-même... ce n'est pas lié à la configuration. Si vous mettez en place un système complet pour les tests d'intégration avec certaines interfaces en utilisant des mocks à la place... ça ne change rien. Pour le test d'intégration du système, vous n'utilisez qu'une seule implémentation et vous n'avez qu'à la configurer une seule fois.
XML: vous pouvez injecter n'importe quoi n'importe où
, Vous pouvez le faire facilement en Guice et j'imagine que vous pouvez en Le CDI aussi. Donc ce n'est pas comme si vous étiez absolument empêchée de faire cela en utilisant un système de configuration basé sur l'annotation. Cela dit, je me risquerais à dire que la majorité des classes injectées dans la majorité des applications sont des classes que vous pouvez ajouter un @Inject
à vous-même si elle n'est pas déjà là. L'existence d'une bibliothèque Java standard légère pour les annotations (JSR-330) rend encore plus facile pour plus de bibliothèques et de cadres de fournir des composants avec un @Inject
annoté constructeur dans l'avenir, aussi.
plus d'une implémentation d'une interface
Les qualificatifs sont une solution à cela, et dans la plupart des cas devrait être très bien. Cependant, dans certains cas, vous voulez faire quelque chose où à l'aide d'un qualificatif sur un paramètre en particulier injecté classe ne fonctionnerait pas... souvent parce que vous voulez avoir plusieurs instances de la classe que , chacune utilisant une implémentation d'interface différente ou instance. Guice résout cela avec quelque chose appelé PrivateModule
s. Je ne sais pas ce que le CDI offre à cet égard. Mais encore une fois, c'est un cas qui est minoritaire et cela ne vaut pas la peine de faire souffrir le reste de votre configuration tant que vous pouvez le gérer.
j'ai le principe suivant: les fèves liées à la configuration sont définies avec XML. Tout le reste - avec des annotations.
pourquoi? Parce que vous ne voulez pas changer la configuration dans les classes. D'autre part, il est beaucoup plus simple d'écrire @Service
et @Inject
, dans la classe que vous souhaitez activer.
cela n'interfère en aucune façon avec les tests - les annotations ne sont que des métadonnées qui sont analysées par le conteneur. Si vous le souhaitez, vous pouvez définir différentes dépendances.
comme pour CDI - il a une extension pour la configuration XML, mais vous avez raison il utilise principalement des annotations. C'est quelque chose que je n'aime pas particulièrement dans ce que.
À mon avis, c'est plus une question de goût.
1) dans notre projet (en utilisant Spring 3), nous voulons que les fichiers de configuration XML soient juste cela: configuration. Si elle n'a pas besoin d'être configurée (du point de vue de l'utilisateur final) ou si un autre problème ne l'oblige pas à être faite en xml, ne mettez pas les définitions de fève/wirings dans les configurations XML, utilisez @Autowired et ainsi de suite.
2) avec Spring, vous pouvez utiliser @Qualifier pour faire correspondre un certain mise en œuvre de l'interface, s'il en existe plusieurs. Oui, cela signifie que vous devez nommer les implémentations réelles, mais ça ne me dérange pas.
dans notre cas, utiliser XML pour traiter tous les DI gonflerait les fichiers de configuration XML beaucoup, bien que cela puisse être fait dans un fichier xml séparé (ou des fichiers), donc ce n'est pas que point valide ;). Comme je l'ai dit, c'est une question de goût et je pense juste qu'il est plus facile et plus propre de gérer les injections via des annotations (vous peut voir ce que les services / dépôts / quelque chose utilise juste en regardant la classe au lieu de passer par le fichier XML à la recherche de la déclaration bean).
Edit: Voici une opinion sur @Autowired vs. XML que je suis tout à fait d'accord avec: Spring @Autowired usage
j'aime garder mon code clair, comme vous l'avez souligné. XML pieds mieux, au moins pour moi, le CIO principe.
le principe fondamental de L'Injection de dépendances pour la configuration est que les objets d'application ne doivent pas être responsables de rechercher les ressources ou les collaborateurs dont ils dépendent. Au lieu de cela, un conteneur IoC devrait configurer les objets, externalisant la recherche de ressources à partir du code d'application dans le conteneur. (J2EE Développement sans EJB-Rod Johnson-page 131)
encore une fois, c'est juste mon point de vue, pas de fondamentalisme là-dedans:)
EDIT: Certaines discussions utiles là-bas:
" mais qu'y a-t-il de mauvais dans xml?"C'est encore un autre fichier à gérer et encore un autre endroit pour aller chercher un bug. Si vos annotations sont juste à côté de votre code, il est beaucoup plus facile de les modifier et de les déboguer.
comme toute chose, l'injection de dépendance doit être utilisée avec modération. De plus, tous les signes extérieurs des injections doivent être séparés du code d'application et relégués au code associé à main.
en général, les applications doivent avoir une limite qui sépare le code abstrait d'application des détails concrets de mise en œuvre. Toutes les dépendances du code source qui traversent cette limite devraient pointer vers l'application. J'appelle le le côté concret de cette frontière, la cloison principale, parce que c'est là que "main" (ou son équivalent) devrait vivre.
la partition principale consiste en implémentations d'usine, implémentations stratégiques, etc. Et c'est sur ce côté de la frontière que l'injection de dépendance cadre devrait le faire. Ensuite, les dépendances injectées peuvent être passées au travers de la frontière dans l'application par des moyens normaux. (par exemple comme arguments).
le nombre les dépendances injectées doivent être relativement petites. Une douzaine ou moins. Dans ce cas, la décision entre XML ou annotations est sans objet.
dans mon cas, les développeurs qui écrivent l'application sont différents de ceux qui la configurent (différents départements, différentes technologies/langues) et le dernier groupe n'a même pas accès au code source (ce qui est le cas dans de nombreuses configurations d'entreprise). Cela rend Guice inutilisable puisque je devrais exposer le code source plutôt que de consommer les xmls configurés par les développeurs implémentant l'application.
dans l'ensemble, je pense qu'il est important de reconnaître que fournir les composants et assembler/configurer une application sont deux exercices différents et fournir si nécessaire cette séparation des préoccupations.
j'ai juste deux ou trois choses à ajouter à ce qui est déjà là.
-
pour moi, la configuration DI est un code. Je voudrais le traiter comme tel, mais la nature même du XML l'empêche sans outils supplémentaires.
-
Spring JavaConfig est un grand pas en avant à cet égard, mais il a encore des complications. La numérisation de composants, la sélection automatique des implémentations d'interface et la sémantique autour L'interception par CGLIB des classes annotées @Configuration rend la chose plus complexe qu'elle ne devrait l'être. Mais C'est encore un pas en avant par rapport au XML.
-
l'avantage de séparer les métadonnées du CIO des objets d'application est surestimé, surtout avec Spring. Peut-être que si vous vous en teniez uniquement au conteneur du CIO du printemps, ce serait vrai. Mais Spring offre une large pile d'applications construite sur le conteneur du CIO (sécurité, Web MVC, etc.). Dès que vous si vous tirez sur tout ça, vous êtes attaché au container de toute façon.
XML présente le seul avantage d'un style déclaratif clairement séparé du code de demande lui-même. Ça reste indépendant des affaires internes. Les inconvénients sont la verbosité, une mauvaise reconfiguration de la robustesse et un comportement général de défaillance pendant le fonctionnement. Il y a juste un support D'outil général (XML) avec peu d'avantages par rapport au support IDE pour par exemple Java. En outre, ce XML est livré avec une performance overhead donc il est généralement plus lent que les solutions de code.
irritations souvent dit être plus intuitif et robuste lors de la refonte du code d'application. Ils bénéficient également d'une meilleure orientation IDE comme guice fournit. Mais ils mélangent le code d'application avec les préoccupations de DI. Une application est dépendante d'un cadre. Séparation claire est presque impossible. Les Annotations sont également limitées lorsqu'il s'agit de décrire des comportements d'injection différents au même endroit (constructeur, champ) en fonction d'autres circonstances (p. ex. problème de jambes de robot). De plus, ils ne permettent pas de traiter des classes externes (code de bibliothèque) comme votre propre source. Par conséquent, ils sont considérés pour courir plus vite que XML.
les deux techniques ont de graves inconvénients. Par conséquent je recommande pour utiliser Silk DI . Il est déclaratif défini dans le code (grand soutien IDE) mais 100% séparé de votre code d'application (Pas de dépendance de cadre). Il permet de traiter tous les codes de la même façon peu importe s'il provient de votre source ou d'une bibliothèque externe. Des problèmes comme le problème de jambes de robot sont faciles à résoudre avec les fixations habituelles. En outre, il a un bon soutien pour l'adapter à vos besoins.