[JAVA] [Pour les débutants] DI ~ Les bases de DI et DI au printemps ~

introduction

DI est une abréviation pour Dependency Injection, et est souvent traduit par «injection de dépendance» en japonais.

Quand je suis entré en contact avec Spring pour la première fois lorsque j'étais un nouveau diplômé, la première chose qui m'est venue à l'esprit lorsque j'ai entendu ce concept était la marque Hatena. Le lien avec le concept de DI, de conteneur DI et d'annotations au printemps ne m'est pas venu à l'esprit.

Cette fois, pour moi-même quand j'étais débutant, je voudrais résumer brièvement le concept de DI et DI au printemps tout en l'organisant à ma manière.

Qu'est-ce que la dépendance?

Je pense qu'il est plus facile de comprendre ce qu'est une dépendance dans le code source.

Main.java


public class Main {
    public int hoge() {
        var sub = new Sub();
        return sub.calculate();
    }
}

Dans la méthode hoge de la classe Main, une instance de la classe Sub est créée et utilisée. Lorsqu'il existe une telle classe Main, elle est exprimée comme "La classe principale dépend de la sous-classe".

Je pense qu'il est relativement facile de comprendre les dépendances.

Qu'est-ce que l'injection?

Dans l'exemple précédent, une instance de la classe Sub a été créée en interne, mais la création d'une instance en externe et sa transmission à la classe qui l'utilise s'appelle injection.

Ici, un exemple utilisant un constructeur (injection de constructeur) est montré.

Main.java


public class Main {
    
    private Sub sub;
    
    public int hoge() {
        return sub.calculate();
    }
    
    //Injection de constructeur
    public Main(Sub sub) {
        this.sub = sub;
    }
}

Auparavant, nous avons créé une instance de la classe Sub dans la méthode hoge, mais dans cet exemple, l'instance est reçue du constructeur.

En faisant cela, lorsque vous utilisez réellement la classe Main,

var sub = new Sub();
var main = new Main(sub);

Sous la forme de, l'instance de la classe Sub est transmise depuis l'extérieur de la classe Main.

Les avantages de ceci seront décrits plus loin.

Qu'est-ce qu'un conteneur DI?

Lorsque vous entendez le mot conteneur, vous pouvez le considérer comme Docker dans les temps modernes, mais le conteneur dans le conteneur DI est différent du conteneur utilisé dans le contexte de Docker et ainsi de suite.

Si vous l'écrivez en un mot sans crainte de malentendu, le conteneur DI agit comme un "conteneur qui gère l'instance d'injection".

Si vous essayez d'utiliser la classe Main sans utiliser le conteneur DI comme auparavant, vous aurez besoin d'une instance de la classe Sub chaque fois que vous l'utilisez.

Si vous utilisez un conteneur DI, il gérera cette instance, vous n'avez donc pas à créer une instance à chaque fois.

Conteneur DI au printemps

Dans Spring, en spécifiant une classe avec une annotation, vous pouvez spécifier une instance de cette classe comme cible à gérer par le conteneur DI.

Plus précisément, les annotations suivantes.

En passant, l'instance gérée par le conteneur DI peut être obtenue à l'aide de la méthode getBean de la classe ApplicationContext.

Dans Spring, vous pouvez également définir la portée de la durée pendant laquelle le conteneur DI gère l'instance.

L'étendue qui peut être définie est la suivante et l'annotation Scope est utilisée lors de la définition.

La valeur par défaut de Spring est singleton, mais en modifiant le paramètre, il est possible de détruire et de reconfigurer l'instance gérée par le conteneur, par exemple, en unités de session.

Une chose que les débutants ont tendance à faire est de donner à la classe un champ qui peut changer, malgré le singleton. Un exemple est présenté ci-dessous.

hogeService


@Service
public class hogeService {
    
    private String result;
    
    public int fuga(String suffix) {
        result = "test" + suffix;        
        return result;
    }
}

Étant donné que l'annotation de service est ajoutée à hogeService et que la portée n'est pas définie en particulier, la portée est singleton.

En conséquence, vous courez le risque de modifier le champ de résultat dans une autre session, ce qui le rend non sécurisé.

En en faisant une variable au lieu d'un champ de classe comme indiqué ci-dessous, il devient une implémentation thread-safe.

hogeService


@Service
public class hogeService {
    
    public int fuga(String suffix) {
        String result = "test" + suffix;        
        return result;
    }
}

DI au printemps

Dans Spring, vous pouvez DI en utilisant l'annotation Autowired.

Il existe les trois méthodes d'injection suivantes, y compris l'injection de constructeur mentionnée précédemment.

Plus précisément, chacun est comme ça.

Main.java


public class Main {
    
    //Injection sur le terrain
    @Autowired
    private Sub sub;
    
    public int hoge() {
        return sub.calculate();
    }
}

Main.java


public class Main {
    
    private Sub sub;
    
    public int hoge() {
        return sub.calculate();
    }
    
    //Injection de poseur
    @Autowired
    public setSub(Sub sub) {
        this.sub = sub;
    }
}

Main.java


public class Main {
    
    private Sub sub;
    
    public int hoge() {
        return sub.calculate();
    }
    
    //Injection de constructeur
    @Autowired
    public Main(Sub sub) {
        this.sub = sub;
    }
}

