35 votes

Injection de dépendances en Java : XML ou annotations

Les annotations deviennent populaires. Spring-3 les supporte. CDI en dépend fortement (je ne peut pas utiliser le CDI en dehors des annotations, non ?)

Ma question est la suivante por qué ?

J'ai entendu plusieurs questions :

  1. "Il permet de se débarrasser de XML". Mais qu'est-ce qui est mauvais dans le XML ? Les dépendances sont déclaratives par nature, 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 le xml, n'est-ce pas ?

  2. "Dans de nombreux cas, il n'existe qu'une seule implémentation pour chaque interface". Ce n'est pas vrai ! Presque toutes les interfaces dans mon système ont une implémentation fantaisie pour les tests.

D'autres problèmes ?

Et maintenant, mes avantages pour le XML :

  1. Vous pouvez injecter n'importe quoi n'importe où (pas seulement du code qui a des annotations).

  2. Que dois-je faire si j'ai plusieurs implémentations d'une même interface ? Utiliser des qualificatifs ? Mais cela oblige ma classe à savoir de quel type d'injection elle a besoin. Ce n'est pas bon pour la conception.

Le DI basé sur XML rend mon code clair : chaque classe n'a aucune idée de l'injection, je peux donc la configurer et la tester unitairement de n'importe quelle manière.

Qu'en pensez-vous ?

25voto

ColinD Points 48573

Je ne peux parler que par expérience avec Guice, mais voici mon point de vue. En résumé, la configuration basée sur les annotations réduit considérablement la quantité de données que vous devez écrire pour assembler une application et facilite le changement de ce qui dépend de ce qui est... souvent sans même avoir à toucher aux fichiers de configuration eux-mêmes. Pour ce faire, elle rend les cas les plus courants absolument triviaux au prix de rendre certains cas relativement rares... légèrement 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 devrait pas y avoir de référence au conteneur d'injection dans le code d'une classe. Je suis tout à fait d'accord avec cela. Cependant, il faut être clair sur un point : les annotations ne sont pas des codes . En elles-mêmes, elles ne changent rien au comportement d'une classe... vous pouvez toujours créer une instance d'une classe avec des annotations comme si elles n'existaient pas du tout. Vous pouvez donc cesser complètement d'utiliser un conteneur DI et laisser les annotations en place sans aucun problème.

Lorsque vous choisissez de ne pas fournir d'indications de métadonnées sur l'injection au sein d'une classe (c'est-à-dire des annotations), vous vous débarrassez d'une source précieuse d'informations sur les dépendances requises par cette classe. Vous êtes obligé de répéter cette information ailleurs (dans le XML, par exemple) ou de vous fier à une magie peu fiable comme le câblage automatique qui peut conduire à des problèmes inattendus.

Pour répondre à certaines de vos questions spécifiques :

Il aide à se débarrasser de XML

La configuration XML présente de nombreux inconvénients.

  • C'est terriblement verbeux.
  • Il n'est pas sûr sans outils spéciaux.
  • Il impose l'utilisation d'identifiants de type chaîne. Là encore, ce n'est pas sûr sans l'aide d'un outil spécial.
  • Il ne tire aucun avantage des caractéristiques du langage, nécessitant toutes sortes de constructions hideuses pour faire ce qui pourrait être fait avec une simple méthode dans le code.

Cela dit, je sais que beaucoup de gens utilisent le XML depuis suffisamment longtemps pour être convaincus qu'il est parfait et je ne m'attends pas vraiment à les faire changer d'avis.

Dans de nombreux cas, il n'existe qu'une seule implémentation pour chaque interface.

Il n'y a souvent qu'une seule implémentation de chaque interface pour le une seule configuration d'une application (par exemple, la production). L'idée est qu'au démarrage de votre application, vous n'avez généralement besoin de lier une interface à une seule implémentation. Celle-ci peut ensuite être utilisée dans de nombreux autres composants. Avec la configuration XML, vous devez indiquer à chaque composant qui utilise cette interface d'utiliser cette liaison particulière de cette interface (ou "bean" si vous voulez). Avec la configuration basée sur les annotations, il suffit de déclarer la liaison une fois et tout le reste est pris en charge automatiquement. C'est très important et cela 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 ne devez souvent rien changer à votre configuration !

