Injection des dépendances

Garder une application flexible

Ce site ne sera plus alimenté de contenu après août 2014. Tous les nouveaux articles seront redigés pour www.waitingforcode.com

Spring est un framework qui facilite la maîtrise du cycle de vie de l'application grâce à de nombreuses bonnes pratiques de développement. Dans cet article on verra le principal concept qui fait la force de ce framework.

Injection des dépendances

Le concept fondamental du Spring est l'injection des dépendances (dependency injection). C'est une réponse à 3 facteurs du mauvais codage, définis en 1994 par Robert C. Martin :

  1. Rigidité : il est difficile de changer quoique ce soit car chaque changement affecte trop le fonctionnement du système.
  2. Fragilité : un changement provoque le mauvais fonctionnement des parties qui devraient fonctionner correctement.
  3. Immobilité : il est difficile de réutiliser le code dans une autre application.

Ces 3 problèmes sont appelés RFI (Rigidity, Fragility, Immobility). L'injection des dépendances est une solution à cette problématique.

Inversion of Control container (IoC)

Il s'agit d'un mécanisme qui facilite la mise en place des dépendances par l'injection automatique des objets. Sous Spring, ces derniers s'appellent des beans. Cette injection automatique peut se faire à travers les fichiers XML aussi bien qu'à travers des annotations.

Le rôle du container consiste donc à regrouper les beans avec le modèle des données. Ce regroupement produit ensuite le système prêt à être déployé. Le container est donc un contexte d'application (application context) qui gère des beans.

Les principaux IoC sont situées dans les packages org.springframework.beans et org.springframework.context. BeanFactory, placé dans le premier package, est moins orienté "production" que ApplicationContext. Il s'occupe uniquement d'initialiser les beans. Ce dernier permet plus de choses. Grâce à l'ApplicationContext on peut internationaliser l'application (support i18n) ou intégrer plus facilement l'AOP. Il contient aussi un contexte spécifique aux applications web, WebApplicationContext.

Pour résumer il est préférable d'utiliser ApplicationContext. On devrait limiter l'usage du BeanFactory à des applications dont la consommation de mémoire est un élément crucial(par exemple dans les applets).

Injection des dépendances dans Spring

On sait déjà que l'IoC lit les méta-données de configuration afin d'assembler et d'initialiser les objets utilisés par l'application. Ensuite chaque bean créé devient injectable via un fichier XML ou une annotation. Dans notre application on injecte les beans directement dans le XML et à travers l'annotation @Autowired. Regardons cela sur un exemple :

afficher le code

afficher le code

On ne va pas entrer trop dans les détails. En gros, le code présente un outil d'envoi de mail qui est ensuite utilisé par un service gérant les utilisateurs. Le document XML affiche comment cet outil est défini. Le code Java illustre une partie de son code de source.

Concentrons-nous sur MailerTool.java à qui on injecte l'attribut velocityEngine. Pour qu'il puisse prendre une valeur grâce à la méthode setVelocityEngine. Jusqu'ici rien de compliqué. Tout simplement, on indique la référence du bean qui doit être attaché l'attribut velocityEngine de la classe MailerTool. Concernant SubscriberServiceImpl.java, on remarque la présence d'une annotation @Autowired. C'est elle qui s'occupe d'injecter le bean MailerTool à cette classe. Cependant, le setter correspondant est absent. Pourquoi ?

C'est possible grâce à la reflection API qu'utilise Spring pour injecter les dépendances. La méthode setAccessible permet de spécifier si les opérateurs d'accès (private, public, protected) doivent être utilisés. Si le paramètre de cette fonction est true, cela veut dire qu'un élément sera accessible sans vérification d'accès. Il se peut donc qu'un attribut privé soit alors accessible par une référence directe, sans passer par un setter. C'est cela qui fait en sorte que l'annotation @Autowired ne nécessite pas la présence d'un setter.

On remarque également un autre point commun. Les deux classes sont des beans. Un est défini dans un fichier XML, l'autre grâce à l'annotation @Service. L'injection peut se faire uniquement entre deux beans. Ils doivent donc vivre et être gérés par le contexte d'application.

Le code suivant ne fonctionnera pas car la classe SubscriberFormValidator n'est pas un bean. L'attribut paymentMethodRepository sera donc toujours null :

public class SubscribeFormValidator implements Validator  {

    @Autowired
    private PaymentMethodRepository paymentMethodRepository;
    
    // ...
}

Mais attention, l'initialisation d'une nouvelle instance (new MyClass) ne permet pas de bénéficier de l'injection des dépendances. Cette dernière peut être accomplie uniquement grâce à des méthodes déjà évoquées (annotation ou fichier de configuration).

Bartosz KONIECZNY Concepts de base

Une question ? Une remarque ?

*

*

Moi

Développeur d'applications Internet et journaliste passionné par l'adjectif français. Un aigle polonais orienté vers la progression, volant très haut et écoutant du zouk après les matches du foot français.

Vous appréciez mon travail ?

Pour contribuer au développement de ce site, ou pour remercier pour des articles rédigés, vous pouvez faire un don.

Un conseil Symfony2

A quoi peut être lié le problème "Unknown Entity namespace alias" ?

Ce problème peut apparaître dans Symfony2 parce que le bundle de l'entité peut ne pas être défini dans AppKernel.