Spring Boot: Der Standard koreanischer Entwickler und die Umkehr der Kontrolle

📖 16min read

Ist Südkorea eine „Spring-Republik“?

Wenn man in Korea als Backend-Entwickler arbeiten will, gibt es eine Frage, der man kaum ausweichen kann: „Können Sie mit Spring arbeiten?“

Auf Jobportalen verlangen neun von zehn Stellenanzeigen ausdrücklich „Erfahrung mit Spring Boot“. Es gibt sogar den scherzhaften Ausdruck „Spring-Republik“. Als Student hielt ich das einfach für einen Trend.

„Warum nicht einfach in Java schreiben? Warum ausgerechnet das schwere Spring benutzen?“ „Ist Node.js oder Python (Django) nicht ohnehin leichter?“

Aber als ich in der Praxis große Projekte erlebt habe, wurde mir klar: Spring ist kein bloßer Trend. Es ist eine standardisierte Werkbank, die von unzähligen erfahrenen Entwicklern über Jahre verfeinert wurde, damit sich große und komplexe Enterprise-Systeme sicher und schnell bauen lassen.

Diese Serie erzählt davon, wie man auf genau dieser Werkbank ein nicht einstürzendes Schloss baut, einen Monolithen.

Framework: Warum man nicht alles nach eigenem Willen machen kann

Bevor wir richtig technisch werden, müssen wir zuerst einen Punkt klären. Was genau ist eigentlich ein Framework? Und worin unterscheidet es sich von einer Library?

Ich habe das in der letzten Re: Booting-Serie schon kurz erwähnt, aber der entscheidende Unterschied hängt an einer Frage: Wer hat die Kontrolle?

Spring ist ein Framework. Wer Spring benutzt, unterschreibt damit fast so etwas wie ein Gelöbnis: „Ich gebe meinen eigenen Stil ein Stück weit auf und arbeite so, wie Spring es vorgibt.“ Der Kern dieses „wie Spring es vorgibt“ ist genau das Thema von heute: die Inversion of Control, kurz IoC.

„Bitte hören Sie auf, ständig new zu benutzen“

Die erste Regel dieses Gelöbnisses war für mich ein Schock. Ausgerechnet auf den in Java grundlegendsten Operator, new, sollte man verzichten.

Im Studium war es völlig selbstverständlich: Wenn ich ein Objekt brauchte, schrieb ich MemberService service = new MemberService();. Ich brauche etwas, also erzeuge ich es selbst und benutze es. Was könnte natürlicher sein?

Doch als ich nach dem Berufseinstieg ein Spring-Boot-Projekt öffnete, sah ich nirgendwo das Schlüsselwort new. Stattdessen standen dort überall fremd wirkende Annotationen wie @Autowired oder @RequiredArgsConstructor.

„Moment mal, wenn ich das Objekt gar nicht erstelle, wie kann dann überhaupt eine Methode aufgerufen werden? Läuft das wirklich?“

Die Antwort eines Senior-Entwicklers klang zunächst ziemlich rätselhaft. „Der Spring Container fügt das schon ein, also müssen wir es nicht selbst erstellen. Im Gegenteil: Wenn du direkt mit new arbeitest, wird der Code später viel schwerer wartbar.“

Ich konnte das nicht akzeptieren. Ich war doch der Besitzer meines Codes, warum durfte ich dann nicht einmal ein Objekt frei erzeugen? Für mich fühlte sich das nach einer Diktatur durch Spring an.

Erstelle ich es selbst, oder verwende ich etwas, das mir jemand anders bereitstellt?

Der Koch und der Zutatenmanager (IoC & DI)

Um zu verstehen, warum diese scheinbar diktatorische Regel sinnvoll ist, wechseln wir die Welt und gehen in eine Restaurantküche.

1. Die traditionelle Art (ich habe die Kontrolle)

Ich bin ein Koch, also eine Class. Zum Kochen brauche ich ein Messer, also eine Dependency.

2. Springs Art (Spring hat die Kontrolle)

Ich bin immer noch der Koch. Aber diesmal gibt es einen Manager für Zutaten und Werkzeuge, den Spring Container.

Das heißt: Ich verwalte die Ressourcen, die ich brauche, nicht mehr selbst. Stattdessen werden sie von außen verwaltet und mir bereitgestellt. Genau das ist Inversion of Control (IoC), und die konkrete Technik dahinter heißt Dependency Injection (DI).

