Zum Hauptinhalt springen

Woche 1, Tag 4 — Dependency Injection im Detail

Ziel

Heute vertiefst du Dependency Injection.

Die Kernfragen:

  1. Was ist Dependency Injection?
  2. Warum nutzt Spring Dependency Injection?
  3. Welche Arten von Dependency Injection gibt es?
  4. Warum wird Constructor Injection empfohlen?
  5. Was ist Autowiring?
  6. Was passiert, wenn mehrere Beans zu einer Abhängigkeit passen?
  7. Was ist @Primary?
  8. Was ist @Qualifier?
  9. Wie injiziert man alle Beans eines Typs?
  10. Wie macht man Abhängigkeiten optional?
  11. Welche typischen Prüfungsfallen gibt es?

1. Kurz-Wiederholung

Aus den bisherigen Lektionen:

  • Spring verwaltet Objekte — Beans.
  • ApplicationContext ist der zentrale Spring-Container.
  • Eine Bean ist ein von Spring verwaltetes Objekt.
  • Spring kann eine Bean in eine andere injizieren.
  • Dependency Injection ist eine Technik, mit der Spring IoC umsetzt.

Merksatz:


IoC ist die Idee. Dependency Injection ist die Technik.

2. Was ist eine Abhängigkeit?

Eine Abhängigkeit ist ein Objekt, das ein anderes Objekt für seine Arbeit braucht.

Beispiel:


public class OrderService {

private final OrderRepository orderRepository;

public OrderService(OrderRepository orderRepository) {
this.orderRepository = orderRepository;
}
}

Hier:


OrderRepository ist eine Abhängigkeit von OrderService.

Weil OrderService OrderRepository braucht.


3. Was ist Dependency Injection?

Dependency Injection heißt:

Eine Klasse bekommt ihre Abhängigkeiten von außen — statt sie selbst zu erzeugen.

Schlecht:


public class OrderService {

private final OrderRepository orderRepository;

public OrderService() {
this.orderRepository = new OrderRepository();
}
}

Besser:


public class OrderService {

private final OrderRepository orderRepository;

public OrderService(OrderRepository orderRepository) {
this.orderRepository = orderRepository;
}
}

In der besseren Version erzeugt OrderService OrderRepository nicht selbst.

Er bekommt es geliefert.

Das ist Dependency Injection.


4. Warum ist Dependency Injection nützlich?

Dependency Injection macht Code:

  • leichter testbar
  • leichter änderbar
  • leichter wartbar
  • weniger eng gekoppelt
  • flexibler
  • einfacher für Spring zu verwalten

Ohne DI:


this.orderRepository = new OrderRepository();

Mit DI:


public OrderService(OrderRepository orderRepository) {
this.orderRepository = orderRepository;
}

Jetzt kannst du verschiedene Implementierungen übergeben:


JpaOrderRepository
JdbcOrderRepository
MockOrderRepository
InMemoryOrderRepository

5. Vergleich mit React / TypeScript

In React übergibst du oft Daten oder Funktionen von außen.

Beispiel:


function UserCard({ user }) {
return <div>{user.name}</div>;
}

UserCard erzeugt den User nicht selbst.

Er bekommt ihn von außen.

In Spring:


@Service
public class UserService {

private final UserRepository userRepository;

public UserService(UserRepository userRepository) {
this.userRepository = userRepository;
}
}

UserService erzeugt UserRepository nicht selbst.

Er bekommt es von außen.

Der Unterschied:


React übergibt Props.
Spring injiziert Abhängigkeiten.

6. Dependency Injection in Spring

Beispiel:


@Repository
public class OrderRepository {
}

@Service
public class OrderService {

private final OrderRepository orderRepository;

public OrderService(OrderRepository orderRepository) {
this.orderRepository = orderRepository;
}
}

Spring macht:


1. OrderRepository-Bean erzeugen
2. OrderService-Bean erzeugen
3. Sehen: OrderService braucht OrderRepository
4. OrderRepository in OrderService-Konstruktor injizieren

7. Was ist Autowiring?

Autowiring heißt:

Spring findet und injiziert die benötigte Abhängigkeit automatisch.

Beispiel:


@Service
public class OrderService {

private final OrderRepository orderRepository;

public OrderService(OrderRepository orderRepository) {
this.orderRepository = orderRepository;
}
}

Spring sieht:


OrderService braucht OrderRepository.