Le fait que vous ayez des implémentations fictives d'une interface n'est pas pertinent. Dans les tests unitaires, il suffit généralement de créer l'objet fantaisie et de le transmettre soi-même... cela n'a rien à voir avec la configuration. Si vous mettez en place un système complet pour les tests d'intégration avec certaines interfaces en utilisant plutôt des objets fantaisie... cela ne change rien. Pour le test d'intégration du système, vous n'utilisez toujours qu'une seule implémentation et vous ne devez la configurer qu'une seule fois.

XML : Vous pouvez injecter n'importe quoi n'importe où

Vous pouvez le faire facilement dans Guice et j'imagine que vous le pouvez aussi dans CDI. Ce n'est donc pas comme si l'utilisation d'un système de configuration basé sur les annotations vous empêchait absolument de le faire. Cela dit, je me risquerais à dire que la majorité des classes injectées dans la majorité des applications sont des classes auxquelles vous pouvez ajouter une annotation @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) permet à un plus grand nombre de bibliothèques et de frameworks de fournir plus facilement des composants avec des annotations. @Inject dans le futur, aussi.

Plus d'une implémentation d'une interface

Les qualificatifs sont une solution à ce problème et, dans la plupart des cas, ils devraient convenir parfaitement. Cependant, dans certains cas, vous voulez faire quelque chose où l'utilisation d'un qualificateur sur un paramètre dans une classe injectée particulière ne fonctionnerait pas... souvent parce que vous voulez avoir plusieurs instances de que chacun utilisant une implémentation ou une instance d'interface différente. Guice résout ce problème 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 ça ne vaut pas la peine de faire souffrir le reste de votre configuration tant que vous pouvez le supporter.

10voto

Bozho Points 273663

J'ai le principe suivant : les beans liés à la configuration sont définis avec XML. Tout le reste - avec des annotations.

Pourquoi ? Parce que vous ne voulez pas modifier la configuration dans les classes. D'autre part, il est beaucoup plus simple d'écrire @Service y @Inject dans la classe que vous voulez activer.

Cela n'interfère en rien 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 des dépendances différentes.

Quant au CDI, il possède une extension pour la configuration XML, mais vous avez raison, il utilise principalement des annotations. C'est un aspect que je n'apprécie pas particulièrement.

4voto

esaj Points 8338

À mon avis, c'est plutôt une question de goût.

1) Dans notre projet (qui utilise Spring 3), nous voulons que les fichiers de configuration XML ne soient que cela : une configuration. Si cela n'a pas besoin d'être configuré (du point de vue de l'utilisateur final) ou si un autre problème n'oblige pas à le faire en XML, ne mettez pas les définitions de bean/câblages dans les configurations XML, utilisez @Autowired et autres.

2) Avec Spring, vous pouvez utiliser @Qualifier pour faire correspondre une certaine implémentation de l'interface, si plusieurs existent. Oui, cela signifie que vous devez nommer les implémentations réelles, mais cela ne me dérange pas.

Dans notre cas, l'utilisation de XML pour gérer toutes les entrées-sorties gonflerait considérablement les fichiers de configuration XML, bien que cela puisse être fait dans un (ou plusieurs) fichier(s) xml séparé(s), ce qui n'est pas nécessaire. que point valable ;). Comme je l'ai dit, c'est une question de goût et je pense simplement qu'il est plus facile et plus propre de gérer les injections via les annotations (vous pouvez voir quels services/référentiels/quelque chose utilise simplement en regardant la classe au lieu de parcourir le fichier XML à la recherche de la déclaration du bean).

Edit : Voici une opinion sur @Autowired vs. XML avec laquelle je suis entièrement d'accord : Utilisation de Spring @Autowired

4voto

Aito Points 3311

J'aime garder mon code clair, comme vous l'avez souligné. XML s'intègre mieux, du moins pour moi, dans le principe du CIO.

Le principe fondamental de l'injection de dépendances pour la configuration est que les objets de l'application ne doivent pas être chargés de rechercher les ressources ou les collaborateurs dont ils dépendent. Au lieu de cela, un conteneur IoC doit configurer les objets, en externalisant la recherche de ressources du code de l'application vers le conteneur. (Développement J2EE sans EJB - Rod Johnson - page 131)

Encore une fois, c'est juste mon point de vue, pas de fondamentalisme là-dedans :)

EDIT : Il y a des discussions utiles là-bas :

3voto

Speck Points 891

"Mais qu'est-ce qui est mauvais dans le xml ?" C'est encore un autre fichier à gérer et encore un autre endroit où il faut aller chercher un bug. Si vos annotations sont juste à côté de votre code, c'est beaucoup plus facile à gérer et à déboguer.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X