Woche 3, Tag 5 — Spring-Boot-Start: Runners, Events, Lazy Initialization und Startup-Debugging
Ziel
Heute verstehst du, was passiert, wenn eine Spring-Boot-Anwendung startet.
Die Kernfragen:
- Was macht
SpringApplication.run(...)? - Was passiert beim Application Startup?
- Was ist
CommandLineRunner? - Was ist
ApplicationRunner? - Was ist der Unterschied zwischen beiden?
- Wann solltest du Runners nutzen?
- Was sind Spring-Boot-Application Events?
- Was ist
ApplicationReadyEvent? - Was ist
ApplicationFailedEvent? - Was ist Lazy Initialization?
- Wie debuggst du Startup-Probleme?
- Welche typischen Prüfungsfallen gibt es?
1. Kurz-Wiederholung aus Woche 3, Tag 4
An Tag 4 hast du gelernt:
- Actuator liefert production-ready Monitoring- und Management-Endpoints.
/actuator/healthzeigt den Application Health Status./actuator/metricszeigt Runtime Metrics./actuator/beanszeigt registrierte Spring Beans./actuator/conditionszeigt Auto-Configuration-Entscheidungen./actuator/configpropszeigt Configuration Properties.- Actuator-Endpoints müssen sorgfältig exposed und gesichert werden.
Merksatz:
Actuator hilft mir, eine laufende Spring-Boot-Anwendung zu beobachten.
Heute lernst du, was beim Start der Anwendung passiert.
2. Die Main-Methode
Eine normale Spring-Boot-App startet hier:
@SpringBootApplication
public class KlarsyncApplication {
public static void main(String[] args) {
SpringApplication.run(KlarsyncApplication.class, args);
}
}
Die wichtigste Zeile ist:
SpringApplication.run(KlarsyncApplication.class, args);
Einfache Bedeutung:
Starte die Spring-Boot-Anwendung.
Intern passiert aber viel mehr.
3. Was macht SpringApplication.run(...)?
Vereinfachte Antwort:
SpringApplication.run(...)erzeugt und refreshed den SpringApplicationContext.
Beim Startup macht Spring Boot:
1. Creates SpringApplication
2. Prepares the environment
3. Loads application properties
4. Determines application type
5. Creates ApplicationContext
6. Registers configuration classes
7. Applies auto-configuration
8. Scans components
9. Registers BeanDefinitions
10. Creates singleton beans
11. Injects dependencies
12. Runs lifecycle callbacks
13. Starts embedded web server if needed
14. Runs ApplicationRunner and CommandLineRunner beans
15. Publishes application ready event
Merksatz:
SpringApplication.runerzeugt, konfiguriert, refreshed und startet den Application Context.
4. Startup-Mentalmodell
Stell dir den Startup so vor:
Read configuration
↓
Create container
↓
Register bean recipes
↓
Create beans
↓
Inject dependencies
↓
Initialize beans
↓
Start web server
↓
Run startup runners
↓
Application ready
Kürzere Version:
config -> context -> beans -> server -> runners -> ready
5. ApplicationContext Refresh
Ein zentraler Teil des Startups ist:
refresh the ApplicationContext
Den Context zu refreshen bedeutet, Spring:
loads bean definitions
creates bean factory
registers post-processors
creates singleton beans
injects dependencies
initializes beans
starts lifecycle components
Wenn der Context Refresh fehlschlägt, startet die Anwendung nicht.
Beispiel-Fehlerursachen:
missing bean
ambiguous bean
invalid configuration property
database configuration error
circular dependency
port already in use
bean initialization exception
6. Was passiert, bevor Beans erzeugt werden?
Bevor Spring Beans erzeugt, bereitet es die Environment vor.
Die Environment umfasst:
application.yml
application.properties
profile-specific files
environment variables
command-line arguments
system properties
active profiles
Deshalb sind Properties und Profiles schon während der Bean-Erzeugung verfügbar.
Beispiel:
spring:
profiles:
active: dev
oder:
java -jar app.jar --spring.profiles.active=prod
Spring Boot liest das früh ein.
7. Was passiert, wenn Beans erzeugt werden?
Spring erzeugt Beans gemäß ihrer BeanDefinition.
Für Singleton Beans gilt standardmäßig:
Spring creates them during startup.
Beispiel:
@Service
public class TaskService {
public TaskService(TaskRepository taskRepository) {
}
}
Spring muss erzeugen:
TaskRepository
TaskService
und Dependencies injizieren.
Wenn Dependency Injection fehlschlägt, schlägt der Startup fehl.
8. Startup-Fehlerbeispiel: fehlende Bean
Code:
@Service
public class TaskService {
public TaskService(TaskRepository taskRepository) {
}
}
Aber es existiert keine TaskRepository-Bean.
Möglicher Fehler:
Parameter 0 of constructor in TaskService required a bean of type TaskRepository that could not be found.
Bedeutung:
Spring could not create TaskService because its dependency is missing.
Der Startup stoppt.
9. Startup-Fehlerbeispiel: Port bereits belegt
Wenn ein anderer Prozess Port 8080 schon nutzt, kann der Startup fehlschlagen.
Beispiel:
Web server failed to start. Port 8080 was already in use.
Fix-Optionen:
stop the other process
change server.port
use a different profile
configure random port in tests
Beispiel:
server:
port: 8081
10. Startup-Fehlerbeispiel: ungültige Config
YAML:
app:
max-tasks: abc
Java:
@ConfigurationProperties(prefix = "app")
public record AppProperties(
int maxTasks
) {
}
Spring kann "abc" nicht in int konvertieren.
Ergebnis:
Application fails to start.
Das ist gut, weil ungültige Configuration früh erkannt wird.
11. Startup-Fehlerbeispiel: DataSource
Dependency:
implementation("org.springframework.boot:spring-boot-starter-data-jpa")
Keine Datasource-Config.
Möglicher Fehler:
Failed to configure a DataSource
Warum?
Spring Boot sieht JPA/Database-Klassen und versucht, eine DataSource zu konfigurieren.
Fix:
configure datasource
add database driver
use embedded DB for tests
remove JPA starter
exclude DataSourceAutoConfiguration only if truly needed
12. CommandLineRunner
CommandLineRunner lässt dich Code ausführen, nachdem der Application Context gestartet ist.
Beispiel:
@Component
public class StartupRunner implements CommandLineRunner {
@Override
public void run(String... args) {
System.out.println("Application started with args:");
System.out.println(Arrays.toString(args));
}
}
Wenn du startest:
java -jar app.jar one two three
dann enthält args:
one
two
three
Einfache Definition:
CommandLineRunnerführt Startup-Code aus und erhält rohe Command-Line-Arguments.
13. ApplicationRunner
ApplicationRunner ist ähnlich, erhält aber geparste Application Arguments.
Beispiel:
@Component
public class StartupApplicationRunner implements ApplicationRunner {
@Override
public void run(ApplicationArguments args) {
System.out.println("Option names: " + args.getOptionNames());
}
}
App starten:
java -jar app.jar --mode=import --limit=100 file1.csv
ApplicationArguments kann unterscheiden:
option arguments: --mode=import, --limit=100
non-option arguments: file1.csv
Einfache Definition:
ApplicationRunnerführt Startup-Code aus und erhält strukturierte Application Arguments.
14. CommandLineRunner vs. ApplicationRunner
| Thema | CommandLineRunner | ApplicationRunner |
|---|---|---|
| Methode | run(String... args) | run(ApplicationArguments args) |
| Args-Stil | rohes String-Array | geparste Arguments |
| Gut für | einfache Startup-Args | Option-/Non-Option-Args |
| Läuft wenn | nach Context-Startup | nach Context-Startup |
Merksatz:
CommandLineRunnerbekommt rohe Args.ApplicationRunnerbekommt geparste Args.
15. Wann laufen Runners?
Runners laufen, nachdem der Application Context erzeugt und refreshed wurde.
Wichtige Startup-Reihenfolge:
1. Beans are created
2. Dependencies are injected
3. Application context is refreshed
4. ApplicationRunner and CommandLineRunner run
5. ApplicationReadyEvent is published
Runners sind nützlich, wenn du Code ausführen musst, nachdem Beans bereit sind.
16. Wofür werden Runners genutzt?
Gute Use Cases:
seed demo data in dev
validate startup assumptions
run one-time import in CLI app
log startup information
warm up caches carefully
start a simple command-line job
Beispiel Dev-Daten:
@Component
@Profile("dev")
public class DevDataRunner implements ApplicationRunner {
private final UserRepository userRepository;
public DevDataRunner(UserRepository userRepository) {
this.userRepository = userRepository;
}
@Override
public void run(ApplicationArguments args) {
userRepository.save(new User("demo@example.com"));
}
}
17. Vorsicht mit Runners
Schlechte Use Cases:
long-running jobs that block startup
heavy imports on every production restart
dangerous data modification without profile protection
external calls without timeout
business logic that should be triggered by users or jobs
Schlecht:
@Component
public class DangerousRunner implements CommandLineRunner {
@Override
public void run(String... args) {
deleteAllData();
}
}
Besser:
protect with profile
protect with property condition
run explicitly
use migration tools
use scheduled job
use admin endpoint
Merksatz:
Runners sind mächtig, aber sie laufen bei jedem Startup.
18. Runners mit Profiles schützen
Beispiel:
@Component
@Profile("dev")
public class DevSeedDataRunner implements CommandLineRunner {
@Override
public void run(String... args) {
System.out.println("Seeding dev data");
}
}
Dieser Runner läuft nur im dev-Profile.
Er läuft nicht in Production.
19. Runners mit Properties schützen
Beispiel:
@Component
@ConditionalOnProperty(
name = "app.seed.enabled",
havingValue = "true"
)
public class SeedDataRunner implements ApplicationRunner {
@Override
public void run(ApplicationArguments args) {
System.out.println("Seeding data");
}
}
YAML:
app:
seed:
enabled: true
Das ist nützlich, wenn Startup-Verhalten über Configuration gesteuert werden soll.
20. Reihenfolge mehrerer Runners
Wenn mehrere Runners existieren, kannst du die Reihenfolge steuern.
Option 1:
@Component
@Order(1)
public class FirstRunner implements CommandLineRunner {
@Override
public void run(String... args) {
System.out.println("First");
}
}
@Component
@Order(2)
public class SecondRunner implements CommandLineRunner {
@Override
public void run(String... args) {
System.out.println("Second");
}
}
Option 2:
@Component
public class FirstRunner implements CommandLineRunner, Ordered {
@Override
public int getOrder() {
return 1;
}
@Override
public void run(String... args) {
System.out.println("First");
}
}
Merksatz:
Nutze
@OrderoderOrdered, um die Runner-Reihenfolge zu steuern.
21. Exceptions in Runners
Wenn ein Runner eine Exception wirft, schlägt der Startup meist fehl.
Beispiel:
@Component
public class FailingRunner implements CommandLineRunner {
@Override
public void run(String... args) {
throw new IllegalStateException("Startup failed");
}
}
Ergebnis:
Application fails to start.
Das kann gut sein, wenn die App bei ungültigem Zustand nicht laufen darf.
Aber sei vorsichtig bei nicht-kritischen Tasks.
22. Runners in Web-Apps vs. CLI-Apps
In einer Web-App:
Runners execute during startup.
Then the app continues running and handles HTTP requests.
In einer CLI-App:
Runners can perform the main job.
Then the app may exit if no non-daemon threads keep it alive.
Spring Boot kann genutzt werden für:
REST APIs
workers
CLI tools
batch-like jobs
message consumers
scheduled services
Nicht nur Web-Apps.
23. Application Events
Spring Boot publiziert Events während des Startups.
Einfache Definition:
Application Events sind Benachrichtigungen, die Spring Boot in verschiedenen Phasen von Startup und Shutdown publiziert.
Wichtige Events:
ApplicationStartingEvent
ApplicationEnvironmentPreparedEvent
ApplicationContextInitializedEvent
ApplicationPreparedEvent
ApplicationStartedEvent
ApplicationReadyEvent
ApplicationFailedEvent
Für die Zertifizierung sind die wichtigsten:
ApplicationReadyEvent
ApplicationFailedEvent
24. ApplicationReadyEvent
ApplicationReadyEvent wird publiziert, wenn die Anwendung bereit ist.
Beispiel:
@Component
public class ReadyListener {
@EventListener(ApplicationReadyEvent.class)
public void onReady() {
System.out.println("Application is ready");
}
}
Bedeutung:
The application has started and runners have been called.
Nutze es, wenn du Logik brauchst, nachdem die App vollständig bereit ist.
Merksatz:
ApplicationReadyEventbedeutet: Die App ist bereit, Requests zu bedienen.
25. ApplicationStartedEvent vs. ApplicationReadyEvent
Wichtiger Unterschied:
ApplicationStartedEvent happens after the context is refreshed but before runners run.
ApplicationReadyEvent happens after runners have run and the application is ready.
Merksatz:
Started ist vor Runners. Ready ist nach Runners.
26. ApplicationFailedEvent
ApplicationFailedEvent wird publiziert, wenn der Application Startup fehlschlägt.
Beispiel-Konzept:
public class StartupFailureListener {
@EventListener(ApplicationFailedEvent.class)
public void onFailure(ApplicationFailedEvent event) {
System.out.println("Application failed: " + event.getException().getMessage());
}
}
Wichtig:
Wenn der Application Context fehlgeschlagen ist, bevor diese Bean erzeugt wurde, ist ein normaler @Component-Listener möglicherweise nicht verfügbar.
Für sehr frühe Events müssen Listener oft anders registriert werden.
Merksatz für die Prüfung:
ApplicationFailedEventsignalisiert, dass der Startup fehlgeschlagen ist.
27. Events mit @EventListener abhören
Für normale Application Events nutze:
@EventListener
Beispiel:
@Component
public class StartupEvents {
@EventListener(ApplicationReadyEvent.class)
public void afterReady() {
System.out.println("Ready");
}
}
Das ist einfach und üblich.
28. Frühe Events brauchen frühe Registrierung
Manche Events passieren, bevor der Application Context vollständig erzeugt ist.
Beispiel:
ApplicationStartingEvent
ApplicationEnvironmentPreparedEvent
Ein als normale Bean registrierter Listener empfängt diese frühen Events möglicherweise nicht, weil die Bean noch nicht existiert.
Für frühe Events können Listener direkt auf SpringApplication registriert werden.
Beispiel-Konzept:
public static void main(String[] args) {
SpringApplication app = new SpringApplication(KlarsyncApplication.class);
app.addListeners(event -> System.out.println(event.getClass().getSimpleName()));
app.run(args);
}
Prüfungsfalle:
Nicht alle Startup-Events können von normalen Spring Beans abgehört werden.
29. Lazy Initialization
Standardmäßig werden Singleton Beans meist eager während des Startups erzeugt.
Lazy Initialization bedeutet:
Beans erst erzeugen, wenn sie zum ersten Mal gebraucht werden.
Global aktivieren:
spring:
main:
lazy-initialization: true
Oder für eine Bean:
@Component
@Lazy
public class HeavyService {
}
30. Warum Lazy Initialization nutzen?
Mögliche Vorteile:
faster startup
less memory used at startup
avoid creating rarely used beans
useful in development or special apps
Beispiel:
@Component
@Lazy
public class ReportExportService {
public ReportExportService() {
System.out.println("Heavy service created");
}
}
Diese Bean wird erst erzeugt, wenn sie zum ersten Mal angefragt wird.
31. Risiken von Lazy Initialization
Lazy Initialization kann Probleme bis zur Runtime verstecken.
Beispiel:
@Component
@Lazy
public class BrokenService {
public BrokenService(MissingDependency missingDependency) {
}
}
Wenn lazy, kann die App erfolgreich starten.
Aber später, wenn BrokenService zum ersten Mal angefragt wird, schlägt es fehl.
Risiken:
missing bean discovered late
configuration error discovered late
first request slower
runtime failure instead of startup failure
harder debugging
Merksatz:
Lazy Initialization kann den Startup schneller machen, aber Fehler verzögern.
32. Lazy Initialization und @PostConstruct
Bei einer lazy Bean läuft @PostConstruct, wenn die Bean tatsächlich erzeugt wird.
Beispiel:
@Component
@Lazy
public class HeavyService {
@PostConstruct
public void init() {
System.out.println("HeavyService initialized");
}
}
Wenn niemand HeavyService beim Startup braucht, läuft init() nicht beim Startup.
Es läuft später, wenn die Bean zum ersten Mal genutzt wird.
33. Startup-Debugging-Tools
Nützliche Tools:
startup logs
--debug
debug=true
Actuator /actuator/conditions
Actuator /actuator/beans
Actuator /actuator/configprops
dependency tree
failure analysis
application events
Merksatz:
Debugge Startup mit Logs, Conditions, Beans, Config und Dependencies.
34. --debug
Ausführen:
java -jar app.jar --debug
oder:
debug: true
Das gibt mehr Diagnose-Informationen aus, inklusive Auto-Configuration-Condition-Details.
Nutze es, wenn du fragst:
Why did this auto-configuration match?
Why did this bean not exist?
Why is Boot trying to configure a DataSource?
35. Failure Analysis
Spring Boot liefert oft hilfreiche Failure Analysis.
Beispiel:
APPLICATION FAILED TO START
Description:
Parameter 0 of constructor in TaskService required a bean of type TaskRepository that could not be found.
Action:
Consider defining a bean of type TaskRepository in your configuration.
Lies:
Description
Reason
Action
Caused by
Lies nicht nur die erste Zeile.
Merksatz:
Spring-Boot-Failure-Analysis sagt dir oft, was fehlgeschlagen ist und wie du es fixen kannst.
36. Häufiger Startup-Fehler: fehlende Bean
Fehler:
No qualifying bean of type 'EmailSender' available
Checkliste:
Is the class annotated?
Is it inside component scan?
Is the active profile correct?
Is a condition preventing creation?
Is the dependency optional?
Are there test slices involved?
Is the bean created by @Bean but config class not scanned?
37. Häufiger Startup-Fehler: mehrere Beans
Fehler:
required a single bean, but 2 were found
Fix-Optionen:
@Primary
@Qualifier
inject List<T>
inject Map<String,T>
use more specific type
remove duplicate bean
check profiles
38. Häufiger Startup-Fehler: Circular Dependency
Beispiel:
@Service
public class AService {
public AService(BService bService) {}
}
@Service
public class BService {
public BService(AService aService) {}
}
Problem:
AService needs BService.
BService needs AService.
Bester Fix:
refactor responsibilities
extract common service
use events
redesign dependencies
Vermeide Lazy- oder Setter-Workarounds als erste Lösung.
39. Häufiger Startup-Fehler: ungültige Configuration Properties
Fehler:
Failed to bind properties under 'app.max-tasks' to int
Prüfe:
YAML value type
property name
relaxed binding
@ConfigurationProperties registration
validation annotations
active profile
environment variable override
40. Häufiger Startup-Fehler: Port bereits belegt
Fehler:
Port 8080 was already in use
Fix:
server:
port: 8081
Oder Prozess finden:
lsof -i :8080
Dann beenden, wenn passend.
41. Häufiger Startup-Fehler: JPA/DataSource
Fehler:
Failed to configure a DataSource
Prüfe:
Is data-jpa starter needed?
Is database driver added?
Is spring.datasource.url configured?
Is active profile correct?
Is Testcontainers or H2 needed in tests?
Should this app exclude DataSourceAutoConfiguration?
42. Startup-Performance
Dinge, die den Startup verlangsamen können:
too many beans
heavy @PostConstruct methods
slow database connection
slow external service health checks
heavy runners
classpath scanning
large auto-configuration set
complex entity scanning
too much work at startup
Gute Praxis:
Keep startup logic small.
Avoid slow external calls during startup.
Use profiles/properties for optional startup tasks.
Move heavy jobs out of startup.
43. Startup messen mit Actuator
Spring Boot Actuator kann Startup-Informationen exposen, wenn Startup Tracking konfiguriert ist.
Konzeptionell kann Startup-Information beantworten:
Which startup steps took time?
Which bean took long to initialize?
Where is startup slow?
Für die Zertifizierung fokussiere dich auf das Konzept:
Startup kann über Logs, Failure Analysis, Actuator und Condition Reports debuggt werden.
44. Runners vs. @PostConstruct
| Thema | @PostConstruct | Runner |
|---|---|---|
| Läuft | während Bean Initialization | nach Context-Startup |
| Gehört zu | einem Bean Lifecycle | Application-Startup-Logik |
| Gut für | Initialisierung einer Bean | App-Level-Startup-Code |
| Hat App Args | nein | ja |
| Kann alle Beans nutzen | eingeschränkt; Bean initialisiert noch | ja, Context ist bereit |
Merksatz:
@PostConstructinitialisiert eine Bean. Runners führen Application-Level-Startup-Logik aus.
45. Runners vs. ApplicationReadyEvent
| Thema | Runner | ApplicationReadyEvent |
|---|---|---|
| Läuft | nach Context-Start | nach Abschluss der Runners |
| Nutzen für | Startup-Tasks | Logik nach vollständig bereiter App |
| Kann Startup failen | ja | ja, wenn Exception geworfen wird |
| Bekommt Args | ja | Event fokussiert nicht auf Args |
Merksatz:
Runners laufen vor Ready.
ApplicationReadyEventkommt nach Runners.
46. Runners vs. Migrations
Nutze Runners nicht als Ersatz für Database-Migration-Tools.
Schlechte Idee:
@Component
public class SchemaRunner implements CommandLineRunner {
public void run(String... args) {
createTablesManually();
}
}
Bessere Tools:
Flyway
Liquibase
Nutze Runners für Data Seeding oder App-Level-Startup-Tasks, nicht für Schema Migration.
47. Runners und Transactions
Ein Runner kann transaktionale Services aufrufen.
Beispiel:
@Component
@Profile("dev")
public class DevSeedRunner implements ApplicationRunner {
private final DevSeedService devSeedService;
public DevSeedRunner(DevSeedService devSeedService) {
this.devSeedService = devSeedService;
}
@Override
public void run(ApplicationArguments args) {
devSeedService.seed();
}
}
Service:
@Service
public class DevSeedService {
@Transactional
public void seed() {
// save demo data
}
}
Das ist besser, als @Transactional auf eine selbst aufgerufene Methode im Runner zu setzen.
Merksatz:
Lass den Runner eine andere Bean aufrufen, wenn Proxy-basiertes Verhalten nötig ist.
48. Application Availability
Spring Boot hat Availability States.
Wichtige Konzepte:
liveness
readiness
Liveness
Lebt die App?
Readiness
Ist die App bereit, Traffic zu empfangen?
Während des Startups:
App is not ready until startup completes.
Nach Ready:
App can accept traffic.
Das ist wichtig auf Deployment-Plattformen wie Kubernetes.
49. Typische Prüfungsfallen
Falle 1
SpringApplication.run(...) macht viel mehr als nur main aufzurufen.
Es erzeugt und refreshed den ApplicationContext.
Falle 2
CommandLineRunner bekommt rohe String... args.
ApplicationRunner bekommt geparste ApplicationArguments.
Falle 3
Runners laufen, nachdem der Application Context erzeugt und refreshed wurde.
Falle 4
ApplicationStartedEvent passiert vor Runners.
ApplicationReadyEvent passiert nach Runners.
Falle 5
Runners laufen bei jedem Startup.
Schütze gefährliche Runners mit Profiles oder Properties.
Falle 6
Wenn ein Runner eine Exception wirft, kann der Startup fehlschlagen.
Falle 7
Lazy Initialization kann den Startup schneller machen, aber Fehler bis zur Runtime verzögern.
Falle 8
Normale Spring-Bean-Listener empfangen möglicherweise keine sehr frühen Startup-Events, weil die Beans noch nicht existieren.
Falle 9
@PostConstruct ist für Bean Initialization.
Runners sind für Application-Level-Startup-Logik.
Falle 10
Lies Spring-Boot-Failure-Analysis sorgfältig. Sie nennt oft Ursache und Action.
50. Prüfungsfrage: SpringApplication.run
Frage:
Was macht SpringApplication.run(...)?
Antwort:
Es startet die Spring-Boot-Anwendung, indem es den ApplicationContext erzeugt und refreshed, Configuration lädt, Auto-Configuration anwendet, Components scannt, Beans erzeugt, Dependencies injiziert, Lifecycle Callbacks ausführt, den Web Server bei Bedarf startet, Startup Runners ausführt und Application Events publiziert.
51. Prüfungsfrage: CommandLineRunner
Frage:
Was ist CommandLineRunner?
Antwort:
CommandLineRunner ist ein Callback Interface, das Code ausführt, nachdem der Application Context erzeugt und refreshed wurde. Es erhält rohe Command-Line-Arguments als String... args.
52. Prüfungsfrage: ApplicationRunner
Frage:
Was ist ApplicationRunner?
Antwort:
ApplicationRunner ist ein Callback Interface, das Code ausführt, nachdem der Application Context erzeugt und refreshed wurde. Es erhält geparste Application Arguments über ApplicationArguments.
53. Prüfungsfrage: Runner-Unterschied
Frage:
Was ist der Unterschied zwischen CommandLineRunner und ApplicationRunner?
Antwort:
CommandLineRunner erhält rohe Command-Line-Arguments als String-Array. ApplicationRunner erhält geparste Arguments als ApplicationArguments-Objekt.
54. Prüfungsfrage: Runner-Reihenfolge
Frage:
Wie kann ich mehrere Runners ordnen?
Antwort:
Nutze @Order oder implementiere das Ordered Interface.
55. Prüfungsfrage: Runner-Exception
Frage:
Was passiert, wenn ein Runner eine Exception wirft?
Antwort:
Der Application Startup schlägt meist fehl.
56. Prüfungsfrage: ApplicationReadyEvent
Frage:
Wann wird ApplicationReadyEvent publiziert?
Antwort:
Es wird publiziert, wenn die Anwendung vollständig gestartet und bereit ist — nachdem Runners aufgerufen wurden.
57. Prüfungsfrage: ApplicationStartedEvent
Frage:
Was ist der Unterschied zwischen ApplicationStartedEvent und ApplicationReadyEvent?
Antwort:
ApplicationStartedEvent wird publiziert, nachdem der Application Context refreshed wurde, aber bevor Runners laufen. ApplicationReadyEvent wird publiziert, nachdem Runners gelaufen sind und die Anwendung bereit ist.
58. Prüfungsfrage: Lazy Initialization
Frage:
Was ist Lazy Initialization?
Antwort:
Lazy Initialization bedeutet, dass Beans erst erzeugt werden, wenn sie zum ersten Mal gebraucht werden — statt eager beim Startup.
59. Prüfungsfrage: Lazy-Risiko
Frage:
Was ist ein Risiko von Lazy Initialization?
Antwort:
Es kann Fehler bis zur Runtime verzögern. Fehlende Dependencies oder Configuration-Probleme erscheinen möglicherweise nicht beim Startup, sondern erst, wenn die lazy Bean zum ersten Mal genutzt wird.
60. Prüfungsfrage: @PostConstruct vs. Runner
Frage:
Was ist der Unterschied zwischen @PostConstruct und einem Runner?
Antwort:
@PostConstruct läuft während des Lifecycles einer bestimmten Bean, nachdem ihre Dependencies injiziert wurden. Ein Runner führt Application-Level-Startup-Code aus, nachdem der Application Context erzeugt und refreshed wurde.
61. Interview-Antwort
Frage:
Was passiert, wenn eine Spring-Boot-Anwendung startet?
Gute Antwort:
Wenn eine Spring-Boot-Anwendung startet, bereitet SpringApplication.run die Environment vor, lädt Configuration, erzeugt den ApplicationContext, wendet Auto-Configuration an, scannt Components, registriert Bean Definitions, erzeugt Singleton Beans, injiziert Dependencies, führt Lifecycle Callbacks aus, startet den embedded Web Server bei Bedarf, führt ApplicationRunner- und CommandLineRunner-Beans aus und publiziert schließlich ApplicationReadyEvent.
62. Interview-Antwort
Frage:
Was ist der Unterschied zwischen
CommandLineRunnerundApplicationRunner?
Gute Antwort:
Beide laufen, nachdem der Application Context gestartet ist. CommandLineRunner erhält rohe Command-Line-Arguments als String... args, während ApplicationRunner ein ApplicationArguments-Objekt erhält, das Option Arguments und Non-Option Arguments trennt. Ich nutze ApplicationRunner, wenn ich strukturierten Zugriff auf Command-Line-Options will.
63. Interview-Antwort
Frage:
Wann würdest du einen Runner nutzen?
Gute Antwort:
Ich würde einen Runner für Application-Level-Startup-Logik nutzen — zum Beispiel Demo-Daten in einem Development Profile seeden, einen Command-Line-Import-Job ausführen, Startup-Annahmen validieren oder Startup-Informationen loggen. Ich würde schwere oder gefährliche Production-Tasks in Runners vermeiden, außer sie sind durch Profiles oder Properties geschützt, weil Runners bei jedem Startup ausgeführt werden.
64. Interview-Antwort
Frage:
Was ist Lazy Initialization?
Gute Antwort:
Lazy Initialization bedeutet, dass Spring Beans erst erzeugt werden, wenn sie zum ersten Mal gebraucht werden — statt eager während des Startups. Es kann Startup-Zeit verbessern und initialen Memory-Verbrauch reduzieren, kann aber auch Fehler bis zur Runtime verzögern. Zum Beispiel könnte eine fehlende Dependency in einer lazy Bean den Application Startup nicht failen, sondern erst später, wenn die Bean zum ersten Mal angefragt wird.
65. Interview-Antwort
Frage:
Wie debuggst du Startup-Probleme?
Gute Antwort:
Ich beginne mit der Failure Analysis und der Root Cause in den Logs. Dann prüfe ich, ob der Fehler eine fehlende Bean, mehrere Beans, ungültige Configuration Property, Profile-Problem, Port-Konflikt oder Auto-Configuration-Problem ist. Ich kann mit --debug laufen, Actuator /actuator/conditions, /actuator/beans und /actuator/configprops nutzen und den Dependency Tree inspizieren, wenn das Problem dependency-bezogen ist.
66. Kleine Code-Übung
Erstelle einen Runner:
@Component
@Profile("dev")
public class DevStartupRunner implements ApplicationRunner {
@Override
public void run(ApplicationArguments args) {
System.out.println("Dev startup runner executed");
}
}
Fragen:
- Wann läuft das?
- In welchem Profile läuft es?
- Bekommt es rohe oder geparste Args?
Antworten:
- Nachdem der Application Context erzeugt und refreshed wurde.
- Nur im
dev-Profile. - Es erhält geparste Args über
ApplicationArguments.
67. Kleine Bug-Übung 1
Problem:
@Component
public class SeedRunner implements CommandLineRunner {
@Override
public void run(String... args) {
seedProductionData();
}
}
Frage:
Was ist gefährlich?
Antwort:
Der Runner läuft bei jedem Startup in jedem Profile. Wenn er Production-Daten ändert, kann das gefährlich sein. Schütze ihn mit @Profile("dev"), @ConditionalOnProperty oder verschiebe die Logik in einen sichereren, expliziten Prozess.
68. Kleine Bug-Übung 2
Problem:
spring:
main:
lazy-initialization: true
Die Anwendung startet erfolgreich, aber der erste Request schlägt mit einem Missing-Bean-Fehler fehl.
Frage:
Warum?
Antwort:
Lazy Initialization hat die Bean-Erzeugung bis zum ersten Request verzögert. Die fehlende Dependency wurde beim Startup nicht entdeckt, weil die kaputte Bean erst erzeugt wurde, als sie gebraucht wurde.
69. Kleine Bug-Übung 3
Problem:
@Component
public class EarlyListener {
@EventListener(ApplicationStartingEvent.class)
public void onStarting() {
System.out.println("Starting");
}
}
Die Methode läuft nicht.
Frage:
Warum?
Antwort:
ApplicationStartingEvent wird sehr früh publiziert — bevor der Application Context erzeugt wird und bevor diese Component als Bean existiert. Frühe Event Listener müssen direkt auf SpringApplication oder über einen anderen frühen Registrierungsmechanismus registriert werden.
Übungsfragen
Frage 1
Was macht SpringApplication.run(...)?
Antwort:
SpringApplication.run(...) startet die Spring-Boot-Anwendung, indem es den ApplicationContext erzeugt und refreshed, Configuration lädt, Auto-Configuration anwendet, Components scannt, Beans erzeugt, Dependencies injiziert, Lifecycle Callbacks ausführt, den Web Server bei Bedarf startet, Startup Runners ausführt und Application Events publiziert.
Frage 2
Was ist der vereinfachte Startup-Flow?
Antwort:
Ein vereinfachter Startup-Flow ist: Configuration lesen, Context erzeugen, Bean Definitions registrieren, Beans erzeugen, Dependencies injizieren, Beans initialisieren, Web Server bei Bedarf starten, Runners ausführen und Ready Event publizieren.
Frage 3
Was ist CommandLineRunner?
Antwort:
CommandLineRunner ist ein Callback Interface, das Code ausführt, nachdem der Application Context gestartet ist. Es erhält rohe Command-Line-Arguments als String... args.
Frage 4
Was ist ApplicationRunner?
Antwort:
ApplicationRunner ist ein Callback Interface, das Code ausführt, nachdem der Application Context gestartet ist. Es erhält geparste Application Arguments als ApplicationArguments-Objekt.
Frage 5
Was ist der Unterschied zwischen CommandLineRunner und ApplicationRunner?
Antwort:
CommandLineRunner erhält rohe String-Arguments. ApplicationRunner erhält strukturierte ApplicationArguments.
Frage 6
Wann laufen Runners?
Antwort:
Runners laufen, nachdem der Application Context erzeugt und refreshed wurde — und vor ApplicationReadyEvent.
Frage 7
Wie kann ich mehrere Runners ordnen?
Antwort:
Nutze @Order oder implementiere Ordered.
Frage 8
Was passiert, wenn ein Runner eine Exception wirft?
Antwort:
Wenn ein Runner eine Exception wirft, schlägt der Application Startup meist fehl.
Frage 9
Wann sollte ich einen Runner nutzen?
Antwort:
Nutze einen Runner für Application-Level-Startup-Logik wie Dev-Data-Seeding, Startup-Validierung, CLI-Jobs oder sicheres Cache-Warmup.
Frage 10
Warum sollten gefährliche Runners mit Profiles oder Properties geschützt werden?
Antwort:
Weil Runners bei jedem Startup ausgeführt werden. Gefährliche Runners können Daten ändern oder den Production-Startup blockieren, wenn sie nicht geschützt sind.
Frage 11
Was ist ApplicationReadyEvent?
Antwort:
ApplicationReadyEvent wird publiziert, wenn die Anwendung vollständig gestartet und bereit ist — nachdem Runners ausgeführt wurden.
Frage 12
Was ist ApplicationFailedEvent?
Antwort:
ApplicationFailedEvent wird publiziert, wenn der Application Startup fehlschlägt.
Frage 13
Was ist der Unterschied zwischen ApplicationStartedEvent und ApplicationReadyEvent?
Antwort:
ApplicationStartedEvent passiert, nachdem der Context refreshed wurde, aber bevor Runners laufen. ApplicationReadyEvent passiert, nachdem Runners gelaufen sind und die App bereit ist.
Frage 14
Warum empfangen normale Bean Listener möglicherweise keine sehr frühen Events?
Antwort:
Sehr frühe Events können passieren, bevor der Application Context erzeugt wird — normale Spring Beans existieren dann noch nicht und können diese Events nicht empfangen.
Frage 15
Was ist Lazy Initialization?
Antwort:
Lazy Initialization bedeutet, dass Beans erst erzeugt werden, wenn sie gebraucht werden — statt eager während des Startups.
Frage 16
Wie aktiviere ich Lazy Initialization global?
Antwort:
Nutze:
spring:
main:
lazy-initialization: true
Frage 17
Was ist ein Risiko von Lazy Initialization?
Antwort:
Lazy Initialization kann Fehler bis zur Runtime verzögern, weil kaputte Beans möglicherweise nicht während des Startups erzeugt werden.
Frage 18
Was ist der Unterschied zwischen @PostConstruct und einem Runner?
Antwort:
@PostConstruct ist Bean-Level-Initialisierung nach Dependency Injection. Ein Runner ist Application-Level-Startup-Logik, nachdem der Context gestartet ist.
Frage 19
Was sind häufige Startup-Fehlerursachen?
Antwort:
Häufige Ursachen sind fehlende Beans, mehrere passende Beans, ungültige Configuration, Circular Dependencies, Port-Konflikte, DataSource-Configuration-Fehler, Profile-Fehler und Bean-Initialization-Exceptions.
Frage 20
Wie kann ich Startup-Probleme debuggen?
Antwort:
Nutze Startup-Logs, Failure Analysis, --debug, debug=true, Actuator /actuator/conditions, /actuator/beans, /actuator/configprops und Dependency-Tree-Tools.
Merksätze zum Mitnehmen
SpringApplication.runstartet die Spring-Boot-Anwendung.- Startup bedeutet: config, context, beans, server, runners, ready.
CommandLineRunnererhält roheString... args.ApplicationRunnererhält geparsteApplicationArguments.- Runners laufen nach Context-Startup und vor
ApplicationReadyEvent. - Nutze
@OrderoderOrdered, um Runners zu ordnen. - Wenn ein Runner eine Exception wirft, kann der Startup fehlschlagen.
- Schütze gefährliche Runners mit Profiles oder Properties.
ApplicationStartedEventpassiert vor Runners.ApplicationReadyEventpassiert nach Runners.ApplicationFailedEventsignalisiert Startup-Fehler.- Sehr frühe Events können passieren, bevor normale Spring Beans existieren.
- Lazy Initialization erzeugt Beans, wenn sie zum ersten Mal gebraucht werden.
- Lazy Initialization kann den Startup verbessern, aber Fehler verzögern.
@PostConstructist Bean-Level-Initialisierung.- Runners sind Application-Level-Startup-Logik.
- Debugge Startup mit Logs, Failure Analysis, Conditions, Beans, Configprops und Dependency-Tree-Tools.