Dann sucht Spring im ApplicationContext nach einer Bean vom Typ:


OrderRepository

Gibt es genau eine passende Bean, injiziert Spring sie.


8. Ist @Autowired nötig?

Modernes Spring:

Hat eine Klasse nur einen Konstruktor, ist @Autowired optional.

Das funktioniert:


@Service
public class OrderService {

private final OrderRepository orderRepository;

public OrderService(OrderRepository orderRepository) {
this.orderRepository = orderRepository;
}
}

Das auch:


@Service
public class OrderService {

private final OrderRepository orderRepository;

@Autowired
public OrderService(OrderRepository orderRepository) {
this.orderRepository = orderRepository;
}
}

Prüfungsfalle:

@Autowired auf einem einzigen Konstruktor ist in modernem Spring optional.


9. Arten von Dependency Injection

Spring unterstützt drei gängige Arten:

  1. Constructor Injection
  2. Setter Injection
  3. Field Injection

10. Constructor Injection

Dependencies kommen über den Konstruktor.

Beispiel:


@Service
public class OrderService {

private final OrderRepository orderRepository;
private final PaymentService paymentService;

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

Empfohlener Stil für erforderliche Abhängigkeiten.


11. Warum Constructor Injection empfohlen wird

Constructor Injection ist empfohlen, weil:

  • Abhängigkeiten explizit sind
  • Felder final sein können
  • das Objekt nicht ohne Pflicht-Abhängigkeiten entstehen kann
  • Tests einfacher werden
  • Immutability unterstützt wird
  • das Klassendesign klarer wird
  • versteckte Abhängigkeiten vermieden werden

Beispiel:


private final OrderRepository orderRepository;

Das heißt:


OrderRepository ist erforderlich und kann nach der Erzeugung nicht geändert werden.

12. Constructor Injection und Tests

Constructor Injection macht Tests einfach.

Service:


public class OrderService {

private final OrderRepository orderRepository;

public OrderService(OrderRepository orderRepository) {
this.orderRepository = orderRepository;
}
}

Test:


OrderRepository fakeRepository = new FakeOrderRepository();
OrderService service = new OrderService(fakeRepository);

Du brauchst Spring nicht, um diese Klasse zu testen.

Das ist gut.


13. Setter Injection

Die Abhängigkeit kommt über eine Setter-Methode.

Beispiel:


@Service
public class ReportService {

private AuditService auditService;

@Autowired
public void setAuditService(AuditService auditService) {
this.auditService = auditService;
}
}

Setter Injection meist für optionale Abhängigkeiten.


14. Wann Setter Injection?

Setter Injection, wenn:

  • die Abhängigkeit optional ist
  • sie sich nach der Objekterzeugung ändern kann
  • du Konstruktor-Overload vermeiden willst
  • Framework-Konfiguration es braucht

Für erforderliche Abhängigkeiten: Constructor Injection.

Merksatz:


Constructor Injection für erforderliche Abhängigkeiten.
Setter Injection für optionale Abhängigkeiten.

15. Field Injection

Spring injiziert direkt in ein Feld.

Beispiel:


@Service
public class OrderService {

@Autowired
private OrderRepository orderRepository;
}

Funktioniert — ist aber nicht empfohlen.


16. Warum Field Injection nicht empfohlen wird

Field Injection ist nicht empfohlen, weil:

  • Abhängigkeiten versteckt sind
  • Felder nicht final sein können
  • Tests ohne Spring schwerer sind
  • das Objekt ohne Pflicht-Abhängigkeiten existieren kann
  • schlechtes Design gefördert wird
  • Abhängigkeiten weniger sichtbar sind

Schlecht:


@Autowired
private OrderRepository orderRepository;

Besser:


private final OrderRepository orderRepository;

public OrderService(OrderRepository orderRepository) {
this.orderRepository = orderRepository;
}

Merksatz:

Field Injection funktioniert — Constructor Injection ist aber bevorzugt.


17. Constructor vs. Setter vs. Field Injection

TypAm besten fürEmpfohlen?
Constructor Injectionerforderliche Depsja
Setter Injectionoptionale Depsmanchmal
Field Injectionschnelle Demosmeiden

18. Praxisbeispiel: Service mit Repository


@Repository
public class OrderRepository {

public void save(String orderName) {
System.out.println("Saving order: " + orderName);
}
}

@Service
public class OrderService {

private final OrderRepository orderRepository;

public OrderService(OrderRepository orderRepository) {
this.orderRepository = orderRepository;
}

public void createOrder(String orderName) {
orderRepository.save(orderName);
}
}

Spring erzeugt beide Beans und injiziert OrderRepository in OrderService.


19. Injektion per Interface

Sehr häufig in Spring.

Interface:


public interface NotificationSender {
void send(String message);
}

Implementierung:


@Component
public class EmailNotificationSender implements NotificationSender {

@Override
public void send(String message) {
System.out.println("Email: " + message);
}
}

Service:


@Service
public class OrderService {

private final NotificationSender notificationSender;

public OrderService(NotificationSender notificationSender) {
this.notificationSender = notificationSender;
}
}

Spring kann EmailNotificationSender injizieren, weil es NotificationSender implementiert.


20. Warum per Interface injizieren?

Reduziert Kopplung.

OrderService hängt ab von:


NotificationSender

nicht direkt von:


EmailNotificationSender

Später kannst du austauschen gegen:


SmsNotificationSender
PushNotificationSender
MockNotificationSender

ohne OrderService zu ändern.


21. Was passiert bei genau einer Bean?

Gibt es genau eine Bean des benötigten Typs, funktioniert die Injektion.

Beispiel:


Benötigt: NotificationSender

Verfügbare Beans:
- emailNotificationSender

Ergebnis:
Spring injiziert emailNotificationSender.

22. Was passiert, wenn keine Bean existiert?

Beispiel:


@Service
public class OrderService {

public OrderService(NotificationSender notificationSender) {
}
}

Aber keine Bean implementiert NotificationSender.

Dann startet Spring nicht.

Typischer Fehler:


No qualifying bean of type 'NotificationSender' available

Bedeutung:


Spring hat keine passende Bean zum Injizieren gefunden.

23. Was passiert bei mehreren Beans?

Beispiel:


@Component
public class EmailNotificationSender implements NotificationSender {
}

@Component
public class SmsNotificationSender implements NotificationSender {
}

Jetzt hat Spring zwei Beans vom Typ NotificationSender.

Wenn du schreibst:


public OrderService(NotificationSender notificationSender) {
}

hat Spring ein Problem:


Welche soll ich injizieren?
emailNotificationSender oder smsNotificationSender?

Die App startet nicht — die Abhängigkeit ist mehrdeutig.


24. Mehrdeutigkeit auflösen

Gängige Lösungen:

  1. @Primary nutzen
  2. @Qualifier nutzen
  3. Liste aller Beans injizieren
  4. Map aller Beans injizieren
  5. Spezifischeren Typ nutzen

25. @Primary

@Primary heißt:

Nimm diese Bean als Standard, wenn mehrere Kandidaten existieren.

Beispiel:


@Component
@Primary
public class EmailNotificationSender implements NotificationSender {
}

@Component
public class SmsNotificationSender implements NotificationSender {
}

Jetzt funktioniert das:


public OrderService(NotificationSender notificationSender) {
}

Spring injiziert:


EmailNotificationSender

weil sie als @Primary markiert ist.


26. Wann @Primary nutzen?

Wenn eine Implementierung meistens der Standard sein soll.

Beispiel:


PaymentProvider
- StripePaymentProvider als Standard
- PaypalPaymentProvider als Sonderfall

Dann:


@Component
@Primary
public class StripePaymentProvider implements PaymentProvider {
}

27. @Qualifier

@Qualifier heißt:

Injiziere genau diese Bean.

Beispiel:


@Service
public class OrderService {

private final NotificationSender notificationSender;

public OrderService(
@Qualifier("smsNotificationSender") NotificationSender notificationSender
) {
this.notificationSender = notificationSender;
}
}

Spring injiziert:


smsNotificationSender

28. @Primary vs. @Qualifier

AnnotationBedeutung
@PrimaryStandardwahl
@Qualifierexakte Wahl

Merksatz:


@Primary ist die Standardwahl. @Qualifier ist die exakte Wahl.

Wenn beides da ist:


@Qualifier gewinnt — es ist spezifischer.

29. Bean-Namen und Qualifier-Namen

Standard-Bean-Name:


@Component
public class EmailNotificationSender implements NotificationSender {
}

Standard-Name:


emailNotificationSender

Also:


@Qualifier("emailNotificationSender")

Eigener Bean-Name:


@Component("emailSender")
public class EmailNotificationSender implements NotificationSender {
}

Dann:


@Qualifier("emailSender")

30. Alle Beans eines Typs injizieren

Manchmal willst du nicht eine Bean — sondern alle Implementierungen.

Beispiel:


@Component
public class NotificationManager {

private final List<NotificationSender> senders;

public NotificationManager(List<NotificationSender> senders) {
this.senders = senders;
}

public void notifyAll(String message) {
for (NotificationSender sender : senders) {
sender.send(message);
}
}
}

Wenn Spring hat:


emailNotificationSender
smsNotificationSender
pushNotificationSender

injiziert Spring alle in die Liste.


31. Map von Beans injizieren

Spring kann auch eine Map injizieren.


@Component
public class NotificationManager {

private final Map<String, NotificationSender> senders;

public NotificationManager(Map<String, NotificationSender> senders) {
this.senders = senders;
}
}

Die Map-Keys sind Bean-Namen.

Beispiel:


emailNotificationSender -> EmailNotificationSender
smsNotificationSender -> SmsNotificationSender

Nützlich, wenn du die Implementierung dynamisch wählen willst.


32. Reihenfolge bei injizierten Listen

Bei Listen willst du vielleicht eine bestimmte Reihenfolge.

Nutze @Order:


@Component
@Order(1)
public class EmailNotificationSender implements NotificationSender {
}

@Component
@Order(2)
public class SmsNotificationSender implements NotificationSender {
}

Spring injiziert die Liste in dieser Reihenfolge.


33. Optionale Abhängigkeiten

Manchmal existiert eine Abhängigkeit vielleicht nicht.

Optionen:


Optional<T>
ObjectProvider<T>
@Nullable

34. Optionale Abhängigkeit mit Optional


@Service
public class ReportService {

private final Optional<AuditService> auditService;

public ReportService(Optional<AuditService> auditService) {
this.auditService = auditService;
}
}

Existiert AuditService, injiziert Spring sie.

Sonst injiziert Spring Optional.empty().


35. Optionale Abhängigkeit mit ObjectProvider

ObjectProvider ist flexibler.


@Service
public class ReportService {

private final ObjectProvider<AuditService> auditServiceProvider;

public ReportService(ObjectProvider<AuditService> auditServiceProvider) {
this.auditServiceProvider = auditServiceProvider;
}

public void generateReport() {
AuditService auditService = auditServiceProvider.getIfAvailable();

if (auditService != null) {
auditService.audit("Report generated");
}
}
}

Nützlich, wenn:

  • die Bean vielleicht nicht existiert
  • du lazy zugreifen willst
  • du die Abhängigkeit nicht zu früh erzeugen willst
  • du alle passenden Beans dynamisch holen willst

36. Optionale Abhängigkeit mit @Nullable


@Service
public class ReportService {

public ReportService(@Nullable AuditService auditService) {
if (auditService != null) {
auditService.audit("ReportService created");
}
}
}

Funktioniert — Optional oder ObjectProvider sind oft klarer.


37. Zirkuläre Abhängigkeiten

Zirkuläre Abhängigkeit: zwei Beans hängen voneinander ab.

Beispiel:


@Service
public class AService {

public AService(BService bService) {
}
}

@Service
public class BService {

public BService(AService aService) {
}
}

Problem:


AService braucht BService.
BService braucht AService.
Spring kann keines sauber erzeugen.

38. Warum zirkuläre Abhängigkeiten schlecht sind

Sie zeigen oft ein Designproblem.

Zwei Klassen wissen zu viel voneinander.

Besseres Design:

  • gemeinsame Logik in einen dritten Service auslagern
  • Events nutzen
  • Verantwortlichkeiten trennen
  • Domain-Grenzen überdenken

Fix-Beispiel:


AService -> CommonService
BService -> CommonService

Statt:


AService <-> BService

39. Kann Spring zirkuläre Abhängigkeiten handhaben?

Manchmal mit Setter- oder Field Injection.

Constructor-basierte Zirkularität ist aber meist ein ernstes Problem.

Modernes Spring Boot ist strenger bei Circular References.

Merksatz:

Constructor Injection macht zirkuläre Abhängigkeiten früh sichtbar — das ist meist gut.


40. Dependency Injection und AOP-Proxies

Fortgeschritten, aber wichtig.

Beim Injizieren kann Spring einen Proxy statt des echten Objekts liefern.

Beispiel:


@Service
public class PaymentService {

@Transactional
public void pay() {
}
}

Spring erzeugt vielleicht:


PaymentService-Proxy -> echtes PaymentService

Wenn eine andere Bean PaymentService injiziert, bekommt sie den Proxy.

Warum?

Damit Spring anwenden kann:

  • Transaktionen
  • Security
  • Caching
  • AOP-Logik

Deshalb ist es wichtig, Beans aus Spring zu holen.


41. Warum new-Objekte Spring-Features verpassen

Wenn du das machst:


PaymentService paymentService = new PaymentService();

verwaltet Spring es nicht.

Spring kann deshalb nicht anwenden:

  • Dependency Injection
  • @Transactional
  • Security-Proxy
  • Lifecycle-Methoden
  • Konfiguration
  • AOP

Prüfungsfalle:

Erzeugst du ein Objekt manuell mit new, greifen Spring-Annotationen darauf oft nicht wie erwartet.


42. Prüfungsfrage: Constructor Injection

Frage:


@Service
public class OrderService {

private final OrderRepository orderRepository;

public OrderService(OrderRepository orderRepository) {
this.orderRepository = orderRepository;
}
}

Ist @Autowired auf dem Konstruktor nötig?

Antwort:

Nein. Hat die Klasse nur einen Konstruktor, nutzt Spring ihn automatisch. @Autowired ist in modernem Spring optional.


43. Prüfungsfrage: Mehrere Beans

Frage:


public interface PaymentProvider {
}

@Component
public class StripePaymentProvider implements PaymentProvider {
}

@Component
public class PaypalPaymentProvider implements PaymentProvider {
}

@Service
public class CheckoutService {

public CheckoutService(PaymentProvider paymentProvider) {
}
}

Was passiert?

Antwort:

Spring findet zwei Beans vom Typ PaymentProvider — die Abhängigkeit ist mehrdeutig. Die App startet nicht, außer eine Bean ist @Primary, der Konstruktor nutzt @Qualifier, oder eine andere Auflösungsstrategie greift.


44. Prüfungsfrage: @Primary

Frage:


@Component
@Primary
public class StripePaymentProvider implements PaymentProvider {
}

@Component
public class PaypalPaymentProvider implements PaymentProvider {
}

Welche Bean wird hier injiziert?


public CheckoutService(PaymentProvider paymentProvider) {
}

Antwort:

Spring injiziert StripePaymentProvider — markiert als @Primary.


45. Prüfungsfrage: @Qualifier

Frage:


public CheckoutService(
@Qualifier("paypalPaymentProvider") PaymentProvider paymentProvider
) {
}

Welche Bean wird injiziert?

Antwort:

Die Bean mit dem Namen paypalPaymentProvider.


46. Prüfungsfrage: @Primary und @Qualifier zusammen

Frage:


@Component
@Primary
public class StripePaymentProvider implements PaymentProvider {
}

@Component
public class PaypalPaymentProvider implements PaymentProvider {
}

public CheckoutService(
@Qualifier("paypalPaymentProvider") PaymentProvider paymentProvider
) {
}

Welche Bean wird injiziert?

Antwort:

PaypalPaymentProvider.

@Qualifier gewinnt — es fordert eine spezifische Bean.


47. Prüfungsfrage: Optionale Abhängigkeit

Frage:


@Service
public class ReportService {

public ReportService(Optional<AuditService> auditService) {
}
}

Was passiert, wenn keine AuditService-Bean existiert?

Antwort:

Spring injiziert Optional.empty(). Die App startet nicht fehl — die Abhängigkeit ist optional.


48. Prüfungsfrage: Listen-Injektion

Frage:


public NotificationManager(List<NotificationSender> senders) {
}

Was injiziert Spring?

Antwort:

Alle Beans, die NotificationSender implementieren — in die Liste.


49. Prüfungsfrage: Field Injection

Frage:

Warum ist Field Injection nicht empfohlen?

Antwort:

Field Injection versteckt Abhängigkeiten, erschwert Tests, verhindert final-Felder und erlaubt Objekte ohne klar erforderliche Dependencies. Constructor Injection macht Abhängigkeiten explizit und unterstützt Immutability.


50. Prüfungsfrage: Zirkuläre Abhängigkeit

Frage:


@Service
public class AService {
public AService(BService bService) {}
}

@Service
public class BService {
public BService(AService aService) {}
}

Was ist das Problem?

Antwort:

Zirkuläre Abhängigkeit. AService braucht BService, BService braucht AService. Mit Constructor Injection kann Spring keine Bean sauber erzeugen. Das deutet meist auf ein Designproblem hin.


51. Typische Prüfungsfallen

Falle 1

@Autowired ist auf einem einzigen Konstruktor optional.


Falle 2

Constructor Injection ist für erforderliche Abhängigkeiten bevorzugt.


Falle 3

Field Injection funktioniert — ist aber nicht empfohlen.


Falle 4

Mehrere passende Beans → Spring startet nicht, bis die Mehrdeutigkeit aufgelöst ist.


Falle 5

@Primary liefert die Standard-Bean.


Falle 6

@Qualifier wählt die exakte Bean.


Falle 7

@Qualifier ist spezifischer als @Primary.


Falle 8

Spring kann alle Beans eines Typs in List<T> oder Map<String, T> injizieren.


Falle 9

Optionale Abhängigkeiten: Optional<T>, ObjectProvider<T> oder @Nullable.


Falle 10

Mit new erzeugte Objekte bekommen keine Spring-DI und kein Proxy-Verhalten.


52. Interview-Antwort

Frage:

Was ist Dependency Injection?

Gute Antwort:

Dependency Injection ist ein Design-Pattern: eine Klasse bekommt Abhängigkeiten von außen statt sie selbst zu erzeugen. In Spring erzeugt der IoC-Container Beans und injiziert benötigte Abhängigkeiten automatisch. Das reduziert enge Kopplung, verbessert Testbarkeit und macht Apps einfacher konfigurierbar und wartbar. Für erforderliche Abhängigkeiten wird Constructor Injection empfohlen — Abhängigkeiten sind explizit und Felder können final sein.


53. Interview-Antwort

Frage:

Warum wird Constructor Injection in Spring empfohlen?

Gute Antwort:

Constructor Injection macht erforderliche Abhängigkeiten explizit. Felder können final sein, Immutability wird unterstützt, Tests werden einfacher — und das Objekt entsteht nicht ohne Pflicht-Dependencies. Designprobleme wie zu viele Abhängigkeiten oder Zirkularität werden früher sichtbar. Field Injection funktioniert, versteckt aber Abhängigkeiten und erschwert Tests.


54. Interview-Antwort

Frage:

Was passiert, wenn mehrere Beans zur gleichen Abhängigkeit passen?

Gute Antwort:

Spring kann nicht entscheiden, welche Bean injiziert werden soll — die App startet meist nicht. Auflösung: eine Bean als @Primary markieren, @Qualifier für eine spezifische Bean, alle als Collection injizieren oder einen spezifischeren Typ nutzen. @Primary definiert die Standardwahl, @Qualifier die exakte Bean.


55. Kleines Code-Übungsbeispiel

Erstelle dieses Beispiel:


public interface MessageSender {
void send(String message);
}

@Component
public class EmailMessageSender implements MessageSender {

@Override
public void send(String message) {
System.out.println("Email: " + message);
}
}

@Component
public class SmsMessageSender implements MessageSender {

@Override
public void send(String message) {
System.out.println("SMS: " + message);
}
}

@Service
public class AlertService {

private final MessageSender messageSender;

public AlertService(
@Qualifier("emailMessageSender") MessageSender messageSender
) {
this.messageSender = messageSender;
}

public void alert(String message) {
messageSender.send(message);
}
}

Frage:

Warum brauchen wir hier @Qualifier?

Antwort:

Weil es zwei Beans vom Typ MessageSender gibt: EmailMessageSender und SmsMessageSender. Ohne @Qualifier weiß Spring nicht, welche er injizieren soll.


Übungsfragen

Frage 1

Was ist Dependency Injection?

Antwort:

Eine Klasse bekommt Abhängigkeiten von außen statt sie selbst zu erzeugen. In Spring erzeugt der Container Beans und injiziert benötigte Abhängigkeiten automatisch.


Frage 2

Was ist eine Abhängigkeit?

Antwort:

Ein Objekt, das ein anderes Objekt für seine Arbeit braucht. Braucht OrderService OrderRepository, ist OrderRepository eine Abhängigkeit von OrderService.


Frage 3

Warum ist Dependency Injection nützlich?

Antwort:

Reduziert enge Kopplung, verbessert Testbarkeit, macht Abhängigkeiten explizit und erlaubt einfacheren Austausch von Implementierungen.


Frage 4

Welche drei gängigen Arten von Dependency Injection gibt es?

Antwort:

Constructor Injection, Setter Injection und Field Injection.


Frage 5

Welche Injektionsart ist für erforderliche Abhängigkeiten empfohlen?

Antwort:

Constructor Injection.


Frage 6

Warum ist Constructor Injection besser als Field Injection?

Antwort:

Abhängigkeiten sind explizit, Felder können final sein, Immutability und Testbarkeit verbessern sich — das Objekt entsteht nicht ohne Pflicht-Abhängigkeiten. Field Injection versteckt Dependencies und erschwert Tests.


Frage 7

Ist @Autowired auf einem einzigen Konstruktor nötig?

Antwort:

Nein. In modernem Spring ist es bei nur einem Konstruktor optional.


Frage 8

Was ist Autowiring?

Antwort:

Spring löst die benötigte Abhängigkeit automatisch aus dem Application Context auf und injiziert sie.


Frage 9

Kann Spring per Interface-Typ injizieren?

Antwort:

Ja — wenn es genau eine passende Implementierung gibt oder Mehrdeutigkeit mit @Primary oder @Qualifier aufgelöst ist.


Frage 10

Was passiert, wenn keine passende Bean existiert?

Antwort:

Spring startet meist nicht mit einem Fehler wie No qualifying bean of type ... available.


Frage 11

Was passiert bei mehreren passenden Beans?

Antwort:

Spring startet meist nicht — Mehrdeutigkeit. Auflösung mit @Primary, @Qualifier, spezifischerem Typ oder Collection-Injection.


Frage 12

Was macht @Primary?

Antwort:

Markiert eine Bean als Standardwahl, wenn mehrere Kandidaten existieren.


Frage 13

Was macht @Qualifier?

Antwort:

Wählt eine spezifische Bean per Name oder Qualifier.


Frage 14

Was ist spezifischer: @Primary oder @Qualifier?

Antwort:

@Qualifier ist spezifischer als @Primary.


Frage 15

Wie injiziere ich alle Beans desselben Typs?

Antwort:

Mit List<T>, Set<T> oder Map<String, T>.


Frage 16

Was injiziert Spring in Map<String, PaymentProvider>?

Antwort:

Eine Map, deren Keys Bean-Namen und deren Values die passenden Beans sind.


Frage 17

Wie mache ich eine Abhängigkeit optional?

Antwort:

Mit Optional<T>, ObjectProvider<T> oder @Nullable.


Frage 18

Wofür ist ObjectProvider nützlich?

Antwort:

Für optionalen, lazy oder dynamischen Bean-Zugriff — Bean nur holen, wenn sie gebraucht wird.


Frage 19

Was ist eine zirkuläre Abhängigkeit?

Antwort:

Zwei oder mehr Beans hängen voneinander ab — z. B. AService braucht BService und BService braucht AService.


Frage 20

Warum bekommen new-Objekte keine Spring-Features?

Antwort:

Sie werden nicht vom Spring-Container erzeugt. Spring kann keine Dependencies injizieren, Lifecycle steuern oder Proxy-Features wie Transaktionen, Security oder AOP anwenden.

Merksätze zum Mitnehmen

  • Dependency Injection = Abhängigkeiten kommen von außen.
  • Abhängigkeit = Objekt, das eine Klasse braucht.
  • Autowiring = Spring injiziert passende Beans automatisch.
  • Constructor Injection ist am besten für Pflicht-Abhängigkeiten.
  • Setter Injection für optionale Abhängigkeiten.
  • Field Injection funktioniert — aber meiden.
  • @Autowired auf einem Konstruktor ist optional.
  • Spring kann per Interface-Typ injizieren.
  • Keine passende Bean → Start schlägt fehl.
  • Mehrere passende Beans → Mehrdeutigkeit.
  • @Primary = Standard-Bean.
  • @Qualifier = exakte Bean.
  • @Qualifier ist spezifischer als @Primary.
  • Alle Beans in List<T> oder Map<String, T> injizierbar.
  • Optional: Optional<T>, ObjectProvider<T>, @Nullable.
  • Zirkuläre Abhängigkeiten = meist Designproblem.
  • Mit new erzeugte Objekte bekommen kein Spring-Management.