Recherche…


Remarques

Le code source des grandes applications logicielles est généralement organisé en plusieurs unités. La définition d'une unité varie normalement selon le langage de programmation utilisé. Par exemple, le code écrit dans un langage de programmation procédural (comme C) est organisé en functions ou procedures . De même, le code dans un langage de programmation orienté objet (comme Java, Scala et C #) est organisé en classes , interfaces , etc. Ces unités d'organisation de code peuvent être considérées comme des unités individuelles constituant l'application logicielle globale.

Lorsque les applications ont plusieurs unités, les interdépendances entre ces unités surviennent lorsqu'une unité doit utiliser d'autres pour compléter ses fonctionnalités. Les unités dépendantes peuvent être considérées comme des consumers et des unités sur lesquelles elles dépendent en tant que providers de fonctionnalités spécifiques.

L'approche de programmation la plus simple consiste pour les consommateurs à contrôler entièrement le flux d'une application logicielle en décidant quels fournisseurs doivent être instanciés, utilisés et détruits à quels moments de l'exécution globale de l'application. On dit que les consommateurs ont un contrôle total sur les fournisseurs pendant le flux d'exécution, qui sont des dependencies pour les consommateurs. Dans le cas où les fournisseurs ont leurs propres dépendances, les consommateurs peuvent avoir à s'inquiéter de la manière dont les fournisseurs doivent être initialisés (et libérés), ce qui rend le flux de contrôle de plus en plus compliqué à mesure que le nombre d'unités du logiciel augmente. Cette approche augmente également le couplage entre les unités, rendant de plus en plus difficile le changement individuel des unités sans se soucier de casser les autres parties du logiciel.

Inversion de contrôle (IoC) est un principe de conception qui préconise l'externalisation des activités de flux de contrôle telles que la découverte, l'instanciation et la destruction des unités dans un cadre indépendant des consommateurs et des fournisseurs. Le principe sous-jacent de l’IoC est de découpler les consommateurs et les fournisseurs, ce qui évite aux unités logicielles de s’inquiéter de la découverte, de l’instanciation et du nettoyage de leurs dépendances, et permet aux unités de se concentrer sur leurs propres fonctionnalités. Ce découplage permet de conserver le logiciel extensible et maintenable.

L'injection de dépendance est l'une des techniques permettant d'implémenter le principe d'inversion de contrôle selon lequel des instances de dépendances (fournisseurs) sont injectées dans une unité logicielle (le consommateur) au lieu que le consommateur les trouve et les instancie.

Le framework Spring contient un module d'injection de dépendances qui permet d'injecter des beans gérés par Spring dans d'autres beans gérés par Spring en tant que dépendances.

Injection manuelle d'une dépendance via la configuration XML

Considérons les classes Java suivantes:

class Foo {
  private Bar bar;

  public void foo() {
    bar.baz();
  }
}

Comme on peut le voir, la classe Foo a besoin d'appeler la méthode baz sur une instance d' une autre classe Bar pour sa méthode foo pour travailler avec succès. Bar est considéré comme une dépendance pour Foo car Foo ne peut pas fonctionner correctement sans une instance de Bar .

Injection de constructeur

Lors de l'utilisation de la configuration XML pour le framework Spring afin de définir des beans gérés par Spring, un bean de type Foo peut être configuré comme suit:

<bean class="Foo">
  <constructor-arg>
    <bean class="Bar" />
  </constructor-arg>
</bean>

ou bien (plus verbeux):

<bean id="bar" class="bar" />

<bean class="Foo">
  <constructor-arg ref="bar" />
</bean>

Dans les deux cas, le framework Spring crée d'abord une instance de Bar et l' injects dans une instance de Foo . Cet exemple suppose que la classe Foo a un constructeur capable de prendre une instance de Bar comme paramètre, à savoir:

class Foo {
  private Bar bar;

  public Foo(Bar bar) { this.bar = bar; }
}

Ce style est appelé injection de constructeur car la dépendance (instance Bar ) est injectée via le constructeur de classe.

Injection de propriété

Une autre option pour injecter la dépendance Bar dans Foo est:

<bean class="Foo">
  <property name="bar">
    <bean class="Bar" />
  </property>
</bean>

ou bien (plus verbeux):

<bean id="bar" class="bar" />

<bean class="Foo">
  <property name="bar" ref="bar" />
</bean>

Cela nécessite que la classe Foo ait une méthode de réglage qui accepte une instance de Bar , telle que:

class Foo {
  private Bar bar;

  public void setBar(Bar bar) { this.bar = bar; }
}

Injection manuelle d'une dépendance via la configuration Java

Les mêmes exemples que ceux illustrés ci-dessus avec la configuration XML peuvent être réécrits avec la configuration Java comme suit.

Injection de constructeur

@Configuration
class AppConfig {
  @Bean
  public Bar bar() { return new Bar(); }

  @Bean
  public Foo foo() { return new Foo(bar()); }
}

Injection de propriété

@Configuration
class AppConfig {
  @Bean
  public Bar bar() { return new Bar(); }

  @Bean
  public Foo foo() {
    Foo foo = new Foo();
    foo.setBar(bar());

    return foo;
  }
}

En utilisant une dépendance via la configuration XML

Les dépendances peuvent être automatiquement générées lors de l'utilisation de la fonctionnalité d'analyse de composants du framework Spring. Pour que le démarrage automatique fonctionne, la configuration XML suivante doit être effectuée:

<context:annotation-config/>
<context:component-scan base-package="[base package]"/>

where, base-package est le package Java complet dans lequel Spring doit effectuer une analyse des composants.

Injection de constructeur

Les dépendances peuvent être injectées via le constructeur de classe comme suit:

@Component
class Bar { ... }

@Component
class Foo {
  private Bar bar;

  @Autowired
  public Foo(Bar bar) { this.bar = bar; }
}

Ici, @Autowired est une annotation spécifique à Spring. Spring prend également en charge JSR-299 pour permettre la portabilité des applications vers d'autres structures d'injection de dépendances basées sur Java. Cela permet à @Autowired d'être remplacé par @Inject tant que:

@Component
class Foo {
  private Bar bar;

  @Inject
  public Foo(Bar bar) { this.bar = bar; }
}

Injection de propriété

Les dépendances peuvent également être injectées en utilisant les méthodes setter comme suit:

@Component
class Foo {
  private Bar bar;

  @Autowired
  public void setBar(Bar bar) { this.bar = bar; }
}

Injection sur le terrain

Le démarrage automatique permet également d'initialiser les champs directement dans les instances de classe, comme suit:

@Component
class Foo {
  @Autowired
  private Bar bar;
}

Pour les versions de printemps 4.1 et ultérieures, vous pouvez utiliser Facultatif pour les dépendances facultatives.

@Component
class Foo {

    @Autowired
    private Optional<Bar> bar;
}

La même approche peut être utilisée pour les constructeurs DI.

@Component
class Foo {
    private Optional<Bar> bar;

    @Autowired
    Foo(Optional<Bar> bar) {
        this.bar = bar;
    }
}

En utilisant une dépendance via la configuration Java

L'injection de constructeur via la configuration Java peut également utiliser le processus de création automatique, tel que:

@Configuration
class AppConfig {
  @Bean
  public Bar bar() { return new Bar(); }

  @Bean
  public Foo foo(Bar bar) { return new Foo(bar); }
}


Modified text is an extract of the original Stack Overflow Documentation
Sous licence CC BY-SA 3.0
Non affilié à Stack Overflow