Injection de dépendance : Guice et Spring
Présentation de l'injection de dépendance
Principes
Lorsque l'on développe un programme en java, afin d'éviter de tout avoir dans un seul fichier, le développeur écrit plusieurs classes (une classe par fichier). Cela permet non seulement d'assurer une meilleure lisibilité mais aussi une meilleure maintenance.Seulement lorsque l'on passe en plusieurs classes, on souhaite pouvoir enlever une classe et la remplacer par une autre classe. Cela n'est malheuresement pas possible en java de base, il faut passer par de l'injection de dépendance. Cela permet entre autre "d'échanger" une classe par une autre et d'avoir plusieurs configurations d'application.
Il existe 4 types d'injections de dépendances :
On peut faire de l'injection de dépendance à la main sans utiliser d'outils ou bien utiliser des frameworks (voir plus bas)
Histoire
Tout d'abord :Lors de la séparation d'un code en plusieurs classes, nous avons une dépendance directe d'une classe a une autre. Nous séparons le code général en une classe A et une classe B. La classe A doit utiliser une méthode de la classe B.
Cela se fait donc dans le code de A comme suit :
public class A {
public static void main(String[] args)
B b = new B();
b.someMethod();
}
}
Avantages :
Les interfaces :
Le java fournit un moyen de simplifier la gestion des dépendances : l'Interface. Les interfaces en java permettent de définir des méthodes et leurs paramètres sans en définir le code. Ces interfaces sont ensuites implémentées par les classes dont on dépend.
Ici, on crée une interface I définissant la méthode someMethod() et la classe A ne dépend donc plus de B directement mais de I qui peut être implémenté par n'importe quelle autre classe.
Cela se fait donc dans le code de A comme suit :
public class A {Comme nous pouvons le constater, nous avons gardé le new ce qui fait qu'il reste une dépendance indirecte dans A.
public static void main(String[] args)
I b = new B();
b.someMethod();
}
}
Avantages :
Les Factories :
Afin d'avoir du code java propre, la comunauté java à instauré des principes de programmations. Ces principes sont appelés des Design Pattern. Parmis ces design pattern on peut trouver le pattern factory. Ce pattern permet d'avoir une classe factory qui va gérer les dépendances. Cette factory possède des méthodes qui vont instancier la dépendance (ici B) et la retourner. Chaque fois qu'une dépendance devra être résolue (besoin d'un objet de type I) , la classe appelante utilisera la factory.
Cela se fait donc dans le code de factory comme suit :
public class factory {
public I getDependency()
return new B();
}
}
Et dans A :
public class A {
public static void main(String[] args) {
I b = new factory().getDependency();
b.someMethod();
}
}
Avantages :
L'injection par constructeur :
Les developpement d'applications java ayant besoin de plus en plus de tests, l'injection par factory ne suffit plus. Effectivement, cette dernière ne permet pas d'avoir une configuration de production et une configuration de tests. Une solution pour permettre de choisir le mode de lancement (configuration) est de passer l'implémentation directement dans le constructeur de notre classe (ici A)
Cela se fait donc dans le code de A comme suit :
public class A {
I inst;
public A(I inst) {
this.inst=inst;
}
public void doWork() {
inst.someMethod();
}
}
Et dans la classe appelante :
public static void main(String[] args) {
A a = new A(factory().getDependency());
a.doWork();
}
Avantages :
Cette méthode est l'une des plus "propre" et des plus pratique pour faire de l'injection de dépendance. Cependant, des frameworks existent pour éviter au developpeur de gérer ses injections.
Les frameworks
Il existe peu de frameworks pour faire de l'injection de dépendances, je ne présenterai que les 2 plus grands frameworks et les plus récents sur ce site.Voici certains frameworks recencés à ce jour :
Les frameworks PicoContainer et Excalibur (sous son ancien nom Avalon) ont été les premiers à apparaitre comme frameworks d'injection de dépendance. Guice et Spring étants très récents
Voici un rapide résumé du fonctionnement des frameworks PicoContainer et Excalibur
PicoContainer :
PicoContainer a un fonctionnement proche de l'injection par constructeur vue ci dessus. Ce dernier requiert que la classe utilisant la dépendance ai un constructeur permettant de définir l'implémentation. L'application instancie ensuite le picoContainer (par défaut DefaultPicoContainer) et lui faire enregistrer quelle implémentation est associée a quelle interface.
Pour finir, le framework se charge de construire les élements qui ont besoin d'utiliser des dépendances.
Excalibur :
Excalibur fonctionne via de l'injection par interface. Il est donc requis de crée une interface qui va permettre d'injection la dépendance (en plus de l'interface qui définit les méthodes de la dépendance). Cette interface possèdera une méthode permettant de mettre en place l'implémentation de la dépendance.
Notre classe devra implémenter cette interface et utilisera le code de la méthode pour définir son implémentation de la dépendance. Elle pourra ensuite utiliser cette dernière pour n'importe quelle autre méthode.
L'application instancie ensuite un Container dans lequel est enre