Spring Framework Core: IoC, DI, Beans, Events und AOP
Das Spring Framework liefert den Container, Bean-Lifecycle, Dependency Injection, Events, Ressourcenabstraktion, AOP, Transaktionen, Web- und Data-Integration.
Fachliche Einordnung
Core Spring bestimmt, wie Objekte erzeugt, verbunden, erweitert und getestet werden. Wer Core versteht, versteht auch Boot, Security, Data und Cloud leichter.
Enterprise-Merksatz: Das Spring Framework liefert den Container, Bean-Lifecycle, Dependency Injection, Events, Ressourcenabstraktion, AOP, Transaktionen, Web- und Data-Integration.
Technische Darstellung
Kernkonzepte
- ApplicationContext als zentrale Laufzeitumgebung.
- Bean Definition, Scope, Lifecycle Callback und Proxy.
- Constructor Injection als bevorzugte Form stabiler Abhängigkeiten.
- AOP für Querschnittsthemen wie Transaktionen, Security, Logging und Observability.
- Application Events für lose Kopplung innerhalb eines Prozesses.
Wann einsetzen?
- Du willst testbare Services ohne harte new-Abhängigkeiten bauen.
- Du willst technische Aspekte von Fachlogik trennen.
- Du willst verstehen, warum @Transactional, @Cacheable oder @PreAuthorize oft über Proxies wirken.
Typische Fehler und Risiken
- Field Injection versteckt Pflichtabhängigkeiten und erschwert Tests.
- Self-invocation umgeht Spring-Proxies und damit @Transactional oder @Async.
- Zu viel AOP macht Kontrollfluss unsichtbar.
Legacy- und Modernisierungssicht
Aus EJB @Stateless Services werden Spring @Service Beans; Interceptors werden meist zu AOP-Aspekten, Filterketten oder Security-Konfigurationen.
Ausführliches Beispiel
Das Beispiel zeigt bewusst nicht nur Annotationen, sondern auch die Verantwortung der Schicht. In echten Projekten sollte der technische Spring-Code an Adapter- oder Konfigurationsrändern bleiben, während die Fachlogik testbar und möglichst frameworkarm bleibt.
@Service
public class InvoiceService {
private final InvoiceRepository repository;
private final ApplicationEventPublisher events;
public InvoiceService(InvoiceRepository repository, ApplicationEventPublisher events) {
this.repository = repository;
this.events = events;
}
@Transactional // Proxy Pattern: Spring legt einen Transaktions-Proxy um diese Bean.
public InvoiceId createInvoice(CreateInvoiceCommand command) {
Invoice invoice = Invoice.create(command.customerId(), command.lines());
repository.save(invoice);
events.publishEvent(new InvoiceCreated(invoice.id()));
return invoice.id();
}
}
@Aspect
@Component
class AuditAspect {
@Around("@annotation(org.springframework.transaction.annotation.Transactional)")
Object auditTransaction(ProceedingJoinPoint joinPoint) throws Throwable {
long started = System.nanoTime();
try { return joinPoint.proceed(); }
finally { System.out.println("tx method took " + (System.nanoTime() - started)); }
}
}
Checkliste für Reviews
- Ist die Verantwortung des Bausteins klar: Framework steuert Lebenszyklus, Library wird gezielt benutzt?
- Ist die Fachlogik außerhalb von Controller, Listener, Repository-Implementierung oder Konfiguration?
- Sind Fehlerfälle, Timeouts, Security, Monitoring und Tests sichtbar modelliert?
- Gibt es klare Grenzen zwischen DTO, Domäne, Persistence und Infrastruktur?