Skip to main content

Week 3 Day 5 — Spring Boot Application Startup: Runners, Events, Lazy Initialization, and Startup Debugging

Goal

Today I want to understand what happens when a Spring Boot application starts.

Main questions:

  1. What does SpringApplication.run(...) do?
  2. What happens during application startup?
  3. What is CommandLineRunner?
  4. What is ApplicationRunner?
  5. What is the difference between them?
  6. When should I use runners?
  7. What are Spring Boot application events?
  8. What is ApplicationReadyEvent?
  9. What is ApplicationFailedEvent?
  10. What is lazy initialization?
  11. How can I debug startup problems?
  12. What are common exam traps?

1. Quick Review from Week 3 Day 4

In Day 4, I learned:

  • Actuator provides production-ready monitoring and management endpoints.
  • /actuator/health shows application health.
  • /actuator/metrics shows runtime metrics.
  • /actuator/beans shows registered Spring beans.
  • /actuator/conditions shows auto-configuration decisions.
  • /actuator/configprops shows configuration properties.
  • Actuator endpoints must be exposed and secured carefully.

Memory sentence:

Actuator helps me observe a running Spring Boot application.

Today I learn what happens when the application starts.


2. The Main Method

A normal Spring Boot app starts here:

@SpringBootApplication
public class KlarsyncApplication {

public static void main(String[] args) {
SpringApplication.run(KlarsyncApplication.class, args);
}
}

The most important line is:

SpringApplication.run(KlarsyncApplication.class, args);

Simple meaning:

Start the Spring Boot application.

But internally, a lot happens.


3. What Does SpringApplication.run(...) Do?

Simplified answer:

SpringApplication.run(...) creates and refreshes the Spring ApplicationContext.

During startup, 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

Memory sentence:

SpringApplication.run creates, configures, refreshes, and starts the application context.


4. Startup Mental Model

Think of startup like this:

Read configuration

Create container

Register bean recipes

Create beans

Inject dependencies

Initialize beans

Start web server

Run startup runners

Application ready

Shorter version:

config -> context -> beans -> server -> runners -> ready

5. ApplicationContext Refresh

A key part of startup is:

refresh the ApplicationContext

Refreshing the context means Spring:

loads bean definitions
creates bean factory
registers post-processors
creates singleton beans
injects dependencies
initializes beans
starts lifecycle components

If context refresh fails, the application fails to start.

Example failure reasons:

missing bean
ambiguous bean
invalid configuration property
database configuration error
circular dependency
port already in use
bean initialization exception

6. What Happens Before Beans Are Created?

Before Spring creates beans, it prepares the environment.

Environment includes:

application.yml
application.properties
profile-specific files
environment variables
command-line arguments
system properties
active profiles

This is why properties and profiles are available during bean creation.

Example:

spring:
profiles:
active: dev

or:

java -jar app.jar --spring.profiles.active=prod

Spring Boot reads these early.


7. What Happens When Beans Are Created?

Spring creates beans according to their BeanDefinition.

For singleton beans, by default:

Spring creates them during startup.

Example:

@Service
public class TaskService {

public TaskService(TaskRepository taskRepository) {
}
}

Spring must create:

TaskRepository
TaskService

and inject dependencies.

If dependency injection fails, startup fails.


8. Startup Failure Example: Missing Bean

Code:

@Service
public class TaskService {

public TaskService(TaskRepository taskRepository) {
}
}

But no TaskRepository bean exists.

Possible error:

Parameter 0 of constructor in TaskService required a bean of type TaskRepository that could not be found.

Meaning:

Spring could not create TaskService because its dependency is missing.

Startup stops.


9. Startup Failure Example: Port Already in Use

If another process already uses port 8080, startup may fail.

Example:

Web server failed to start. Port 8080 was already in use.

Fix options:

stop the other process
change server.port
use a different profile
configure random port in tests

Example:

server:
port: 8081

10. Startup Failure Example: Invalid Config

YAML:

app:
max-tasks: abc

Java:

@ConfigurationProperties(prefix = "app")
public record AppProperties(
int maxTasks
) {
}

Spring cannot convert "abc" to int.

Result:

Application fails to start.

This is good because invalid configuration is detected early.


11. Startup Failure Example: DataSource

Dependency:

implementation("org.springframework.boot:spring-boot-starter-data-jpa")

No datasource config.

Possible error:

Failed to configure a DataSource

Why?

Spring Boot sees JPA/database classes and tries to configure a DataSource.

