Konstruktorinjektion im Frühjahr mit Lombok

1. Einleitung

Lombok ist eine äußerst nützliche Bibliothek zur Überwindung von Boilerplate-Code. Wenn Sie noch nicht damit vertraut sind, empfehle ich dringend, das vorherige Tutorial - Einführung in Project Lombok - zu lesen.

In diesem Artikel werden wir seine Verwendbarkeit in Kombination mit der konstruktorbasierten Abhängigkeitsinjektion von Spring demonstrieren .

2. Konstruktorbasierte Abhängigkeitsinjektion

Eine gute Möglichkeit, Abhängigkeiten im Frühjahr mithilfe einer auf Konstruktoren basierenden Abhängigkeitsinjektion zu verkabeln . Dieser Ansatz zwingt uns, die Abhängigkeiten der Komponenten explizit an einen Konstruktor zu übergeben.

Im Gegensatz zur feldbasierten Abhängigkeitsinjektion bietet sie auch eine Reihe von Vorteilen:

  • Es muss keine testspezifische Konfigurationskomponente erstellt werden. Abhängigkeiten werden explizit in einen Konstruktor eingefügt
  • konsistentes Design - alle erforderlichen Abhängigkeiten werden durch die Konstruktordefinition hervorgehoben und berücksichtigt
  • einfache Unit-Tests - reduzierter Overhead von Spring Framework
  • zurückgewonnene Freiheit bei der Verwendung endgültiger Schlüsselwörter

Aufgrund der Notwendigkeit, einen Konstruktor zu schreiben, führt dies jedoch zu einer erheblich größeren Codebasis. Betrachten Sie die beiden Beispiele für GreetingService und FarewellService:

@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"); } }

Grundsätzlich machen beide Komponenten dasselbe - sie rufen einen konfigurierbaren Übersetzer mit einem aufgabenspezifischen Wort auf.

Die zweite Variante ist jedoch aufgrund des Boilerplates des Konstruktors, das dem Code keinen wirklichen Wert verleiht, viel verschleierter.

In der neuesten Spring-Version muss der Konstruktor nicht mit @ Autowired- Annotation versehen werden.

3. Konstruktorinjektion mit Lombok

Mit Lombok ist es möglich, einen Konstruktor entweder für alle Felder der Klasse (mit @AllArgsConstructor ) oder für alle Felder der letzten Klasse (mit @RequiredArgsConstructor ) zu generieren . Wenn Sie noch einen leeren Konstruktor benötigen, können Sie außerdem eine zusätzliche Annotation @NoArgsConstructor anhängen .

Erstellen wir eine dritte Komponente, analog zu den beiden vorherigen:

@Component @RequiredArgsConstructor public class ThankingService { private final Translator translator; public String produce() { return translator.translate("thank you"); } }

Die obige Annotation veranlasst Lombok , einen Konstruktor für uns zu generieren:

@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. Mehrere Konstruktoren

Ein Konstruktor muss nicht mit Anmerkungen versehen werden, solange eine Komponente nur eine enthält und Spring sie eindeutig als die richtige auswählen kann, um ein neues Objekt zu instanziieren. Sobald mehr vorhanden sind, müssen Sie auch die Anmerkung angeben, die vom IoC-Container verwendet werden soll.

Betrachten Sie das ApologizeService- Beispiel:

@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); } }

Die obige Komponente kann optional mit dem Nachrichtenfeld konfiguriert werden, das sich nach dem Erstellen der Komponente nicht ändern kann (daher das Fehlen eines Setters ). Daher mussten wir zwei Konstruktoren bereitstellen - einen mit vollständiger Konfiguration und einen impliziten Standardwert der Nachricht .

Wenn einer der Konstruktoren nicht mit @Autowired , @Inject oder @Resource versehen ist , gibt Spring einen Fehler aus:

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

Wenn wir den von Lombok generierten Konstruktor mit Anmerkungen versehen möchten , müssen wir die Anmerkung mit einem onConstructor- Parameter des @AllArgsConstructor übergeben :

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

Der Parameter onConstructor akzeptiert ein Array von Annotationen (oder eine einzelne Annotation wie in diesem speziellen Beispiel), die auf einen generierten Konstruktor gesetzt werden sollen. Die doppelte Unterstreichungssprache wurde aufgrund von Abwärtskompatibilitätsproblemen eingeführt. Laut Dokumentation:

Der Grund für die seltsame Syntax ist, dass diese Funktion in Javac 7-Compilern funktioniert. Der @__Typ ist eine Annotationsreferenz auf den Annotationstyp __(doppelter Unterstrich), der tatsächlich nicht vorhanden ist. Dies führt dazu, dass javac 7 den Kompilierungsprozess aufgrund eines Fehlers verzögert, da es möglich ist, dass ein Anmerkungsprozessor den __Typ später erstellt .

5. Zusammenfassung

In diesem Tutorial haben wir gezeigt, dass es nicht erforderlich ist, feldbasiertes DI gegenüber konstruktorbasiertem DI in Bezug auf erhöhten Boilerplate-Code zu bevorzugen.

Dank Lombok ist es möglich, die allgemeine Codegenerierung zu automatisieren, ohne die Leistung auf die Laufzeit zu beeinträchtigen. Dadurch wird langer, undurchsichtiger Code durch die Verwendung einer einzeiligen Anmerkung abgekürzt.

Der im Tutorial verwendete Code ist auf GitHub verfügbar.