Konstruktorinjektion im Frühjahr mit Lombok

Konstruktorinjektion im Frühjahr mit Lombok

1. Einführung

Lombok ist eine äußerst nützliche Bibliothek zur Überwindung von Boilerplate-Code. Wenn Sie noch nicht damit vertraut sind, empfehle ich dringend, einen Blick auf das vorherige Tutorial zu werfen -Introduction to Project Lombok.

In diesem Artikel zeigen wir die Verwendbarkeit in Kombination mit denConstructor-Based Dependency Injectionvon Spring.

2. Konstruktorbasierte Abhängigkeitsinjektion

Ein guter Weg, um Abhängigkeiten im Frühjahr mit constructor-based Dependency Injection zu verkabeln. Dieser Ansatz zwingt uns, die Abhängigkeiten der Komponenten explizit an einen Konstruktor zu übergeben.

Im Gegensatz zuField-Based Dependency Injection bietet es 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 Komponententests - reduzierter Overhead von Spring Framework

  • die Freiheit der Verwendung der Schlüsselwörter vonfinalzurückgewonnen

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

@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 ein konfigurierbaresTranslator mit einem aufgabenspezifischen Wort auf.

Die zweite Variante ist jedoch viel verschleierter, da die Konstruktionsplatte des Konstruktors dem Code keinen wirklichen Wert verleiht.

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

3. Konstruktorinjektion mit Lombok

MitLombok ist es möglich, einen Konstruktor entweder für alle Felder der Klasse (mit@AllArgsConstructor) oder für alle Felder der Klassefinal(mit@RequiredArgsConstructor) zu generieren. Wenn Sie noch einen leeren Konstruktor benötigen, können Sie außerdem eine zusätzliche Annotation von@NoArgsConstructoranhä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 bewirkt, dassLombok einen Konstruktor für uns generiert:

@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 Anmerkungen hinzufügen, die vom IoC-Container verwendet werden soll.

Betrachten Sie das Beispiel vonApologizeService:

@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 Feldmessage konfiguriert werden, das sich nach dem Erstellen der Komponente nicht ändern kann (daher das Fehlen vonsetter). Daher mussten wir zwei Konstruktoren bereitstellen - einen mit vollständiger Konfiguration und einen impliziten Standardwert vonmessage.

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 generierten KonstruktorLombok-annotieren wollten, müssten wir die Annotation mit einemonConstructor-Parameter von@AllArgsConstructor übergeben:

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

Der ParameteronConstructor akzeptiert ein Array von Annotationen (oder eine einzelne Annotation wie in diesem speziellen Beispiel), die auf einen generierten Konstruktor gesetzt werden sollen. Das doppelte Unterstrich-Idiom wurde aufgrund von Problemen mit der Abwärtskompatibilität eingeführt. Nach der 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 später den Typ__erstellt.

5. Zusammenfassung

In diesem Tutorial haben wir gezeigt, dass es nicht erforderlich ist, feldbasierte DI gegenüber konstruktorbasierten DI zu bevorzugen, wenn der Code für die Boilerplate erhöht wird.

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 Lernprogramm verwendete Code istover on GitHub verfügbar.