Zum Hauptinhalt springen

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:

  1. Was macht SpringApplication.run(...)?
  2. Was passiert beim Application Startup?
  3. Was ist CommandLineRunner?
  4. Was ist ApplicationRunner?
  5. Was ist der Unterschied zwischen beiden?
  6. Wann solltest du Runners nutzen?
  7. Was sind Spring-Boot-Application Events?
  8. Was ist ApplicationReadyEvent?
  9. Was ist ApplicationFailedEvent?
  10. Was ist Lazy Initialization?
  11. Wie debuggst du Startup-Probleme?
  12. 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/health zeigt den Application Health Status.
  • /actuator/metrics zeigt Runtime Metrics.
  • /actuator/beans zeigt registrierte Spring Beans.
  • /actuator/conditions zeigt Auto-Configuration-Entscheidungen.
  • /actuator/configprops zeigt 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 Spring ApplicationContext.

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.run erzeugt, 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:

CommandLineRunner fü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:

ApplicationRunner führt Startup-Code aus und erhält strukturierte Application Arguments.


14. CommandLineRunner vs. ApplicationRunner

ThemaCommandLineRunnerApplicationRunner
Methoderun(String... args)run(ApplicationArguments args)
Args-Stilrohes String-Arraygeparste Arguments
Gut füreinfache Startup-ArgsOption-/Non-Option-Args
Läuft wennnach Context-Startupnach Context-Startup

Merksatz:

CommandLineRunner bekommt rohe Args. ApplicationRunner bekommt 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 @Order oder Ordered, 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:

ApplicationReadyEvent bedeutet: 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:

ApplicationFailedEvent signalisiert, 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@PostConstructRunner
Läuftwährend Bean Initializationnach Context-Startup
Gehört zueinem Bean LifecycleApplication-Startup-Logik
Gut fürInitialisierung einer BeanApp-Level-Startup-Code
Hat App Argsneinja
Kann alle Beans nutzeneingeschränkt; Bean initialisiert nochja, Context ist bereit

Merksatz:

@PostConstruct initialisiert eine Bean. Runners führen Application-Level-Startup-Logik aus.


45. Runners vs. ApplicationReadyEvent

ThemaRunnerApplicationReadyEvent
Läuftnach Context-Startnach Abschluss der Runners
Nutzen fürStartup-TasksLogik nach vollständig bereiter App
Kann Startup failenjaja, wenn Exception geworfen wird
Bekommt ArgsjaEvent fokussiert nicht auf Args

Merksatz:

Runners laufen vor Ready. ApplicationReadyEvent kommt 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 CommandLineRunner und ApplicationRunner?

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:

  1. Wann läuft das?
  2. In welchem Profile läuft es?
  3. Bekommt es rohe oder geparste Args?

Antworten:

  1. Nachdem der Application Context erzeugt und refreshed wurde.
  2. Nur im dev-Profile.
  3. 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.run startet die Spring-Boot-Anwendung.
  • Startup bedeutet: config, context, beans, server, runners, ready.
  • CommandLineRunner erhält rohe String... args.
  • ApplicationRunner erhält geparste ApplicationArguments.
  • Runners laufen nach Context-Startup und vor ApplicationReadyEvent.
  • Nutze @Order oder Ordered, um Runners zu ordnen.
  • Wenn ein Runner eine Exception wirft, kann der Startup fehlschlagen.
  • Schütze gefährliche Runners mit Profiles oder Properties.
  • ApplicationStartedEvent passiert vor Runners.
  • ApplicationReadyEvent passiert nach Runners.
  • ApplicationFailedEvent signalisiert 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.
  • @PostConstruct ist Bean-Level-Initialisierung.
  • Runners sind Application-Level-Startup-Logik.
  • Debugge Startup mit Logs, Failure Analysis, Conditions, Beans, Configprops und Dependency-Tree-Tools.