30 Beans in Spring Boot

In Spring Boot sind Beans zentrale Bausteine, die durch den Spring IoC (Inversion of Control)-Container verwaltet werden. Eine Bean ist ein Objekt, das vom Spring-Framework instanziiert, konfiguriert und verwaltet wird. Beans repräsentieren die Komponenten und Services einer Spring-Anwendung und interagieren miteinander, um die gewünschte Geschäftslogik auszuführen.

In diesem Kapitel werden wir untersuchen, was Beans in Spring Boot sind, wie sie definiert, verwaltet und genutzt werden, und welche Rolle sie im IoC-Container spielen. Dabei gehen wir auf ihre Lebenszyklen, Konfigurationen und die wichtigsten Annotationen ein.

30.1 Was sind Beans?

Eine Bean in Spring ist ein Objekt, das vom Spring IoC-Container verwaltet wird. Beans werden typischerweise in einer Konfigurationsdatei (z.B. XML oder Java-Konfiguration) definiert oder über Annotationen in den Quellcode eingefügt. Der IoC-Container übernimmt die Verwaltung von Beans, einschließlich ihrer Abhängigkeiten, ihres Lebenszyklus und ihrer Sichtbarkeit innerhalb der Anwendung.

Beans in Spring Boot können durch Annotationen oder manuelle Konfiguration erstellt und verwaltet werden. In der Regel werden Beans in Spring Boot mithilfe von Annotationen wie @Component, @Service, @Repository oder @Controller definiert.

30.2 Bean-Definition und Instanziierung

Spring Boot verwendet standardmäßig eine Annotation-basierte Konfiguration. Beans werden automatisch vom Spring Framework erkannt und instanziiert, wenn die Klasse mit einer der oben genannten Annotationen versehen ist.

30.2.1 Definition von Beans mit @Component

Die Annotation @Component wird verwendet, um eine Klasse als Bean zu markieren, die vom IoC-Container verwaltet werden soll.

Beispiel: Bean-Definition mit @Component

import org.springframework.stereotype.Component;

@Component
public class MyComponent {
    public String getMessage() {
        return "Hello, Spring Boot!";
    }
}

In diesem Beispiel wird die Klasse MyComponent als Bean registriert, die automatisch vom IoC-Container instanziiert wird.

30.2.2 Weitere Stereotyp-Annotationen

Spring bietet mehrere Stereotyp-Annotationen, die spezialisierte Formen von @Component sind. Diese Annotationen erleichtern die Semantik und das Verständnis des Codes:

Beispiel: Bean-Definition mit @Service

import org.springframework.stereotype.Service;

@Service
public class MyService {
    public void performAction() {
        System.out.println("Geschäftslogik wird ausgeführt.");
    }
}

30.2.3 Manuelle Bean-Definition mit @Bean

Es ist auch möglich, Beans manuell in einer Konfigurationsklasse zu definieren. Dazu verwendet man die @Bean-Annotation in einer Klasse, die mit @Configuration annotiert ist.

Beispiel: Manuelle Bean-Definition

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class AppConfig {

    @Bean
    public MyComponent myComponent() {
        return new MyComponent();
    }
}

In diesem Fall wird die myComponent-Bean explizit in der Konfigurationsklasse AppConfig definiert.

30.3 Bean-Lebenszyklus

Jede Bean in Spring durchläuft einen festen Lebenszyklus, der vom IoC-Container verwaltet wird. Dieser Lebenszyklus umfasst mehrere Phasen, die sicherstellen, dass die Beans korrekt instanziiert, konfiguriert und schließlich zerstört werden.

30.3.1 Phasen des Bean-Lebenszyklus

  1. Instanziierung: Der IoC-Container erstellt eine Instanz der Bean.
  2. Dependency Injection: Der Container injiziert die erforderlichen Abhängigkeiten in die Bean (z.B. über Konstruktoren oder Setter).
  3. Initialisierung: Nach der Instanziierung kann die Bean eine Initialisierungslogik ausführen.
  4. Zerstörung: Vor der Entfernung der Bean kann eine Cleanup-Logik aufgerufen werden.

30.3.2 Initialisierung und Zerstörung von Beans

Um Initialisierungs- und Zerstörungsmethoden in einer Bean zu definieren, können die Annotationen @PostConstruct und @PreDestroy verwendet werden.

Beispiel: Bean-Initialisierung und -Zerstörung

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import org.springframework.stereotype.Component;

@Component
public class MyComponent {

    @PostConstruct
    public void init() {
        System.out.println("Bean wurde initialisiert.");
    }

