Configuration et injection des dépendances dans le conteneur Spring

Détection automatique des composants

Configurer manuellement chaque classe via des balises XML devient rapidement fastidieux. Le framework Spring propose un mécanisme de scan du classpath pour identifier et enregistrer automatiquement les composants éligibles dans le contexte d'application.

L'annotation @Component indique explicitement qu'une classe doit être gérée par le conteneur d'inversion de contrôle. Par défaut, l'identifiant du bean correspond au nom de la classe avec la première lettre en minuscule. Il est possible de personnaliser cet identifiant directement via le paramètre de l'annotation.

/**
 * Marqueur pour la détection automatique.
 * L'identifiant par défaut sera "albumVinyle".
 */
@Component
public class AlbumVinyle implements AudioDisc {
    @Override
    public void lire() {
        System.out.println("Lecture audio en cours...");
    }
}

Lorsqu'une interface possède plusieurs implémentations, l'injection par type devient ambiguë. Spring résout cette situation en croisant @Autowired avec @Qualifier, permettant de cibler précisément le bean requis grâce à son identifiant personnalisé.

Pour activer le processus de scan, l'annotation @ComponentScan s'applique sur une classe de configuration. Elle cherche par défaut dans le package racine de la classe annotée, mais accepte une liste explicite de packages à indexer.

@Configuration
@ComponentScan(basePackages = "framework.audio")
public class ConfigurationLecteur {
}

Une alternative en XML consiste à utiliser la directive <context:component-scan base-package="framework.audio"/> au sein du fichier de définition des beans.

Intégration des tests unitaires

L'initialisation manuelle du ApplicationContext dans chaque test JUnit alourdit le code de vérification. Le module spring-test fournit des extensions capables de charger le conteneur automatiquement avant l'exécution des tests.

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-test</artifactId>
    <version>5.3.30</version>
    <scope>test</scope>
</dependency>

L'annotation @RunWith délègue l'exécution à un runner spécifique à Spring, tandis que @ContextConfiguration pointe vers les métadonnées de chargement.

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = ConfigurationLecteur.class)
public class VerificationLecteurTest {
    @Autowired
    private AudioDisc sourceAudio;

    @Test
    public void verifierLecture() {
        sourceAudio.lire();
        // Ajout des assertions unitaires ici
    }
}

Résolution automatique des dépendances

Le conteneur peut injecter les références nécessaires sans configuration explicite, en s'appuyant sur la méthode @Autowired. Cette annotation fonctionne indifféremment sur les constructeurs ou les accesseurs. Spring analyse la signature des méthodes et injecte les beans correspondants. En cas d'absence de candidat, le conteneur lève une exception, sauf si la propriété required est définie à false.

@Component
public class LecteurMultimedia implements DispositifLecture {
    private final AudioDisc disque;

    @Autowired
    public LecteurMultimedia(AudioDisc disque) {
        this.disque = disque;
    }

    // Injection par setter également supportée
    @Autowired
    public void definirDisque(AudioDisc nouveauDisque) {
        // Mise à jour dynamique ou validation
    }

    public void demarrer() {
        disque.lire();
    }
}

Configuration programmatique en Java

Lorsqu'il s'agit d'intégrer des bibliothèques tierces ne contrôlant pas le code source, les méthodes annotées @Bean offrent un moyen déclaratif de les intégrer au cycle de vie de Spring. Ces méthodes s'exécutent dans une classe marquée @Configuration. Les dépendances entre beans peuvent être déclarées directement via les paramètres des méthodes de définition.

@Configuration
@ComponentScan
public class ConfigurationApplication {
    @Bean
    public AudioDisc collectionMusique() {
        return new AlbumVinyle();
    }

    @Bean
    public LecteurMultimedia lecteurPrincipal(AudioDisc source) {
        return new LecteurMultimedia(source);
    }
}

Déclaration via fichiers XML

Les configurations traditionnelles s'appuient sur des fichiers XML structurés selon les schémas XSD de Spring. Le namespace racine xmlns="http://www.springframework.org/schema/beans" est indispensable.

Pour les injections par constructeur, Spring propose le namespace abrégé c: ou la balise standard <constructor-arg>. Les collections se définissent avec <list> ou <set>.

<bean id="monDisque" class="framework.audio.AlbumVinyle">
    <constructor-arg value="Titre Principal"/>
    <constructor-arg>
        <list>
            <value>Piste 01</value>
            <value>Piste 02</value>
        </list>
    </constructor-arg>
</bean>

<!-- Injection par référence via le namespace c -->
<bean id="lecteurAudio" class="framework.audio.LecteurMultimedia" c:_0-ref="monDisque"/>

L'injection par propriétés utilise le namespace p: ou la balise <property>. Pour externaliser et réutiliser des collections, le namespace util: permet de créer des références indépendantes.

<util:list id="listePistes">
    <value>Introduction</value>
    <value>Finale</value>
</util:list>

<bean id="disqueConfig" class="framework.audio.AlbumVinyle" p:titre="Compilation" p:pistes-ref="listePistes"/>

Fusion des configurations

Les projets complexes combinent souvent plusieurs sources de configuration. En Java, @Import permet d'incorporer d'autres classes de configuration, tandis que @ImportResource charge des fichiers XML externes. L'équivalent XML s'obtient via la balise <import> ou la déclaration directe d'un bean de configuration Java.

@Configuration
@Import(ConfigurationApplication.class)
@ImportResource("classpath:config-externes.xml")
public class ConfigurationRacine {
}

<import resource="config-externes.xml"/>
<bean class="framework.audio.ConfigurationApplication"/>

Étiquettes: Spring Framework Injection de dépendances Component Scanning JUnit Configuration XML

Publié le 11 septembre à 09h42