En ajoutant l'annotation Autowired, il injectera des instances du conteneur DI dans les arguments des champs, des méthodes et des constructeurs.

D'ailleurs, quand je m'injecte, je l'écris en utilisant l'annotation RequiredArgsConstructor de Lombok dans la bibliothèque, comme décrit dans l'article ici.

Avantages de DI

Un mérite commun est qu'il facilite l'écriture de tests unitaires, Je pense que cela est vrai.

Voici à nouveau l'exemple du début.

Main.java


public class Main {
    public int hoge() {
        var sub = new Sub();
        return sub.calculate();
    }
}

Si la méthode de calcul de cette sous-classe était nécessaire pour accéder à la base de données, le test unitaire de la classe Main serait très difficile.

Cependant, il peut être testé en se moquant des instances injectées par DI. Au fait, j'utilise Mockito lorsque j'utilise une maquette.

Résumé

Enfin, ce qui suit est un résumé des conteneurs DI et DI en un mot.

DI: Passer une instance d'une classe qui dépend d'une classe de l'extérieur Conteneur DI: un conteneur qui gère l'instance à injecter

Leur utilisation présente l'avantage de faciliter l'écriture des tests et la gestion du périmètre.

C'est tout pour le contenu. Nous espérons que vous trouverez cet article utile. Merci d'avoir lu pour moi jusqu'à la fin.

Les références

Documentation officielle Core Technologies

Recommended Posts

[Pour les débutants] DI ~ Les bases de DI et DI au printemps ~
[Pour les débutants] Comprendre rapidement les bases de Java 8 lambda
[Pour les débutants] Explication des classes, des instances et des statiques en Java
La validation de printemps était importante dans l'ordre de Form et BindingResult
Memo of JSUG Study Group 2018 Partie 2-Efforts pour les spécifications de travail à l'ère du printemps et de l'API-
Définissez le nombre de secondes d'avance et de retour rapides dans ExoPlayer
[Introduction à Ruby] À propos du rôle de true et break in the while statement
[Rails] Articles pour les débutants pour organiser et comprendre le flux de form_with
Comparez la vitesse de l'instruction for et de l'instruction for étendue.
Quels sont les avantages de DI et de Thymeleaf?
[Introduction à Java] Bases de l'arithmétique Java (pour les débutants)
À propos de DI of Spring ①
À propos de DI of Spring ②
Les bases du printemps ~ Édition DI ~
Spécifiez le codage des ressources statiques dans Spring Boot
Jusqu'à l'utilisation de Spring Data et JPA Part 2
Jusqu'à l'utilisation de Spring Data et JPA Part 1
J'ai résumé les types et les bases des exceptions Java
Liste des instructions Java fréquemment utilisées (pour les débutants et les débutants)
[Ruby] Imbrication de classes, héritage et principes de base de soi
Vérifiez le comportement de getOne, findById et des méthodes de requête avec Spring Boot + Spring Data JPA
Surveillance Docker-expliquant les bases des bases-
J'ai essayé de résumer les bases de kotlin et java
Mettez le fichier dans les propriétés de string avec la configuration spring xml
Accélérez les tests des validateurs qui nécessitent DI dans Spring Boot
Une histoire remplie des bases de Spring Boot (résolu)
Saisissons l'image de fonctionnement (atmosphère) du conteneur DI de Spring
Les débutants en Java ont brièvement résumé le comportement de Array et ArrayList
Une introduction pratique pour les débutants de Spring 5 et Spring Boot 2 a été publiée
Créer plus d'onglets et de fragments dans le fragment de BottomNavigationView
[Spring Data JPA] La condition And peut-elle être utilisée dans la méthode de suppression implémentée automatiquement?
[Pour les débutants Swift] J'ai essayé de résumer le cycle de mise en page désordonné de ViewController et View
Traitement de branche avec la valeur de retour de RestTemplate et le code d'état de ResponseEntity dans Spring Boot
Je vais expliquer l'imbrication des déclarations qui tuent les débutants
Bases du branchement conditionnel et du retour
À propos des bases du développement Android
Spring Boot pour la première fois
[Pour les débutants] Résumé du constructeur java
Les débutants jouent à des jeux Janken en Java
[Java] Obtenez les dates des derniers lundi et dimanche dans l'ordre
Java pour les débutants, les expressions et les opérateurs 1
Obtenez une instance proxy du composant lui-même dans Spring Boot
[Pour les débutants] Exécutez Selenium sur Java
Les bases de SpringBoot + MyBatis + MySQL
[Pour les super débutants] Les connaissances minimales que vous voulez garder à l'esprit avec les hachages et les symboles
Java pour les débutants, les expressions et les opérateurs 2
Examinons la signification de "stream" et "collect" dans l'API Stream de Java.
Ceci et cela de JDK
Explication de Ruby on rails pour les débutants ⑤ ~ Modifier et supprimer la base de données ~
[Android Studio] [Pour les débutants] Expliquons grossièrement l'écran et le répertoire
Formulaire qui reçoit la valeur de l'élément répétitif dans Spring MVC
Ordre de traitement dans le programme
Spring AOP pour la première fois
[Android] Définir dynamiquement la hauteur de ListView avec copie (pour les débutants)
Classes et instances Java pour les débutants