Fix:

configure datasource
add database driver
use embedded DB for tests
remove JPA starter
exclude DataSourceAutoConfiguration only if truly needed

12. CommandLineRunner

CommandLineRunner lets me run code after the application context has started.

Example:

@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));
}
}

If I start:

java -jar app.jar one two three

Then args contains:

one
two
three

Simple definition:

CommandLineRunner runs startup code and receives raw command-line arguments.


13. ApplicationRunner

ApplicationRunner is similar, but it receives parsed application arguments.

Example:

@Component
public class StartupApplicationRunner implements ApplicationRunner {

@Override
public void run(ApplicationArguments args) {
System.out.println("Option names: " + args.getOptionNames());
}
}

Start app:

java -jar app.jar --mode=import --limit=100 file1.csv

ApplicationArguments can distinguish:

option arguments: --mode=import, --limit=100
non-option arguments: file1.csv

Simple definition:

ApplicationRunner runs startup code and receives structured application arguments.


14. CommandLineRunner vs ApplicationRunner

TopicCommandLineRunnerApplicationRunner
Methodrun(String... args)run(ApplicationArguments args)
Args styleraw String arrayparsed arguments
Good forsimple startup argsoption/non-option args
Runs whenafter context startupafter context startup

Memory sentence:

CommandLineRunner gets raw args. ApplicationRunner gets parsed args.


15. When Do Runners Run?

Runners run after the application context has been created and refreshed.

Important startup order:

1. Beans are created
2. Dependencies are injected
3. Application context is refreshed
4. ApplicationRunner and CommandLineRunner run
5. ApplicationReadyEvent is published

So runners are useful when I need to run code after beans are ready.


16. What Are Runners Used For?

Good 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

Example dev data:

@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. Be Careful with Runners

Bad 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

Bad:

@Component
public class DangerousRunner implements CommandLineRunner {

@Override
public void run(String... args) {
deleteAllData();
}
}

Better:

protect with profile
protect with property condition
run explicitly
use migration tools
use scheduled job
use admin endpoint

Memory sentence:

Runners are powerful, but they run every startup.


18. Protecting Runners with Profiles

Example:

@Component
@Profile("dev")
public class DevSeedDataRunner implements CommandLineRunner {

@Override
public void run(String... args) {
System.out.println("Seeding dev data");
}
}

This runner only runs in the dev profile.

It does not run in production.


19. Protecting Runners with Properties

Example:

@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

This is useful when startup behavior should be controlled by configuration.


20. Ordering Multiple Runners

If multiple runners exist, I can control order.

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");
}
}

Memory sentence:

Use @Order or Ordered to control runner order.


21. Exceptions in Runners

If a runner throws an exception, startup usually fails.

Example:

@Component
public class FailingRunner implements CommandLineRunner {

@Override
public void run(String... args) {
throw new IllegalStateException("Startup failed");
}
}

Result:

Application fails to start.

This can be good if the app must not run with invalid state.

But be careful with non-critical tasks.


22. Runners in Web Apps vs CLI Apps

In a web app:

Runners execute during startup.
Then the app continues running and handles HTTP requests.

In a CLI app:

Runners can perform the main job.
Then the app may exit if no non-daemon threads keep it alive.

Spring Boot can be used for:

REST APIs
workers
CLI tools
batch-like jobs
message consumers
scheduled services

Not only web apps.


23. Application Events

Spring Boot publishes events during startup.

Simple definition:

Application events are notifications published by Spring Boot during different phases of startup and shutdown.

Important events:

ApplicationStartingEvent
ApplicationEnvironmentPreparedEvent
ApplicationContextInitializedEvent
ApplicationPreparedEvent
ApplicationStartedEvent
ApplicationReadyEvent
ApplicationFailedEvent

For certification, the most useful are:

ApplicationReadyEvent
ApplicationFailedEvent

24. ApplicationReadyEvent

ApplicationReadyEvent is published when the application is ready.

Example:

@Component
public class ReadyListener {

@EventListener(ApplicationReadyEvent.class)
public void onReady() {
System.out.println("Application is ready");
}
}

Meaning:

The application has started and runners have been called.

Use it when you need logic after the app is fully ready.

Memory sentence:

ApplicationReadyEvent means the app is ready to service requests.


25. ApplicationStartedEvent vs ApplicationReadyEvent

Important distinction:

ApplicationStartedEvent happens after the context is refreshed but before runners run.

ApplicationReadyEvent happens after runners have run and the application is ready.