    @PreDestroy
    public void destroy() {
        System.out.println("Bean wird zerstört.");
    }
}

In diesem Beispiel wird die Methode init() nach der Instanziierung der Bean aufgerufen, und die Methode destroy() wird vor der Zerstörung der Bean ausgeführt.

30.4 Singleton und Prototype Beans

In Spring gibt es verschiedene Scopes, die bestimmen, wie oft eine Bean instanziiert wird. Die beiden häufigsten Scopes sind:

30.4.1 Singleton Beans

Standardmäßig sind Beans in Spring als Singleton definiert. Das bedeutet, dass nur eine Instanz der Bean pro ApplicationContext erstellt wird.

Beispiel: Singleton-Scope

import org.springframework.stereotype.Component;

@Component
public class SingletonBean {
    public SingletonBean() {
        System.out.println("SingletonBean wird instanziiert.");
    }
}

Diese Bean wird nur einmal instanziiert, auch wenn sie mehrfach in verschiedenen Klassen injiziert wird.

30.4.2 Prototype Beans

Wenn eine Bean bei jeder Anforderung neu instanziiert werden soll, kann der Prototype-Scope verwendet werden. Dazu wird die Annotation @Scope("prototype") verwendet.

Beispiel: Prototype-Scope

import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

@Component
@Scope("prototype")
public class PrototypeBean {
    public PrototypeBean() {
        System.out.println("PrototypeBean wird instanziiert.");
    }
}

In diesem Fall wird eine neue Instanz der PrototypeBean jedes Mal erstellt, wenn sie angefordert wird.

30.5 Dependency Injection in Beans

Beans interagieren miteinander durch Dependency Injection. Dies ermöglicht es, Abhängigkeiten zwischen Komponenten zu verwalten, ohne sie direkt in den Klassen zu instanziieren. Spring Boot bietet verschiedene Möglichkeiten zur Durchführung von Dependency Injection, wie in dem Kapitel „Dependency Injection“ beschrieben.

30.5.1 Konstruktorbasierte Dependency Injection

Die Konstruktor-Injection wird in Spring als bevorzugte Methode angesehen, da sie sicherstellt, dass alle Abhängigkeiten bei der Instanziierung der Bean bereitgestellt werden.

Beispiel: Konstruktorbasierte Injection

import org.springframework.stereotype.Component;

@Component
public class OrderService {

    private final PaymentService paymentService;

    public OrderService(PaymentService paymentService) {
        this.paymentService = paymentService;
    }

    public void processOrder() {
        paymentService.processPayment();
    }
}

Hier wird die PaymentService-Bean über den Konstruktor injiziert.

30.6 Abhängigkeitshierarchie und Bean-Priorisierung

In einer Spring-Anwendung können mehrere Beans desselben Typs definiert sein. In diesem Fall wird der @Qualifier verwendet, um anzugeben, welche spezifische Bean verwendet werden soll.

Beispiel: Verwendung von @Qualifier

import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;

@Component
public class OrderService {

    private final PaymentService paymentService;

    public OrderService(@Qualifier("paypalService") PaymentService paymentService) {
        this.paymentService = paymentService;
    }

    public void processOrder() {
        paymentService.processPayment();
    }
}

In diesem Beispiel wird die spezifische paypalService-Bean injiziert, obwohl es möglicherweise mehrere PaymentService-Implementierungen gibt.

30.7 Beans mit Parametern oder Konfigurationen

Spring Beans können auch mit Parametern oder Konfigurationen versehen werden, die zur Laufzeit gesetzt werden. Dies geschieht oft in Konfigurationsklassen, in denen beans erstellt und konfiguriert werden.

Beispiel: Bean mit Parametern

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class AppConfig {

    @Bean
    public MyComponent myComponent() {
        MyComponent myComponent = new MyComponent();
        myComponent.setParameter("Wert");
        return myComponent;
    }
}

Hier wird die Bean myComponent manuell konfiguriert, bevor sie dem ApplicationContext hinzugefügt wird.

30.8 tl;dr

Beans sind fundamentale Bausteine in jeder Spring- und Spring Boot-Anwendung. Sie stellen die zentralen Komponenten dar, die vom IoC-Container verwaltet werden, und interagieren miteinander durch Dependency Injection. Durch die Verwendung von Beans wird der Code flexibler, wiederverwendbarer und leichter testbar. Spring bietet verschiedene Mechanismen zur Verwaltung und Konfiguration von Beans, einschließlich Singleton- und Prototype-Scopes, Initialisierungs- und Zerstörungslogik sowie der Definition von Abhängigkeiten zwischen Beans.