Woche 1, Tag 4 — Dependency Injection im Detail
Ziel
Heute vertiefst du Dependency Injection.
Die Kernfragen:
- Was ist Dependency Injection?
- Warum nutzt Spring Dependency Injection?
- Welche Arten von Dependency Injection gibt es?
- Warum wird Constructor Injection empfohlen?
- Was ist Autowiring?
- Was passiert, wenn mehrere Beans zu einer Abhängigkeit passen?
- Was ist
@Primary? - Was ist
@Qualifier? - Wie injiziert man alle Beans eines Typs?
- Wie macht man Abhängigkeiten optional?
- Welche typischen Prüfungsfallen gibt es?
1. Kurz-Wiederholung
Aus den bisherigen Lektionen:
- Spring verwaltet Objekte — Beans.
ApplicationContextist 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:
@Autowiredauf einem einzigen Konstruktor ist in modernem Spring optional.
9. Arten von Dependency Injection
Spring unterstützt drei gängige Arten:
- Constructor Injection
- Setter Injection
- 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
finalsein 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
finalsein 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
| Typ | Am besten für | Empfohlen? |
|---|---|---|
| Constructor Injection | erforderliche Deps | ja |
| Setter Injection | optionale Deps | manchmal |
| Field Injection | schnelle Demos | meiden |
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:
@Primarynutzen@Qualifiernutzen- Liste aller Beans injizieren
- Map aller Beans injizieren
- 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
| Annotation | Bedeutung |
|---|---|
@Primary | Standardwahl |
@Qualifier | exakte 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.
@Autowiredauf 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.@Qualifierist spezifischer als@Primary.- Alle Beans in
List<T>oderMap<String, T>injizierbar. - Optional:
Optional<T>,ObjectProvider<T>,@Nullable. - Zirkuläre Abhängigkeiten = meist Designproblem.
- Mit
newerzeugte Objekte bekommen kein Spring-Management.