Memory sentence:

Started is before runners. Ready is after runners.


26. ApplicationFailedEvent

ApplicationFailedEvent is published if application startup fails.

Example concept:

public class StartupFailureListener {

@EventListener(ApplicationFailedEvent.class)
public void onFailure(ApplicationFailedEvent event) {
System.out.println("Application failed: " + event.getException().getMessage());
}
}

Important:

If the application context failed before this bean was created, a normal @Component listener may not be available.

For very early events, listeners often need to be registered differently.

Exam-safe memory:

ApplicationFailedEvent signals that startup failed.


27. Listening to Events with @EventListener

For normal application events, use:

@EventListener

Example:

@Component
public class StartupEvents {

@EventListener(ApplicationReadyEvent.class)
public void afterReady() {
System.out.println("Ready");
}
}

This is simple and common.


28. Early Events Need Early Registration

Some events happen before the application context is fully created.

Example:

ApplicationStartingEvent
ApplicationEnvironmentPreparedEvent

A listener registered as a normal bean may not receive these early events because the bean does not exist yet.

For early events, listeners can be registered directly on SpringApplication.

Example concept:

public static void main(String[] args) {
SpringApplication app = new SpringApplication(KlarsyncApplication.class);
app.addListeners(event -> System.out.println(event.getClass().getSimpleName()));
app.run(args);
}

Exam trap:

Not all startup events can be listened to by normal Spring beans.


29. Lazy Initialization

By default, singleton beans are usually created eagerly during startup.

Lazy initialization means:

Create beans only when they are first needed.

Enable globally:

spring:
main:
lazy-initialization: true

Or for one bean:

@Component
@Lazy
public class HeavyService {
}

30. Why Use Lazy Initialization?

Possible benefits:

faster startup
less memory used at startup
avoid creating rarely used beans
useful in development or special apps

Example:

@Component
@Lazy
public class ReportExportService {

public ReportExportService() {
System.out.println("Heavy service created");
}
}

This bean is created only when first requested.


31. Risks of Lazy Initialization

Lazy initialization can hide problems until runtime.

Example:

@Component
@Lazy
public class BrokenService {

public BrokenService(MissingDependency missingDependency) {
}
}

If lazy, the app may start successfully.

But later, when BrokenService is first requested, it fails.

Risks:

missing bean discovered late
configuration error discovered late
first request slower
runtime failure instead of startup failure
harder debugging

Memory sentence:

Lazy initialization can make startup faster but can delay errors.


32. Lazy Initialization and @PostConstruct

For a lazy bean, @PostConstruct runs when the bean is actually created.

Example:

@Component
@Lazy
public class HeavyService {

@PostConstruct
public void init() {
System.out.println("HeavyService initialized");
}
}

If no one needs HeavyService at startup, init() does not run at startup.

It runs later when the bean is first used.


33. Startup Debugging Tools

Useful tools:

startup logs
--debug
debug=true
Actuator /actuator/conditions
Actuator /actuator/beans
Actuator /actuator/configprops
dependency tree
failure analysis
application events

Memory sentence:

Debug startup by checking logs, conditions, beans, config, and dependencies.


34. --debug

Run:

java -jar app.jar --debug

or:

debug: true

This prints more diagnostic information, including auto-configuration condition details.

Use when asking:

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 often provides helpful failure analysis.

Example:

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.

Read:

Description
Reason
Action
Caused by

Do not only read the first line.

Memory sentence:

Spring Boot failure analysis often tells you what failed and how to fix it.


36. Common Startup Error: Missing Bean

Error:

No qualifying bean of type 'EmailSender' available

Checklist:

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. Common Startup Error: Multiple Beans

Error:

required a single bean, but 2 were found

Fix options:

@Primary
@Qualifier
inject List<T>
inject Map<String,T>
use more specific type
remove duplicate bean
check profiles

38. Common Startup Error: Circular Dependency

Example:

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

Problem:

AService needs BService.
BService needs AService.

Best fix:

refactor responsibilities
extract common service
use events
redesign dependencies

Avoid using lazy or setter workarounds as the first solution.


39. Common Startup Error: Invalid Configuration Properties

Error:

Failed to bind properties under 'app.max-tasks' to int

Check:

YAML value type
property name
relaxed binding
@ConfigurationProperties registration
validation annotations
active profile
environment variable override

40. Common Startup Error: Port Already Used

Error:

Port 8080 was already in use

Fix:

server:
port: 8081

Or find process:

