Injection de dépendance : Guice et Spring
Google Guice
Google propose chaque jour de nouvelles fonctionnalités ou de nouveaux produits et donc un grand besoin d'avoir un code propre et fonctionnel. Pour cela google propose aussi des outils (utilisés en interne chez eux) pour contribuer a ce code propre. Parmis ces outils on peux trouver Google Guice pour l'injection de dépendance.
Google Guice est apparu après la solution de Spring. Spring n'a pas convenu a Google qui cherchait un outil simple et facile à utiliser. Guice à donc été developé en mettant ces 2 aspects en avant. Il ne couvre pas tous les cas que couvre Spring mais offre une facilité et rapidité beaucoup plus évoluée.
Depuis sa version 2.1 (actuellement en version 3.0 depuis mars 2011) Guice respecte la JSR 330 en ce qui concerne les annotations d'injection de dépendance. Il peut donc être remplacé par un autre framework respectant la JSR 330 sans changement de code.
Fonctionnement
Le fonctionnement de Guice repose sur 3 éléments clés :
Contexte de l'application
Afin de pouvoir comparer correctement les deux solutions, nous reprendrons le même contexte que pour Spring IoC.
Pour notre exemple nous allons avoir une projet avec une classe principale qui va publier un lien sur un site web. Ce lien pouvant être compliqué nous souhaitons qu'il puisse être simplifié.
Nous avons donc :

Les modules de configuration
La configuration de Guice se fait via des objet java appelé Modules. Le developpeur doit créer une classe qui étend AbsractModule de Guice. Lors de l'extention, on peut redefinir la méthode configure() dans laquelle on va pouvoir associer une implémentation à une interface.
Dans notre cas, nous aurons 2 modules, un pour le lancement normal et un pour les tests. Le module devra ressembler à ça :
public class TweetModule extends AbstractModule {
protected void configure() {
bind(Tweeter.class).to(SmsTweeter.class);
bind(Shortener.class).to(BasicShortener.class);
}
Nous avons déclaré 2 associations : BasicShortener (associé a la classe impl.BasicShortener) et SmsTweeter (associé a impl.smsTweeter). Pour toute classe qui sera sous la gestion de l'injecteur (que nous verrons plus bas) chaque injection à faire pour ces deux interfaces sera régie par ce module. Dans le cas où l'on souhaiterais avoir plusieurs implémentations pour la même interface dans le code il faudra créer un second module qui sera géré par un second injecteur.
L'annotation Inject
Pour pouvoir injecter notre implémentation dans notre classes principale, l'injecteur de Guice va parcourir les classes a la recherche de l'annotation Inject. Cette dernière peut être placée sur un attribut (on injecte directement dans l'attribut), sur un constructeur (on injecte dans les paramètres du constructeurs) ou bien sur une méthode (on injecte dans les paramètres de la méthode).
Cela nous donne donc pour notre classe TweetClient :
@Inject
private Tweeter tweet;
@Inject
private Shortener shorten;
Ici nous avons fais le choix de l'injection sur l'attribut directement. Nous aurions aussi pu avoir annoté le constructeur de TweetClient :
@Inject
Public TweetClient(Tweeter tweet, Shortener shorten) {
this.tweet=tweet;
this.shorten=shorten;
}
L'Injector
L'Injector est la classe de Guice qui va charger le module et injecter les dépendances à sa charge. Une fois le module chargé, nous allons demander à l'injecteur une instance de notre classe qui a besoin d'injection (ici TweetClient).
Note : Toutes les sous classes et sous dépendances dont la classe mère a été chargée par un injecteur peuvent bénéfier de l'injection de dépendance. Si on demande a l'injecteur la classe la plus haute de notre application, alors toutes les annotations @Inject seront gérées en une seule fois.
Cela nous donne donc pour notre Main :
public static void main(String[] args) {
Injector injector = Guice.createInjector(new TweetModule());
TweetClient tweetClient = injector.getInstance(TweetClient.class);
tweeter.publishWithUrl("mon message de publication", "http://www.monsite.com/truccompliqué&dur_a_retenir=true");
}
Ici, en première ligne, nous demande à Guice de créer un injecteur à partir du module TweetModule.
Ensuite, nous demandons à l'injecteur de nous donner une instance de notre classe mére TweetClient. toutes les annotations trouvées en parcourant TweetClient et ses dépendances directes et indirectes seront résolues par l'injecteur en utilisant les implémentations trouvées dans TweetModule.
Nous aurons en résultat selon le code mis dans BasicShortener et SmsTweeter notre message avec un lien simplifié vers monsite.com
Les sources de cet exemple sont disponibles ici