Injection bedeutet, die Entscheidung und Vorbereitung der Werkzeuge an jemand anderen abzugeben.

[Code Verification] Warum ist new gefährlich?

Nur mit Worten ist das schwer zu greifen. Vergleichen wir es direkt im Code. Angenommen, wir bauen ein System für Kartenzahlungen.

1. Schlechtes Beispiel: direkte Erzeugung (starke Kopplung)

public class PaymentService {
    // Ich habe selbst eine Samsung-Karte ausgewaehlt und erstellt (mit new)
    private final SamsungCard card = new SamsungCard();

    public void pay() {
        card.payment(); // Bezahlung nur mit Samsung-Karte moeglich
    }
}

Das Problem: Eines Tages sagt der Chef: „Wechseln wir zu Hyundai Card, die Gebühren sind günstiger.“ Dann muss ich im PaymentService den gesamten Code öffnen und jede SamsungCard durch HyundaiCard ersetzen. Und wenn dieser Code an hundert Stellen auftaucht? Dann ist Überstundenmodus angesagt.

2. Gutes Beispiel: Dependency Injection (lose Kopplung)

public class PaymentService {
    private final Card card; // Keinen konkreten Kartenanbieter angeben (Interface verwenden)

    // Constructor Injection: darauf vertrauen, dass jemand von aussen die Karte reicht
    public PaymentService(Card card) {
        this.card = card;
    }

    public void pay() {
        card.payment();
    }
}

Jetzt ist es dem PaymentService egal, welche konkrete Kartenimplementierung hereinkommt.

    Genau das ist der Kern von dem, was man in der Praxis als „gut wartbaren Code“ oder OCP-Prinzip bezeichnet. Diese Flexibilität ist der eigentliche Grund, warum man Spring Boot verwendet.

    Spring Container: ein Hotel für Objekte

    Wer ist also dieser „Manager“, der Objekte erzeugt und verteilt? Genau das ist der Spring Container.

    In dem Moment, in dem wir den Spring-Boot-Server mit run starten, passiert intern unglaublich viel.

    Unsere Aufgabe ist nur, auf die Klasse einen Aufkleber zu kleben, der sinngemäß sagt: „Bitte verwalten“, also zum Beispiel @Service. Den Rest übernimmt Spring wie ein riesiger Hotelmanager, der alle Gäste ordentlich eincheckt und verwaltet.

    Praktischer Rat: Verwende Konstruktor-Injektion

    Spring bietet mehrere Wege, Abhängigkeiten zu injizieren: Feldinjektion mit @Autowired, Setter-Injektion oder Konstruktor-Injektion. In der Praxis wird aber fast immer die Konstruktor-Injektion empfohlen. Genau das ist auch das Muster mit Lomboks @RequiredArgsConstructor.

    @Service
    @RequiredArgsConstructor // Das erzeugt die Constructor Injection automatisch.
    public class OrderService {
        // final kann verwendet werden, also sicher
        private final PaymentService paymentService;
    }
    
    

    Warum?

    Zum Schluss: kein Magier, sondern ein Dirigent

    Anfangs fühlte es sich so an, als würde Spring mit meinem Code machen, was es will, und genau deshalb sträubte ich mich dagegen. Heute sehe ich es anders. Spring ist kein Diktator, der mich schikaniert, sondern ein fähiger Dirigent, der komplexe Beziehungen zwischen Objekten ordnet.

    Dadurch verbringe ich weniger Zeit mit der Frage „Welches Objekt muss ich erzeugen?“ und kann mich stärker darauf konzentrieren, „Wie baue ich mit diesem Objekt die eigentliche Business-Logik?“ Wahrscheinlich genau deshalb sind so viele Entwickler in Korea so begeistert von Spring.

    Jetzt haben wir die Verwaltung der Objekte an Spring übergeben. Der Server ist startklar. Aber eine Webanwendung läuft nicht allein. Sie muss mit dem Frontend sprechen. In der PHP-Zeit war es bequem, weil HTML und Code in einer einzigen Datei lagen. Warum trennt man heute Frontend-Entwicklung mit Vue oder React vom Backend? Und warum erscheint plötzlich ein roter CORS-Fehler, sobald man beides verbindet?

    Beim nächsten Mal schauen wir uns den Wandel der Webarchitektur, SSR vs. CSR, und die wahre Identität von CORS an, der Mauer zwischen beiden.

    Schreibe einen Kommentar