lsof -i :8080

Then stop it if appropriate.


41. Common Startup Error: JPA/DataSource

Error:

Failed to configure a DataSource

Check:

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

Things that can slow startup:

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

Good practice:

Keep startup logic small.
Avoid slow external calls during startup.
Use profiles/properties for optional startup tasks.
Move heavy jobs out of startup.

43. Measuring Startup with Actuator

Spring Boot Actuator can expose startup information if configured with startup tracking.

Conceptually, startup information can help answer:

Which startup steps took time?
Which bean took long to initialize?
Where is startup slow?

For certification, focus on the concept:

Startup can be debugged through logs, failure analysis, Actuator, and condition reports.


44. Runners vs @PostConstruct

Topic@PostConstructRunner
Runsduring bean initializationafter context startup
Belongs toone bean lifecycleapplication startup logic
Good forinitializing one beanrunning app-level startup code
Has app argsnoyes
Can use all beanslimited; bean still initializingyes, context is ready

Memory sentence:

@PostConstruct initializes a bean. Runners run application-level startup logic.


45. Runners vs ApplicationReadyEvent

TopicRunnerApplicationReadyEvent
Runsafter context startedafter runners complete
Use forstartup taskslogic after app is fully ready
Can fail startupyesyes, if exception is thrown
Gets argsyesevent does not focus on args

Memory sentence:

Runners run before ready. ApplicationReadyEvent comes after runners.


46. Runners vs Migrations

Do not use runners as a replacement for database migration tools.

Bad idea:

@Component
public class SchemaRunner implements CommandLineRunner {
public void run(String... args) {
createTablesManually();
}
}

Better tools:

Flyway
Liquibase

Use runners for data seeding or app-level startup tasks, not schema migration.


47. Runners and Transactions

A runner can call transactional services.

Example:

@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
}
}

This is better than putting @Transactional on a self-invoked method inside the runner.

Memory sentence:

Let the runner call another bean if proxy-based behavior is needed.


48. Application Availability

Spring Boot has availability states.

Important concepts:

liveness
readiness

Liveness

Is the app alive?

Readiness

Is the app ready to receive traffic?

During startup:

App is not ready until startup completes.

After ready:

App can accept traffic.

This matters in deployment platforms like Kubernetes.


49. Common Exam Traps

Trap 1

SpringApplication.run(...) does much more than call main.

It creates and refreshes the ApplicationContext.


Trap 2

CommandLineRunner gets raw String... args.

ApplicationRunner gets parsed ApplicationArguments.


Trap 3

Runners run after the application context has been created and refreshed.


Trap 4

ApplicationStartedEvent happens before runners.

ApplicationReadyEvent happens after runners.


Trap 5

Runners execute on every startup.

Protect dangerous runners with profiles or properties.


Trap 6

If a runner throws an exception, startup can fail.


Trap 7

Lazy initialization can make startup faster but delay errors until runtime.


Trap 8

Normal Spring bean listeners may not receive very early startup events because the beans do not exist yet.


Trap 9

@PostConstruct is for bean initialization.

Runners are for application-level startup logic.


Trap 10

Read Spring Boot failure analysis carefully. It often tells the cause and action.


50. Real Exam Question: SpringApplication.run

Question:

What does SpringApplication.run(...) do?

Answer:

It starts the Spring Boot application by creating and refreshing the ApplicationContext, loading configuration, applying auto-configuration, scanning components, creating beans, injecting dependencies, running lifecycle callbacks, starting the web server if needed, running startup runners, and publishing application events.


51. Real Exam Question: CommandLineRunner

Question:

What is CommandLineRunner?

Answer:

CommandLineRunner is a callback interface that runs code after the application context has been created and refreshed. It receives raw command-line arguments as String... args.


52. Real Exam Question: ApplicationRunner

Question:

What is ApplicationRunner?

Answer:

ApplicationRunner is a callback interface that runs code after the application context has been created and refreshed. It receives parsed application arguments through ApplicationArguments.


53. Real Exam Question: Runner Difference

Question:

What is the difference between CommandLineRunner and ApplicationRunner?

Answer:

CommandLineRunner receives raw command-line arguments as a string array. ApplicationRunner receives parsed arguments as an ApplicationArguments object.


54. Real Exam Question: Runner Order

Question:

How can I order multiple runners?

Answer:

Use @Order or implement the Ordered interface.


55. Real Exam Question: Runner Exception

Question:

What happens if a runner throws an exception?

Answer:

The application startup usually fails.


56. Real Exam Question: ApplicationReadyEvent

Question:

When is ApplicationReadyEvent published?

Answer:

It is published when the application is fully started and ready, after runners have been called.


57. Real Exam Question: ApplicationStartedEvent

Question:

What is the difference between ApplicationStartedEvent and ApplicationReadyEvent?

Answer:

ApplicationStartedEvent is published after the application context is refreshed but before runners run. ApplicationReadyEvent is published after runners have run and the application is ready.


58. Real Exam Question: Lazy Initialization

Question:

What is lazy initialization?

Answer:

Lazy initialization means beans are created only when they are first needed instead of being created eagerly at startup.


59. Real Exam Question: Lazy Risk

Question:

What is a risk of lazy initialization?

Answer:

It can delay errors until runtime. Missing dependencies or configuration problems may not appear at startup but only when the lazy bean is first used.


60. Real Exam Question: @PostConstruct vs Runner

Question:

What is the difference between @PostConstruct and a runner?

Answer:

@PostConstruct runs during the lifecycle of a specific bean after its dependencies are injected. A runner runs application-level startup code after the application context has been created and refreshed.


61. Interview Answer

Question:

What happens when a Spring Boot application starts?

Good answer:

When a Spring Boot application starts, SpringApplication.run prepares the environment, loads configuration, creates the ApplicationContext, applies auto-configuration, scans components, registers bean definitions, creates singleton beans, injects dependencies, runs lifecycle callbacks, starts the embedded web server if needed, runs ApplicationRunner and CommandLineRunner beans, and finally publishes ApplicationReadyEvent.


62. Interview Answer

Question:

What is the difference between CommandLineRunner and ApplicationRunner?

Good answer:

Both run after the application context has started. CommandLineRunner receives raw command-line arguments as String... args, while ApplicationRunner receives an ApplicationArguments object that separates option arguments and non-option arguments. I use ApplicationRunner when I want structured access to command-line options.


63. Interview Answer

Question:

When would you use a runner?

Good answer:

I would use a runner for application-level startup logic, such as seeding demo data in a development profile, running a command-line import job, validating startup assumptions, or logging startup information. I would avoid heavy or dangerous production tasks in runners unless they are protected by profiles or properties, because runners execute on every startup.


64. Interview Answer

Question:

What is lazy initialization?

Good answer:

Lazy initialization means Spring creates beans only when they are first needed instead of eagerly during startup. It can improve startup time and reduce initial memory usage, but it can also delay errors until runtime. For example, a missing dependency in a lazy bean might not fail application startup but fail later when the bean is first requested.


65. Interview Answer

Question:

How do you debug startup problems?

Good answer:

I start by reading the failure analysis and the root cause in the logs. Then I check whether the error is a missing bean, multiple beans, invalid configuration property, profile issue, port conflict, or auto-configuration problem. I can run with --debug, use Actuator /actuator/conditions, /actuator/beans, and /actuator/configprops, and inspect the dependency tree if the issue is dependency-related.


66. Tiny Code Practice

Create a runner:

@Component
@Profile("dev")
public class DevStartupRunner implements ApplicationRunner {

@Override
public void run(ApplicationArguments args) {
System.out.println("Dev startup runner executed");
}
}

Questions:

  1. When does this run?
  2. In which profile does it run?
  3. Does it receive raw args or parsed args?

Answers:

  1. After the application context has been created and refreshed.
  2. Only in the dev profile.
  3. It receives parsed args through ApplicationArguments.

67. Tiny Bug Practice 1

Problem:

@Component
public class SeedRunner implements CommandLineRunner {

@Override
public void run(String... args) {
seedProductionData();
}
}

Question:

What is dangerous?

Answer:

The runner executes on every startup in every profile. If it modifies production data, it can be dangerous. Protect it with @Profile("dev"), @ConditionalOnProperty, or move the logic to a safer explicit process.


68. Tiny Bug Practice 2

Problem:

spring:
main:
lazy-initialization: true

The application starts successfully, but the first request fails with a missing bean error.

Question:

Why?

Answer:

Lazy initialization delayed bean creation until the first request. The missing dependency was not discovered at startup because the broken bean was not created until it was needed.


69. Tiny Bug Practice 3

Problem:

@Component
public class EarlyListener {

@EventListener(ApplicationStartingEvent.class)
public void onStarting() {
System.out.println("Starting");
}
}

The method does not run.

Question:

Why?

Answer:

