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.