Injection de constructeur au printemps à Lombok

Injection de constructeur au printemps à Lombok

1. introduction

Lombok est une bibliothèque extrêmement utile pour surmonter le code standard. Si vous ne le connaissez pas encore, je vous recommande vivement de consulter le tutoriel précédent -Introduction to Project Lombok.

Dans cet article, nous allons démontrer sa convivialité lorsqu'il est combiné avec lesConstructor-Based Dependency Injection de Spring.

2. Injection de dépendances basée sur le constructeur

Un bon moyen de câbler les dépendances dans Spring en utilisant constructor-based Dependency Injection. Cette approche nous oblige à passer explicitement les dépendances des composants à un constructeur.

Contrairement àField-Based Dependency Injection, il offre également un certain nombre d'avantages:

  • pas besoin de créer un composant de configuration spécifique au test - les dépendances sont injectées explicitement dans un constructeur

  • conception cohérente - toutes les dépendances requises sont soulignées et traitées par la définition du constructeur

  • tests unitaires simples - réduction des frais généraux de Spring Framework

  • liberté récupérée d'utiliser les mots-clésfinal

Cependant, en raison de la nécessité d'écrire un constructeur, il est généralement utilisé pour créer une base de code considérablement plus grande. Prenons les deux exemples deGreetingService etFarewellService:

@Component
public class GreetingService {

    @Autowired
    private Translator translator;

    public String produce() {
        return translator.translate("hello");
    }
}
@Component
public class FarewellService {

    private final Translator translator;

    public FarewellService(Translator translator) {
        this.translator = translator;
    }

    public String produce() {
        return translator.translate("bye");
    }
}

Fondamentalement, les deux composants font la même chose - ils appellent unTranslator configurable avec un mot spécifique à la tâche.

La deuxième variante, cependant, est beaucoup plus obscure en raison du passe-partout du constructeur qui n’apporte pas vraiment de valeur au code.

Dans la dernière version de Spring, le constructeur n'a pas besoin d'être annoté avec l'annotation@Autowired.

3. Injection de constructeur avec Lombok

AvecLombok, il est possible de générer un constructeur pour tous les champs de la classe (avec@AllArgsConstructor) ou tous les champs de la classefinal (avec@RequiredArgsConstructor). De plus, si vous avez toujours besoin d'un constructeur vide, vous pouvez ajouter une annotation@NoArgsConstructor supplémentaire.

Créons un troisième composant, analogue aux deux précédents:

@Component
@RequiredArgsConstructor
public class ThankingService {

    private final Translator translator;

    public String produce() {
        return translator.translate("thank you");
    }
}

L'annotation ci-dessus amèneraLombok à générer un constructeur pour nous:

@Component
public class ThankingService {

    private final Translator translator;

    public String thank() {
        return translator.translate("thank you");
    }

    /* Generated by Lombok */
    public ThankingService(Translator translator) {
        this.translator = translator;
    }
}

4. Constructeurs multiples

Un constructeur n'a pas besoin d'être annoté tant qu'il n'y en a qu'un dans un composant et Spring peut sans ambiguïté le choisir comme le bon pour instancier un nouvel objet. Une fois qu'il y en a plus, vous devez également annoter celui qui doit être utilisé par le conteneur IoC.

Prenons l'exemple deApologizeService:

@Component
@RequiredArgsConstructor
public class ApologizeService {

    private final Translator translator;
    private final String message;

    @Autowired
    public ApologizeService(Translator translator) {
        this(translator, "sorry");
    }

    public String produce() {
        return translator.translate(message);
    }
}

Le composant ci-dessus est éventuellement configurable avec le champmessage qui ne peut pas changer après la création du composant (d'où l'absence d'unsetter). Il nous a donc fallu fournir deux constructeurs - l'un avec une configuration complète et l'autre avec une valeur implicite par défaut desmessage.

À moins que l'un des constructeurs ne soit annoté avec@Autowired,@Inject ou@Resource, Spring lancera une erreur:

Failed to instantiate [...]: No default constructor found;

Si nous voulions annoter le constructeur généré parLombok-, il faudrait passer l'annotation avec un paramètreonConstructor du@AllArgsConstructor:

@Component
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class ApologizeService {
    // ...
}

Le paramètreonConstructor accepte un tableau d'annotations (ou une seule annotation comme dans cet exemple spécifique) qui doivent être placées sur un constructeur généré. Le double soulignement a été introduit en raison de problèmes de compatibilité ascendante. Selon la documentation:

La raison de la syntaxe étrange est de faire fonctionner cette fonctionnalité dans les compilateurs javac 7; le type@__ est une référence d'annotation au type d'annotation__ (double tiret bas) qui n'existe pas réellement; cela fait que javac 7 retarde l'abandon du processus de compilation en raison d'une erreur car il est possible qu'un processeur d'annotation crée plus tard le type__.

5. Sommaire

Dans ce didacticiel, nous avons montré qu'il n'était pas nécessaire de privilégier l'ID basée sur le champ par rapport à l'ID basée sur le constructeur en termes d'augmentation du code standard.

Grâce à Lombok, il est possible d'automatiser la génération de code commun sans impact sur les performances de l'exécution, en abrégeant le code long et obscurcissant à l'utilisation d'une annotation sur une seule ligne.

Le code utilisé lors du tutoriel est disponibleover on GitHub.