ApplicationStartingEvent is published very early, before the application context is created and before this component exists as a bean. Early event listeners must be registered directly on SpringApplication or through another early registration mechanism.


Practice Questions and Answers

Question 1

What does SpringApplication.run(...) do?

Answer:

SpringApplication.run(...) starts the Spring Boot application by creating and refreshing the ApplicationContext, loading configuration, applying auto-configuration, scanning components, creating beans, injecting dependencies, running lifecycle callbacks, starting the web server if needed, running startup runners, and publishing application events.


Question 2

What is the simplified startup flow?

Answer:

A simplified startup flow is: read configuration, create context, register bean definitions, create beans, inject dependencies, initialize beans, start web server if needed, run runners, and publish ready event.


Question 3

What is CommandLineRunner?

Answer:

CommandLineRunner is a callback interface that runs code after the application context has started. It receives raw command-line arguments as String... args.


Question 4

What is ApplicationRunner?

Answer:

ApplicationRunner is a callback interface that runs code after the application context has started. It receives parsed application arguments as an ApplicationArguments object.


Question 5

What is the difference between CommandLineRunner and ApplicationRunner?

Answer:

CommandLineRunner receives raw string arguments. ApplicationRunner receives structured ApplicationArguments.


Question 6

When do runners run?

Answer:

Runners run after the application context has been created and refreshed, and before ApplicationReadyEvent.


Question 7

How can I order multiple runners?

Answer:

Use @Order or implement Ordered.


Question 8

What happens if a runner throws an exception?

Answer:

If a runner throws an exception, application startup usually fails.


Question 9

When should I use a runner?

Answer:

Use a runner for application-level startup logic such as dev data seeding, startup validation, CLI jobs, or safe cache warmup.


Question 10

Why should dangerous runners be protected with profiles or properties?

Answer:

Because runners execute on every startup. Dangerous runners can modify data or block production startup if not protected.


Question 11

What is ApplicationReadyEvent?

Answer:

ApplicationReadyEvent is published when the application is fully started and ready, after runners have executed.


Question 12

What is ApplicationFailedEvent?

Answer:

ApplicationFailedEvent is published when application startup fails.


Question 13

What is the difference between ApplicationStartedEvent and ApplicationReadyEvent?

Answer:

ApplicationStartedEvent happens after the context is refreshed but before runners run. ApplicationReadyEvent happens after runners have run and the app is ready.


Question 14

Why may normal bean listeners not receive very early events?

Answer:

Very early events can happen before the application context is created, so normal Spring beans do not exist yet and cannot receive those events.


Question 15

What is lazy initialization?

Answer:

Lazy initialization means beans are created only when first needed instead of being created eagerly during startup.


Question 16

How can I enable lazy initialization globally?

Answer:

Use:

spring:
main:
lazy-initialization: true

Question 17

What is a risk of lazy initialization?

Answer:

Lazy initialization can delay errors until runtime because broken beans may not be created during startup.


Question 18

What is the difference between @PostConstruct and a runner?

Answer:

@PostConstruct is bean-level initialization after dependency injection. A runner is application-level startup logic after the context has started.


Question 19

What are common startup failure causes?

Answer:

Common causes include missing beans, multiple matching beans, invalid configuration, circular dependencies, port conflicts, DataSource configuration errors, profile mistakes, and bean initialization exceptions.


Question 20

How can I debug startup problems?

Answer:

Use startup logs, failure analysis, --debug, debug=true, Actuator /actuator/conditions, /actuator/beans, /actuator/configprops, and dependency tree tools.

Final Memory Sentences

  • SpringApplication.run starts the Spring Boot application.
  • Startup means config, context, beans, server, runners, ready.
  • CommandLineRunner receives raw String... args.
  • ApplicationRunner receives parsed ApplicationArguments.
  • Runners run after context startup and before ApplicationReadyEvent.
  • Use @Order or Ordered to order runners.
  • If a runner throws an exception, startup can fail.
  • Protect dangerous runners with profiles or properties.
  • ApplicationStartedEvent happens before runners.
  • ApplicationReadyEvent happens after runners.
  • ApplicationFailedEvent signals startup failure.
  • Very early events may happen before normal Spring beans exist.
  • Lazy initialization creates beans when first needed.
  • Lazy initialization can improve startup but delay errors.
  • @PostConstruct is bean-level initialization.
  • Runners are application-level startup logic.
  • Debug startup with logs, failure analysis, conditions, beans, configprops, and dependency tree tools.