or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

admin-jmx.mdansi-support.mdaot-native-image.mdapplication-info.mdavailability.mdbootstrap.mdbootstrapping.mdbuilder.mdcloud-platform.mdconfiguration-annotations.mdconfiguration-data.mdconfiguration-properties.mdconversion.mddiagnostics.mdenvironment-property-sources.mdindex.mdjson-support.mdlifecycle-events.mdlogging.mdorigin-tracking.mdresource-loading.mdretry-support.mdssl-tls.mdstartup-metrics.mdsupport.mdsystem-utilities.mdtask-execution.mdthreading.mdutilities.mdvalidation.mdweb-support.md
tile.json

tessl/maven-org-springframework-boot--spring-boot

Core library providing essential Spring Boot functionality for bootstrapping, configuration, logging, and application lifecycle management.

Workspace
tessl
Visibility
Public
Created
Last updated
Describes
mavenpkg:maven/org.springframework.boot/spring-boot@4.0.x

To install, run

npx @tessl/cli install tessl/maven-org-springframework-boot--spring-boot@4.0.0

index.mddocs/

Spring Boot Core Framework

The core library providing essential Spring Boot functionality for bootstrapping, configuration, logging, and application lifecycle management.

Package Information

  • Package Name: spring-boot

  • Group ID: org.springframework.boot

  • Package Type: maven

  • Language: Java

  • Installation:

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot</artifactId>
        <version>4.0.0</version>
    </dependency>

    Gradle:

    implementation 'org.springframework.boot:spring-boot:4.0.0'

Core Imports

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

Common imports for configuration:

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;

Common imports for lifecycle:

import org.springframework.boot.ApplicationRunner;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.context.event.*;

Basic Usage

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.ApplicationRunner;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;

@SpringBootApplication
public class MyApplication {

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

    @Bean
    public ApplicationRunner runner() {
        return args -> {
            System.out.println("Application started!");
        };
    }
}

@ConfigurationProperties(prefix = "app")
class AppConfig {
    private String name;
    private int timeout = 30;

    // Getters and setters
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
    public int getTimeout() { return timeout; }
    public void setTimeout(int timeout) { this.timeout = timeout; }
}

Quick Reference

This documentation has been enhanced for AI coding agents with comprehensive examples, complete API signatures, thread safety notes, error handling patterns, and production-ready usage patterns.

Package: org.springframework.boot Maven: org.springframework.boot:spring-boot:4.0.0 Module: Core library providing essential Spring Boot functionality

Common Task Lookup

TaskPrimary ClassesKey MethodDoc Link
Bootstrap applicationSpringApplicationrun(Class, String[])bootstrapping.md
Type-safe config@ConfigurationPropertiesEnable with @EnableConfigurationPropertiesconfiguration-properties.md
Lifecycle hooksApplicationRunnerrun(ApplicationArguments)lifecycle-events.md
Health stateApplicationAvailabilitygetLivenessState(), getReadinessState()availability.md
Configure loggingLoggingSystemsetLogLevel(String, LogLevel)logging.md
SSL/TLS setupSslBundlesgetBundle(String)ssl-tls.md
Parse JSONJsonParserparseMap(String), parseList(String)json-support.md
Failure analysisFailureAnalyzeranalyze(Throwable, Throwable)diagnostics.md
Task executionThreadPoolTaskExecutorBuilderbuild()task-execution.md
Register servletServletRegistrationBeanConstructor + setUrlMappings()web-support.md

Package-to-Documentation Mapping

Package PatternDocumentation File
org.springframework.boot.SpringApplication*bootstrapping.md
org.springframework.boot.bootstrap.*bootstrap.md
org.springframework.boot.builder.*builder.md
org.springframework.boot.context.annotation.*configuration-annotations.md
org.springframework.boot.context.properties.*configuration-properties.md
org.springframework.boot.context.config.*configuration-data.md
org.springframework.boot.context.event.*lifecycle-events.md
org.springframework.boot.availability.*availability.md
org.springframework.boot.logging.*logging.md
org.springframework.boot.ssl.*ssl-tls.md
org.springframework.boot.json.*json-support.md
org.springframework.boot.diagnostics.*diagnostics.md
org.springframework.boot.web.*web-support.md
org.springframework.boot.task.*task-execution.md
org.springframework.boot.system.*system-utilities.md
org.springframework.boot.convert.*conversion.md
org.springframework.boot.env.*environment-property-sources.md
org.springframework.boot.info.*application-info.md
org.springframework.boot.cloud.*cloud-platform.md
org.springframework.boot.admin.*admin-jmx.md
org.springframework.boot.ansi.*ansi-support.md
org.springframework.boot.origin.*origin-tracking.md
org.springframework.boot.*Aot*aot-native-image.md
org.springframework.boot.support.*support.md
org.springframework.boot.validation.*validation.md
org.springframework.boot.thread.*threading.md
org.springframework.boot.util.*utilities.md
org.springframework.boot.io.*resource-loading.md

Decision Matrix: ApplicationRunner vs CommandLineRunner

CriterionApplicationRunnerCommandLineRunner
Parsed arguments neededUse this
Raw String[] neededUse this
Access named options (--opt=val)Use this
Simple arg processingEither (prefer ApplicationRunner)

Example:

// ApplicationRunner - parsed arguments
@Component
class MyRunner implements ApplicationRunner {
    public void run(ApplicationArguments args) {
        if (args.containsOption("debug")) { /* ... */ }
    }
}

// CommandLineRunner - raw arguments
@Component
class MyRunner implements CommandLineRunner {
    public void run(String... args) {
        // Process raw args
    }
}

Overview

This tile documents the Spring Boot Core library (org.springframework.boot:spring-boot@4.0.0), which provides the foundational infrastructure for bootstrapping, configuring, and running Spring Boot applications. It is the essential dependency for all Spring Boot applications.

Package Structure

org.springframework.boot
├── admin                    # JMX administration support
├── availability            # Application availability states (liveness/readiness)
├── cloud                   # Cloud platform detection
├── context
│   ├── config             # Configuration data loading
│   ├── event              # Application lifecycle events
│   ├── metrics            # Startup metrics and buffering
│   └── properties         # Configuration properties binding
├── convert                # Type conversion utilities
├── diagnostics            # Failure analysis framework
├── env                    # Environment and property sources
├── info                   # Application runtime information
├── io                     # Resource loading
├── json                   # JSON parsing and writing
├── logging                # Logging system configuration
├── retry                  # Retry policy support
├── ssl                    # SSL/TLS bundle management
├── system                 # System utilities (PID, home, temp)
├── task                   # Task executor builders
├── thread                 # Threading model detection
├── util                   # General utilities
├── web                    # Web application support
│   ├── context           # Web application contexts
│   ├── error             # Error page support
│   ├── server            # Web server abstraction
│   └── servlet           # Servlet registration
└── SpringApplication      # Main entry point

Core Components

Application Bootstrapping

  • SpringApplication: Main class for bootstrapping Spring Boot applications
  • SpringApplicationBuilder: Fluent builder API for SpringApplication configuration
  • ApplicationRunner/CommandLineRunner: Interfaces for executing code after startup

See: bootstrapping.md

Bootstrap Context and Registry

  • BootstrapRegistry: Early-stage object registry available during startup
  • BootstrapContext: Read-only access to bootstrap instances
  • BootstrapRegistryInitializer: Callback for initializing bootstrap registry
  • BootstrapContextClosedEvent: Event when bootstrap context closes

See: bootstrap.md

Configuration Annotations Support

  • Configurations: Manage sets of @Configuration classes with ordering
  • UserConfigurations: User-defined configuration classes with lowest precedence
  • ImportCandidates: Discover configuration imports from META-INF/spring/*.imports files
  • DeterminableImports: Interface for predictable ImportSelector implementations

See: configuration-annotations.md

Application Builder

  • SpringApplicationBuilder: Fluent builder with context hierarchy support
  • ParentContextApplicationContextInitializer: Set parent-child context relationships
  • Context hierarchy: Parent, child, and sibling context configurations

See: builder.md

Environment Post-Processing Support

  • EnvironmentPostProcessorsFactory: Factory for creating EnvironmentPostProcessors
  • SpringApplicationJsonEnvironmentPostProcessor: Process SPRING_APPLICATION_JSON
  • RandomValuePropertySourceEnvironmentPostProcessor: Add random value support
  • SystemEnvironmentPropertySourceEnvironmentPostProcessor: Configure system environment

See: support.md

Validation Support

  • MessageInterpolatorFactory: Create Bean Validation MessageInterpolators
  • MethodValidationExcludeFilter: Filter types from method validation
  • FilteredMethodValidationPostProcessor: Custom method validation with exclusions

See: validation.md

Threading Configuration

  • Threading: Enum for platform vs virtual threads (Java 21+)
  • Virtual thread support: Enable with spring.threads.virtual.enabled=true
  • Thread model detection: Automatic detection of active threading model

See: threading.md

Utility Classes

  • Instantiator: Generic object instantiation with parameter injection
  • LambdaSafe: Safe lambda invocation handling ClassCastException
  • Type-safe callbacks: Avoid type erasure issues in lambda expressions

See: utilities.md

Resource Loading

  • ApplicationResourceLoader: Enhanced resource loading with protocol resolvers
  • FilePathResolver: Resolve resources to file system paths
  • Protocol resolvers: Support for custom protocols (base64:, etc.)

See: resource-loading.md

Configuration System

  • ConfigurationProperties: Type-safe configuration property binding
  • ConfigData API: Extensible configuration data loading (properties, YAML, custom formats)
  • Environment: Unified property access across multiple sources
  • Profiles: Environment-specific configuration activation

See: configuration-properties.md See: configuration-data.md

Application Lifecycle

  • ApplicationEvent: Comprehensive event system covering all lifecycle phases
  • ApplicationListener: Type-safe event listener registration
  • ApplicationContextInitializer: Pre-refresh context customization
  • EnvironmentPostProcessor: Environment configuration before context creation

See: lifecycle-events.md

Logging

  • LoggingSystem: Abstraction over logging frameworks (Logback, Log4J2, JUL)
  • LogFile: Log file location and rotation configuration
  • LogLevel: Dynamic log level adjustment

See: logging.md

SSL/TLS Support

  • SslBundles: Central registry for SSL certificate and key management
  • SslBundle: Abstraction for PEM and JKS certificate bundles
  • Dynamic certificate updates: Runtime certificate rotation without restart

See: ssl-tls.md

JSON Support

  • JsonParser: Parse JSON to Maps and Lists
  • JsonWriter: Write objects to JSON with member filtering
  • Multiple implementations: Jackson, Gson, JSON-B, Simple JSON, basic fallback

See: json-support.md

Application Information

  • BuildProperties: Build-time metadata (version, artifact, timestamp)
  • GitProperties: Git commit information (branch, commit ID, time)
  • JavaInfo: Java runtime environment details
  • OsInfo: Operating system information
  • ProcessInfo: Process details (PID, memory, virtual threads)
  • SslInfo: SSL certificate chain information

See: application-info.md

Availability Management

  • LivenessState: Indicates if application's internal state is healthy
  • ReadinessState: Indicates if application is willing to accept traffic
  • ApplicationAvailability: Query current availability states
  • AvailabilityChangeEvent: Publish state transitions for Kubernetes probes

See: availability.md

Cloud Platform Integration

  • CloudPlatform: Auto-detect cloud environments (Kubernetes, Cloud Foundry, Heroku, AWS ECS, Azure)
  • CloudFoundryVcapEnvironmentPostProcessor: Parse and expose VCAP environment variables
  • Platform-specific behavior: Automatic configuration based on detected platform

See: cloud-platform.md

Type Conversion

  • ApplicationConversionService: Enhanced conversion service with Boot-specific converters
  • DurationStyle/PeriodStyle: Parse human-readable durations and periods
  • DataSizeUnit: Type-safe data size conversion
  • Delimiter annotation: Configure delimited string-to-collection conversion

See: conversion.md

Failure Analysis

  • FailureAnalyzer: SPI for analyzing startup failures
  • FailureAnalysis: Human-readable error descriptions with suggested actions
  • Built-in analyzers: 15+ analyzers for common failure scenarios
  • Custom analyzer support: Extensible via spring.factories

See: diagnostics.md

Environment Property Sources

  • RandomValuePropertySource: Generate random values, UUIDs, ports for testing
  • ConfigTreePropertySource: Read Kubernetes ConfigMaps and Secrets from file trees
  • PropertySourceInfo: Metadata about property sources (immutability, prefixes)

See: environment-property-sources.md

Retry Support

  • RetryPolicySettings: Configure retry policies with exponential backoff and jitter
  • Exception filtering: Retry only specific exception types
  • Integration: Works with Spring Retry's @Retryable and RetryTemplate

See: retry-support.md

Startup Metrics

  • BufferingApplicationStartup: Record startup steps with nanosecond precision
  • StartupTimeline: Timeline of startup events for performance analysis
  • Performance optimization: Identify bottlenecks during application initialization

See: startup-metrics.md

System Utilities

  • ApplicationHome: Detect application home directory (JAR or exploded)
  • ApplicationPid: Process ID management and PID file writing
  • ApplicationTemp: Application-specific temporary directories
  • JavaVersion: Java version detection and comparison
  • Threading: Detect platform vs virtual threads (Java 21+)

See: system-utilities.md

Task Execution

  • ThreadPoolTaskExecutorBuilder: Configure thread pool executors
  • ThreadPoolTaskSchedulerBuilder: Configure scheduled task executors
  • SimpleAsyncTaskExecutorBuilder: Configure simple async executors with virtual thread support
  • TaskDecorator: Decorate tasks (e.g., propagate security context)

See: task-execution.md

Web Support

  • ServletRegistrationBean: Register servlets programmatically
  • FilterRegistrationBean: Register servlet filters
  • ServletListenerRegistrationBean: Register event listeners
  • ErrorPage: Define custom error pages
  • WebServer: Embedded server abstraction (Tomcat, Jetty, Undertow, Netty)
  • Reactive support: Full WebFlux/Project Reactor integration

See: web-support.md

JMX Administration

  • SpringApplicationAdminMXBean: Remote management via JMX
  • Operations: Check readiness, inspect environment, trigger shutdown
  • Production monitoring: Integration with JConsole, VisualVM

See: admin-jmx.md

ANSI Terminal Support

  • AnsiOutput: Generate ANSI colored console output with automatic terminal detection
  • AnsiColor/AnsiBackground: Standard and bright color enums (16 colors)
  • AnsiStyle: Text styling (bold, italic, underline, faint)
  • Ansi8BitColor: Extended 256-color palette support
  • Terminal detection: Automatic ANSI capability detection

See: ansi-support.md

Origin Tracking

  • Origin: Interface for tracking source location of properties and resources
  • OriginProvider/OriginLookup: Interfaces for providing and looking up origins
  • OriginTrackedValue: Wrapper for values with origin information
  • TextResourceOrigin: Origin with file path and line/column numbers
  • PropertySourceOrigin: Origin from PropertySource with property name
  • Hierarchical tracking: Parent origin support for nested origins

See: origin-tracking.md

AOT Processing and Native Image

  • SpringApplicationAotProcessor: Entry point for AOT processing during build
  • AotInitializerNotFoundException: Exception when AOT initializer missing at runtime
  • RuntimeHints API: Register reflection, resources, proxies for GraalVM
  • Native image compilation: Build standalone executables with <100ms startup
  • Build tool integration: Maven and Gradle plugin support
  • Testing: Native test support for validation

See: aot-native-image.md

Quick Start

Basic Application Bootstrap

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class MyApplication {

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

Configuration Properties

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.bind.DefaultValue;
import java.time.Duration;

@ConfigurationProperties(prefix = "myapp")
public class MyAppProperties {

    private String name;
    private Duration timeout = Duration.ofSeconds(30);
    private int maxRetries = 3;

    // Getters and setters
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }

    public Duration getTimeout() { return timeout; }
    public void setTimeout(Duration timeout) { this.timeout = timeout; }

    public int getMaxRetries() { return maxRetries; }
    public void setMaxRetries(int maxRetries) { this.maxRetries = maxRetries; }
}

Lifecycle Event Handling

import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;

@Component
public class StartupListener {

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

Availability State Management

import org.springframework.boot.availability.AvailabilityChangeEvent;
import org.springframework.boot.availability.LivenessState;
import org.springframework.boot.availability.ReadinessState;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Component;

@Component
public class HealthManager {

    private final ApplicationEventPublisher publisher;

    public HealthManager(ApplicationEventPublisher publisher) {
        this.publisher = publisher;
    }

    public void markAsReady() {
        AvailabilityChangeEvent.publish(publisher, this, ReadinessState.ACCEPTING_TRAFFIC);
    }

    public void markAsUnhealthy() {
        AvailabilityChangeEvent.publish(publisher, this, LivenessState.BROKEN);
    }
}

Common Patterns

Pattern 1: Complete Spring Boot Application with Configuration Properties

Production-ready application demonstrating configuration properties binding and lifecycle management:

package com.example.app;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;

import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotBlank;
import java.time.Duration;

/**
 * Main application class with configuration properties.
 */
@SpringBootApplication
@EnableConfigurationProperties(AppProperties.class)
public class MyApplication {

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

/**
 * Type-safe configuration properties with validation.
 */
@ConfigurationProperties(prefix = "app")
public class AppProperties {

    @NotBlank
    private String name;

    @Min(1)
    private int maxConnections = 10;

    private Duration timeout = Duration.ofSeconds(30);

    private Database database = new Database();
    private Cache cache = new Cache();

    // Getters and setters
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }

    public int getMaxConnections() { return maxConnections; }
    public void setMaxConnections(int maxConnections) {
        this.maxConnections = maxConnections;
    }

    public Duration getTimeout() { return timeout; }
    public void setTimeout(Duration timeout) { this.timeout = timeout; }

    public Database getDatabase() { return database; }
    public void setDatabase(Database database) { this.database = database; }

    public Cache getCache() { return cache; }
    public void setCache(Cache cache) { this.cache = cache; }

    public static class Database {
        @NotBlank
        private String url;
        private String username;
        private String password;
        private int maxPoolSize = 20;

        // Getters and setters
        public String getUrl() { return url; }
        public void setUrl(String url) { this.url = url; }

        public String getUsername() { return username; }
        public void setUsername(String username) { this.username = username; }

        public String getPassword() { return password; }
        public void setPassword(String password) { this.password = password; }

        public int getMaxPoolSize() { return maxPoolSize; }
        public void setMaxPoolSize(int maxPoolSize) {
            this.maxPoolSize = maxPoolSize;
        }
    }

    public static class Cache {
        private boolean enabled = true;
        private Duration ttl = Duration.ofMinutes(10);
        private int maxSize = 1000;

        // Getters and setters
        public boolean isEnabled() { return enabled; }
        public void setEnabled(boolean enabled) { this.enabled = enabled; }

        public Duration getTtl() { return ttl; }
        public void setTtl(Duration ttl) { this.ttl = ttl; }

        public int getMaxSize() { return maxSize; }
        public void setMaxSize(int maxSize) { this.maxSize = maxSize; }
    }
}

/**
 * Service using configuration properties.
 */
@Service
public class ApplicationService {

    private final AppProperties properties;

    public ApplicationService(AppProperties properties) {
        this.properties = properties;
    }

    @EventListener(ApplicationReadyEvent.class)
    public void onApplicationReady() {
        System.out.println("Application Ready: " + properties.getName());
        System.out.println("Max Connections: " + properties.getMaxConnections());
        System.out.println("Timeout: " + properties.getTimeout());
        System.out.println("Database URL: " + properties.getDatabase().getUrl());
        System.out.println("Cache Enabled: " + properties.getCache().isEnabled());
    }

    public void performOperation() {
        // Use properties for business logic
        if (properties.getCache().isEnabled()) {
            System.out.println("Using cache with TTL: " + properties.getCache().getTtl());
        }
    }
}

Configuration file (application.yml):

app:
  name: MyApplication
  max-connections: 50
  timeout: 60s
  database:
    url: jdbc:postgresql://localhost:5432/mydb
    username: admin
    password: secret
    max-pool-size: 30
  cache:
    enabled: true
    ttl: 15m
    max-size: 5000

Pattern 2: Comprehensive Lifecycle Event Handling

Complete event listener system covering all application lifecycle phases:

package com.example.lifecycle;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.availability.AvailabilityChangeEvent;
import org.springframework.boot.availability.LivenessState;
import org.springframework.boot.availability.ReadinessState;
import org.springframework.boot.context.event.*;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.event.ContextClosedEvent;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;

import java.time.Instant;

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

/**
 * Comprehensive lifecycle event listener demonstrating all major events.
 */
@Component
public class ApplicationLifecycleListener {

    private final ApplicationEventPublisher publisher;
    private Instant startTime;

    public ApplicationLifecycleListener(ApplicationEventPublisher publisher) {
        this.publisher = publisher;
    }

    @EventListener
    public void onApplicationStartingEvent(ApplicationStartingEvent event) {
        // Very early in startup - before Spring context is created
        // Limited functionality available
        startTime = Instant.now();
        System.out.println("1. ApplicationStartingEvent - Bootstrap starting");
    }

    @EventListener
    public void onApplicationEnvironmentPreparedEvent(ApplicationEnvironmentPreparedEvent event) {
        // Environment is ready, but context not yet created
        // Can access/modify environment here
        System.out.println("2. ApplicationEnvironmentPreparedEvent - Environment ready");
        System.out.println("   Active profiles: " +
            String.join(",", event.getEnvironment().getActiveProfiles()));
    }

    @EventListener
    public void onApplicationContextInitializedEvent(ApplicationContextInitializedEvent event) {
        // Context created but not yet refreshed
        System.out.println("3. ApplicationContextInitializedEvent - Context initialized");
    }

    @EventListener
    public void onApplicationPreparedEvent(ApplicationPreparedEvent event) {
        // Context prepared and bean definitions loaded, but not yet refreshed
        System.out.println("4. ApplicationPreparedEvent - Context prepared, beans loading");
    }

    @EventListener
    public void onApplicationStartedEvent(ApplicationStartedEvent event) {
        // Context refreshed, application started but CommandLineRunners not yet called
        System.out.println("5. ApplicationStartedEvent - Context refreshed");

        // Now safe to publish availability events
        AvailabilityChangeEvent.publish(publisher, this, LivenessState.CORRECT);
    }

    @EventListener
    public void onApplicationReadyEvent(ApplicationReadyEvent event) {
        // Application fully started and ready to serve requests
        Instant now = Instant.now();
        long startupTime = now.toEpochMilli() - startTime.toEpochMilli();

        System.out.println("6. ApplicationReadyEvent - Application READY");
        System.out.println("   Startup time: " + startupTime + "ms");

        // Mark application as ready to accept traffic
        AvailabilityChangeEvent.publish(publisher, this, ReadinessState.ACCEPTING_TRAFFIC);

        // Perform post-startup initialization
        performPostStartupTasks();
    }

    @EventListener
    public void onApplicationFailedEvent(ApplicationFailedEvent event) {
        // Application failed to start
        System.err.println("7. ApplicationFailedEvent - Startup FAILED");
        System.err.println("   Error: " + event.getException().getMessage());

        // Mark application as broken
        AvailabilityChangeEvent.publish(publisher, this, LivenessState.BROKEN);
    }

    @EventListener
    public void onContextClosedEvent(ContextClosedEvent event) {
        // Application is shutting down
        System.out.println("8. ContextClosedEvent - Application shutting down");

        // Mark application as refusing traffic
        AvailabilityChangeEvent.publish(publisher, this, ReadinessState.REFUSING_TRAFFIC);

        // Perform cleanup
        performShutdownTasks();
    }

    @EventListener
    public void onAvailabilityChangeEvent(AvailabilityChangeEvent<?> event) {
        // Availability state changed
        System.out.println("   AvailabilityChangeEvent: " +
            event.getState().getClass().getSimpleName() + " -> " + event.getState());
    }

    private void performPostStartupTasks() {
        // Warm up caches, establish connections, etc.
        System.out.println("   Performing post-startup initialization...");
    }

    private void performShutdownTasks() {
        // Flush buffers, close connections, etc.
        System.out.println("   Performing graceful shutdown tasks...");
    }
}

Pattern 3: Custom Failure Analyzer

Production-ready failure analyzer for custom error handling:

package com.example.diagnostics;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.diagnostics.AbstractFailureAnalyzer;
import org.springframework.boot.diagnostics.FailureAnalysis;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Service;

import jakarta.annotation.PostConstruct;

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

/**
 * Custom exception for configuration errors.
 */
class InvalidConfigurationException extends RuntimeException {
    private final String configKey;
    private final String providedValue;
    private final String expectedFormat;

    public InvalidConfigurationException(String configKey, String providedValue,
                                        String expectedFormat) {
        super(String.format("Invalid configuration for '%s': '%s'", configKey, providedValue));
        this.configKey = configKey;
        this.providedValue = providedValue;
        this.expectedFormat = expectedFormat;
    }

    public String getConfigKey() { return configKey; }
    public String getProvidedValue() { return providedValue; }
    public String getExpectedFormat() { return expectedFormat; }
}

/**
 * Custom failure analyzer providing helpful error messages and solutions.
 */
public class InvalidConfigurationFailureAnalyzer
        extends AbstractFailureAnalyzer<InvalidConfigurationException> {

    @Override
    protected FailureAnalysis analyze(Throwable rootFailure,
                                     InvalidConfigurationException cause) {
        StringBuilder description = new StringBuilder();
        description.append("Application failed to start due to invalid configuration.\n\n");
        description.append("Configuration Key: ").append(cause.getConfigKey()).append("\n");
        description.append("Provided Value: ").append(cause.getProvidedValue()).append("\n");
        description.append("Expected Format: ").append(cause.getExpectedFormat()).append("\n");

        StringBuilder action = new StringBuilder();
        action.append("Update your configuration:\n\n");
        action.append("1. Check application.properties or application.yml\n");
        action.append("2. Ensure '").append(cause.getConfigKey())
              .append("' matches format: ").append(cause.getExpectedFormat()).append("\n");
        action.append("3. Example: ").append(getExample(cause.getConfigKey())).append("\n");
        action.append("\nFor more information, see: https://docs.example.com/config/")
              .append(cause.getConfigKey().replace('.', '-'));

        return new FailureAnalysis(description.toString(), action.toString(), cause);
    }

    private String getExample(String configKey) {
        return switch (configKey) {
            case "app.database.url" ->
                "app.database.url=jdbc:postgresql://localhost:5432/mydb";
            case "app.timeout" ->
                "app.timeout=30s";
            case "app.max-connections" ->
                "app.max-connections=50";
            default ->
                configKey + "=<valid-value>";
        };
    }
}

/**
 * Service that validates configuration during startup.
 */
@Service
class ConfigurationValidator {

    private final String databaseUrl;

    public ConfigurationValidator(@org.springframework.beans.factory.annotation.Value("${app.database.url}")
                                  String databaseUrl) {
        this.databaseUrl = databaseUrl;
    }

    @PostConstruct
    public void validate() {
        // Validate database URL format
        if (!databaseUrl.startsWith("jdbc:")) {
            throw new InvalidConfigurationException(
                "app.database.url",
                databaseUrl,
                "jdbc:<database-type>://<host>:<port>/<database>"
            );
        }

        System.out.println("Configuration validated successfully");
    }
}

Register the analyzer in META-INF/spring.factories:

org.springframework.boot.diagnostics.FailureAnalyzer=\
com.example.diagnostics.InvalidConfigurationFailureAnalyzer

Pattern 4: Multi-Environment Application Runner

Application runner with environment-specific initialization:

package com.example.runner;

import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Profile;
import org.springframework.core.annotation.Order;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;

import java.util.Arrays;

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

/**
 * Ordered runner that executes first - performs critical initialization.
 */
@Component
@Order(1)
class DatabaseInitializationRunner implements ApplicationRunner {

    @Override
    public void run(ApplicationArguments args) throws Exception {
        System.out.println("1. Database Initialization Runner");
        System.out.println("   Initializing database schema...");
        System.out.println("   Creating indexes...");

        // Access command-line arguments
        if (args.containsOption("force-recreate")) {
            System.out.println("   Force recreate enabled");
        }

        // Access non-option args
        if (!args.getNonOptionArgs().isEmpty()) {
            System.out.println("   Additional args: " + args.getNonOptionArgs());
        }
    }
}

/**
 * Ordered runner that executes second - loads reference data.
 */
@Component
@Order(2)
class DataLoadingRunner implements CommandLineRunner {

    @Override
    public void run(String... args) throws Exception {
        System.out.println("2. Data Loading Runner");
        System.out.println("   Loading reference data...");
        System.out.println("   Command-line args: " + Arrays.toString(args));
    }
}

/**
 * Profile-specific runner for development environment.
 */
@Component
@Order(3)
@Profile("dev")
class DevelopmentDataRunner implements ApplicationRunner {

    @Override
    public void run(ApplicationArguments args) throws Exception {
        System.out.println("3. Development Data Runner (dev profile only)");
        System.out.println("   Loading test users...");
        System.out.println("   Loading sample data...");
    }
}

/**
 * Profile-specific runner for production environment.
 */
@Component
@Order(3)
@Profile("prod")
class ProductionVerificationRunner implements ApplicationRunner {

    private final Environment environment;

    public ProductionVerificationRunner(Environment environment) {
        this.environment = environment;
    }

    @Override
    public void run(ApplicationArguments args) throws Exception {
        System.out.println("3. Production Verification Runner (prod profile only)");

        // Verify critical configuration
        String dbUrl = environment.getProperty("app.database.url");
        if (dbUrl == null || dbUrl.contains("localhost")) {
            throw new IllegalStateException(
                "Invalid database URL for production: " + dbUrl
            );
        }

        System.out.println("   Production environment verified");
        System.out.println("   Database: " + dbUrl);
    }
}

/**
 * Runner with error handling and retry logic.
 */
@Component
@Order(4)
class ExternalServiceHealthCheckRunner implements ApplicationRunner {

    private static final int MAX_RETRIES = 3;

    @Override
    public void run(ApplicationArguments args) throws Exception {
        System.out.println("4. External Service Health Check Runner");

        int attempt = 0;
        boolean healthy = false;

        while (attempt < MAX_RETRIES && !healthy) {
            attempt++;
            System.out.println("   Health check attempt " + attempt + "/" + MAX_RETRIES);

            try {
                // Simulate health check
                Thread.sleep(1000);
                healthy = checkExternalServices();

                if (healthy) {
                    System.out.println("   All external services healthy");
                }
            } catch (Exception e) {
                System.err.println("   Health check failed: " + e.getMessage());

                if (attempt >= MAX_RETRIES) {
                    throw new IllegalStateException(
                        "External services not available after " + MAX_RETRIES + " attempts"
                    );
                }

                // Exponential backoff
                Thread.sleep(1000L * attempt);
            }
        }
    }

    private boolean checkExternalServices() {
        // Check external APIs, databases, message queues, etc.
        return true;
    }
}

Run with arguments:

java -jar app.jar --force-recreate --spring.profiles.active=dev additional-arg

Pattern 5: Advanced SSL/TLS Configuration with Hot Reload

Complete SSL bundle management with certificate rotation:

package com.example.ssl;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.ssl.SslBundle;
import org.springframework.boot.ssl.SslBundles;
import org.springframework.boot.web.server.Ssl;
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.boot.web.servlet.server.ConfigurableServletWebServerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.time.Instant;
import java.util.concurrent.atomic.AtomicReference;

@SpringBootApplication
@EnableScheduling
public class SslApplication {
    public static void main(String[] args) {
        SpringApplication.run(SslApplication.class, args);
    }
}

/**
 * SSL configuration with hot reload support.
 */
@Component
class SslConfigurationManager {

    private final SslBundles sslBundles;
    private final AtomicReference<Instant> lastReload = new AtomicReference<>(Instant.now());

    public SslConfigurationManager(SslBundles sslBundles) {
        this.sslBundles = sslBundles;
    }

    /**
     * Check for certificate updates every hour.
     */
    @Scheduled(fixedRate = 3600000) // Every hour
    public void checkCertificateExpiry() {
        try {
            SslBundle bundle = sslBundles.getBundle("server");

            // Get certificate details (implementation depends on bundle type)
            System.out.println("Checking SSL certificate status...");
            System.out.println("Last reload: " + lastReload.get());

            // Trigger reload if certificate is close to expiry or has been updated
            // In production, check actual certificate expiry dates
            boolean needsReload = shouldReloadCertificate(bundle);

            if (needsReload) {
                reloadCertificate();
            }
        } catch (Exception e) {
            System.err.println("Failed to check certificate status: " + e.getMessage());
        }
    }

    private boolean shouldReloadCertificate(SslBundle bundle) {
        // Check if certificate file has been modified
        // Check if certificate is within 30 days of expiry
        // Implementation depends on your certificate management strategy
        return false;
    }

    public void reloadCertificate() {
        System.out.println("Reloading SSL certificate...");

        try {
            // Reload certificate from disk or certificate store
            // This triggers bundle update listeners
            SslBundle bundle = sslBundles.getBundle("server");

            lastReload.set(Instant.now());
            System.out.println("SSL certificate reloaded successfully at " + lastReload.get());
        } catch (Exception e) {
            System.err.println("Failed to reload certificate: " + e.getMessage());
            throw new RuntimeException("Certificate reload failed", e);
        }
    }
}

/**
 * Web server customizer for SSL configuration.
 */
@Component
class SslWebServerCustomizer implements WebServerFactoryCustomizer<ConfigurableServletWebServerFactory> {

    private final SslBundles sslBundles;

    public SslWebServerCustomizer(SslBundles sslBundles) {
        this.sslBundles = sslBundles;
    }

    @Override
    public void customize(ConfigurableServletWebServerFactory factory) {
        try {
            SslBundle bundle = sslBundles.getBundle("server");

            Ssl ssl = new Ssl();
            ssl.setEnabled(true);

            // Configure SSL from bundle
            factory.setSsl(ssl);

            System.out.println("SSL configured from bundle 'server'");
        } catch (Exception e) {
            System.err.println("Failed to configure SSL: " + e.getMessage());
        }
    }
}

Configuration (application.yml):

spring:
  ssl:
    bundle:
      pem:
        server:
          keystore:
            certificate: classpath:ssl/server.crt
            private-key: classpath:ssl/server.key
          truststore:
            certificate: classpath:ssl/ca.crt
      jks:
        client:
          keystore:
            location: classpath:ssl/client-keystore.jks
            password: changeit
            type: JKS
          truststore:
            location: classpath:ssl/client-truststore.jks
            password: changeit

server:
  port: 8443
  ssl:
    enabled: true
    bundle: server

Best Practices

  1. Configuration Properties Best Practices

    • Use @ConfigurationProperties for type-safe configuration instead of @Value
    • Enable validation with @Validated and JSR-303 annotations
    • Provide sensible defaults for all properties
    • Use nested classes for complex hierarchical configuration
    • Document properties with Javadoc for IDE autocomplete support
  2. Application Lifecycle Management

    • Use ApplicationReadyEvent for post-startup initialization, not @PostConstruct
    • Handle ApplicationFailedEvent for proper error reporting
    • Publish availability state changes for Kubernetes liveness/readiness probes
    • Use @Order to control ApplicationRunner/CommandLineRunner execution sequence
    • Implement graceful shutdown with ContextClosedEvent listeners
  3. Error Handling and Diagnostics

    • Create custom FailureAnalyzer implementations for domain-specific errors
    • Provide actionable error messages with specific solutions
    • Include links to documentation in failure analysis descriptions
    • Log failures with sufficient context for troubleshooting
    • Use fail-fast validation during startup for critical configuration
  4. Environment-Specific Configuration

    • Use Spring profiles for environment-specific beans and configuration
    • Externalize configuration using environment variables in production
    • Never hardcode credentials or secrets in application code
    • Use different property files per environment (application-{profile}.yml)
    • Validate production configuration during startup
  5. Dependency Injection Best Practices

    • Prefer constructor injection over field injection for required dependencies
    • Use @Autowired only for optional dependencies
    • Make injected fields final to ensure immutability
    • Avoid circular dependencies by redesigning component relationships
    • Use ObjectProvider<T> for lazy or optional bean resolution
  6. Logging Configuration

    • Configure logging levels per package, not globally
    • Use structured logging with correlation IDs for request tracking
    • Set appropriate log levels for third-party libraries (reduce noise)
    • Enable debug logging only for specific packages during troubleshooting
    • Use async appenders in high-throughput applications
  7. Performance and Resource Management

    • Configure appropriate thread pool sizes for task executors
    • Set connection pool limits based on expected load
    • Enable lazy initialization (spring.main.lazy-initialization=true) for faster startup in development
    • Use @ConditionalOnProperty to disable features not needed in certain environments
    • Monitor startup time with BufferingApplicationStartup and optimize bottlenecks
  8. Security Configuration

    • Always use SSL/TLS in production (configure via spring.ssl.bundle)
    • Implement certificate rotation with SslBundles hot reload
    • Never log sensitive configuration values (passwords, tokens, keys)
    • Use Spring Boot's secrets management for encrypted properties
    • Validate all external configuration inputs during binding
  9. Testing Strategies

    • Use @SpringBootTest for full integration tests
    • Use @TestPropertySource to override configuration in tests
    • Test each Spring profile configuration separately
    • Mock external dependencies with @MockBean for unit tests
    • Verify startup behavior with OutputCaptureExtension for log assertions
  10. Production Readiness

    • Enable Spring Boot Actuator endpoints for monitoring
    • Configure health indicators for all critical dependencies
    • Set up proper logging aggregation and monitoring
    • Implement distributed tracing (Micrometer Tracing + Zipkin)
    • Use build metadata (spring-boot-maven-plugin with build-info goal) for version tracking

Common Pitfalls

1. Missing @EnableConfigurationProperties

Problem: @ConfigurationProperties class not registered as a bean

Error:

Parameter 0 of constructor in com.example.MyService required a bean of type 'com.example.AppProperties' that could not be found.

Solution:

// Solution 1: Enable in main application class
@SpringBootApplication
@EnableConfigurationProperties(AppProperties.class)
public class MyApplication {
    // ...
}

// Solution 2: Add @Component to properties class
@Component
@ConfigurationProperties(prefix = "app")
public class AppProperties {
    // ...
}

// Solution 3: Use @ConfigurationPropertiesScan
@SpringBootApplication
@ConfigurationPropertiesScan("com.example.config")
public class MyApplication {
    // ...
}

Rationale: Spring Boot requires explicit registration of @ConfigurationProperties classes. Without registration, the class is not instantiated as a bean and cannot be injected into other components.

2. Incorrect Property Naming Convention

Problem: Properties not binding due to naming mismatch

Error: Properties remain null despite being set in application.properties

Solution:

# WRONG - uses dots in compound words
app.maxconnections=50
app.database.maxpoolsize=20

# CORRECT - use kebab-case (recommended)
app.max-connections=50
app.database.max-pool-size=20

# Also works - camelCase
app.maxConnections=50
app.database.maxPoolSize=20
// Java property names use camelCase
@ConfigurationProperties(prefix = "app")
public class AppProperties {
    private int maxConnections;  // Binds to app.max-connections or app.maxConnections

    public int getMaxConnections() { return maxConnections; }
    public void setMaxConnections(int maxConnections) {
        this.maxConnections = maxConnections;
    }
}

Rationale: Spring Boot uses relaxed binding to map property names. Use kebab-case in properties files (recommended) or camelCase. Always use camelCase in Java code. Spring Boot automatically converts between formats.

3. ApplicationRunner vs CommandLineRunner Confusion

Problem: Using wrong interface or expecting wrong argument format

Error: Cannot access parsed command-line options

Solution:

// Use ApplicationRunner when you need parsed arguments
@Component
class MyApplicationRunner implements ApplicationRunner {
    @Override
    public void run(ApplicationArguments args) throws Exception {
        // Access options: --option=value
        if (args.containsOption("debug")) {
            System.out.println("Debug mode enabled");
        }

        // Access non-option args
        List<String> nonOptionArgs = args.getNonOptionArgs();
    }
}

// Use CommandLineRunner when you need raw String[] args
@Component
class MyCommandLineRunner implements CommandLineRunner {
    @Override
    public void run(String... args) throws Exception {
        // Access raw arguments
        System.out.println("Args: " + Arrays.toString(args));
    }
}

Rationale: ApplicationRunner provides parsed arguments via ApplicationArguments, making it easier to access named options. CommandLineRunner provides raw String[] array. Use ApplicationRunner unless you specifically need raw access.

4. Lifecycle Event Timing Issues

Problem: Accessing beans or context too early in lifecycle

Error:

BeanCreationNotAllowedException: Error creating bean with name 'myBean'
NullPointerException when accessing ApplicationContext

Solution:

// WRONG - Too early, context not ready
@Component
public class EarlyInitializer {
    private final ApplicationContext context;

    public EarlyInitializer(ApplicationContext context) {
        // DON'T access beans in constructor
        context.getBean(MyService.class); // MAY FAIL
    }
}

// CORRECT - Use appropriate lifecycle callback
@Component
public class ProperInitializer {

    @Autowired
    private MyService myService; // Injected after construction

    @PostConstruct
    public void init() {
        // Safe to use injected beans here
        myService.initialize();
    }

    @EventListener(ApplicationReadyEvent.class)
    public void onReady() {
        // Safest - application fully started
        myService.performOperation();
    }
}

Rationale: Constructor execution happens during bean creation, before all dependencies are wired. Use @PostConstruct for bean initialization or ApplicationReadyEvent for application-wide initialization after full startup.

5. Missing Validation Annotations

Problem: Invalid configuration accepted without errors

Error: Application starts with invalid configuration, fails later at runtime

Solution:

import jakarta.validation.constraints.*;

@Validated  // REQUIRED for validation to work
@ConfigurationProperties(prefix = "app")
public class AppProperties {

    @NotBlank(message = "Application name is required")
    private String name;

    @Min(value = 1, message = "Max connections must be at least 1")
    @Max(value = 100, message = "Max connections cannot exceed 100")
    private int maxConnections = 10;

    @Pattern(regexp = "^jdbc:.*", message = "Database URL must start with 'jdbc:'")
    private String databaseUrl;

    @NotNull
    @DurationMin(seconds = 1)
    @DurationMax(minutes = 5)
    private Duration timeout;

    // Getters and setters with validation
}

Configuration to trigger validation failure:

app.name=
app.max-connections=150
app.database-url=invalid-url
app.timeout=10m

Rationale: Without @Validated annotation on the properties class, JSR-303 validation annotations are ignored. Application accepts invalid configuration and fails unpredictably later. Always validate critical configuration.

6. Circular Dependency in ApplicationRunner

Problem: ApplicationRunner depends on beans that depend on runner completion

Error:

The dependencies of some of the beans in the application context form a cycle

Solution:

// WRONG - Circular dependency
@Component
class DataLoader implements ApplicationRunner {
    private final MyService service; // MyService depends on DataLoader completion

    @Override
    public void run(ApplicationArguments args) {
        service.loadData(); // Circular!
    }
}

// CORRECT - Break circular dependency
@Component
class DataLoader implements ApplicationRunner {
    private final ApplicationContext context;

    public DataLoader(ApplicationContext context) {
        this.context = context;
    }

    @Override
    public void run(ApplicationArguments args) {
        // Lazy lookup breaks circular dependency
        MyService service = context.getBean(MyService.class);
        service.loadData();
    }
}

// BETTER - Use event listener instead
@Component
class DataLoader {

    private final MyService service;

    public DataLoader(MyService service) {
        this.service = service;
    }

    @EventListener(ApplicationReadyEvent.class)
    public void onReady() {
        service.loadData();
    }
}

Rationale: ApplicationRunner beans are created during startup, which can create circular dependencies. Use lazy lookup via ApplicationContext or switch to @EventListener(ApplicationReadyEvent.class) which fires after all beans are created.

7. Forgetting to Set spring.application.name

Problem: Application identified as "application" in logs and monitoring

Error: Cannot distinguish between multiple applications in distributed systems

Solution:

# application.properties
spring.application.name=my-service

# Or application.yml
spring:
  application:
    name: my-service
// Access programmatically
@Component
public class AppNameChecker {

    @Value("${spring.application.name}")
    private String applicationName;

    @PostConstruct
    public void checkName() {
        if ("application".equals(applicationName)) {
            throw new IllegalStateException(
                "Application name not configured. Set spring.application.name in properties"
            );
        }
    }
}

Rationale: Default application name is "application", which makes it impossible to identify services in logs, metrics, and distributed tracing. Always set a unique application name for each service.

8. Incorrect SSL Bundle Configuration

Problem: SSL certificate not loaded or server won't start with SSL

Error:

java.io.FileNotFoundException: class path resource [ssl/server.crt] cannot be opened
SSL handshake failed

Solution:

# Correct PEM configuration
spring:
  ssl:
    bundle:
      pem:
        server:
          keystore:
            certificate: "file:/etc/ssl/certs/server.crt"  # Use file: for filesystem
            private-key: "file:/etc/ssl/private/server.key"
          truststore:
            certificate: "file:/etc/ssl/certs/ca.crt"

# Or use classpath (must be in resources/)
spring:
  ssl:
    bundle:
      pem:
        server:
          keystore:
            certificate: "classpath:ssl/server.crt"
            private-key: "classpath:ssl/server.key"

# Enable SSL on server
server:
  port: 8443
  ssl:
    enabled: true
    bundle: server
// Verify SSL configuration at startup
@Component
public class SslConfigurationValidator {

    @Value("${server.ssl.enabled:false}")
    private boolean sslEnabled;

    @Value("${server.ssl.bundle:}")
    private String sslBundle;

    @PostConstruct
    public void validate() {
        if (sslEnabled && sslBundle.isEmpty()) {
            throw new IllegalStateException(
                "SSL enabled but no bundle configured. Set server.ssl.bundle"
            );
        }
    }
}

Rationale: SSL bundle configuration requires correct resource prefix (file: or classpath:) and valid certificate files. Without proper configuration, server fails to start with cryptic SSL errors. Always validate SSL configuration at startup.

9. Not Handling Failed Application Start

Problem: Application fails silently or with unhelpful error messages

Error: Startup fails but root cause is buried in stack trace

Solution:

@Component
public class StartupFailureHandler {

    @EventListener
    public void onApplicationFailed(ApplicationFailedEvent event) {
        Throwable exception = event.getException();

        System.err.println("=================================");
        System.err.println("APPLICATION FAILED TO START");
        System.err.println("=================================");
        System.err.println("Reason: " + exception.getMessage());
        System.err.println("Exception type: " + exception.getClass().getName());

        // Log specific failure types
        if (exception instanceof BeanCreationException) {
            System.err.println("Bean creation failed - check configuration and dependencies");
        } else if (exception instanceof BindException) {
            System.err.println("Configuration binding failed - check properties");
        } else if (exception instanceof DataAccessException) {
            System.err.println("Database connection failed - check database configuration");
        }

        System.err.println("\nFull stack trace:");
        exception.printStackTrace();

        // Optionally send alerts
        sendStartupFailureAlert(exception);
    }

    private void sendStartupFailureAlert(Throwable exception) {
        // Send to monitoring system, Slack, PagerDuty, etc.
    }
}

Rationale: Default Spring Boot error messages can be difficult to diagnose. Listening to ApplicationFailedEvent allows custom error handling, better logging, and alerting. Essential for production troubleshooting.

10. Property Precedence Confusion

Problem: Properties from wrong source taking effect

Error: Expected property value not being used

Solution:

// Understand property source precedence (highest to lowest):
// 1. Command line arguments
// 2. SPRING_APPLICATION_JSON properties
// 3. ServletConfig init parameters
// 4. ServletContext init parameters
// 5. JNDI attributes from java:comp/env
// 6. Java System properties (System.getProperties())
// 7. OS environment variables
// 8. Profile-specific application properties (application-{profile}.properties)
// 9. Application properties (application.properties)
// 10. @PropertySource annotations
// 11. Default properties (SpringApplication.setDefaultProperties)

// Example: Debug property sources
@Component
public class PropertySourceDebugger {

    private final ConfigurableEnvironment environment;

    public PropertySourceDebugger(ConfigurableEnvironment environment) {
        this.environment = environment;
    }

    @EventListener(ApplicationReadyEvent.class)
    public void debugPropertySources() {
        String propertyKey = "app.database.url";
        String value = environment.getProperty(propertyKey);

        System.out.println("\n=== Property Source Debug ===");
        System.out.println("Property: " + propertyKey);
        System.out.println("Final value: " + value);
        System.out.println("\nProperty sources (in precedence order):");

        environment.getPropertySources().forEach(source -> {
            if (source instanceof EnumerablePropertySource) {
                EnumerablePropertySource<?> enumerable = (EnumerablePropertySource<?>) source;
                for (String name : enumerable.getPropertyNames()) {
                    if (name.equals(propertyKey)) {
                        System.out.println("  " + source.getName() + ": " +
                            enumerable.getProperty(name));
                    }
                }
            }
        });
    }
}
# Override in specific environments
# application.properties (default)
app.database.url=jdbc:postgresql://localhost:5432/devdb

# application-prod.properties (production override)
app.database.url=jdbc:postgresql://prod-db:5432/proddb

# Can also override via environment variable
# APP_DATABASE_URL=jdbc:postgresql://override-db:5432/db

# Or command line (highest precedence)
# java -jar app.jar --app.database.url=jdbc:postgresql://cmdline-db:5432/db

Rationale: Spring Boot has complex property precedence rules. Properties can be overridden from multiple sources, leading to unexpected values. Use environment-specific property files and understand precedence order to avoid conflicts.

Import Statements

// Core application
import org.springframework.boot.SpringApplication;
import org.springframework.boot.SpringApplicationRunListener;
import org.springframework.boot.autoconfigure.SpringBootApplication;

// Configuration
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.context.config.*;

// Lifecycle
import org.springframework.boot.context.event.*;
import org.springframework.boot.ApplicationRunner;
import org.springframework.boot.CommandLineRunner;

// Availability
import org.springframework.boot.availability.*;

// Logging
import org.springframework.boot.logging.*;

// SSL/TLS
import org.springframework.boot.ssl.*;

// JSON
import org.springframework.boot.json.*;

// Info
import org.springframework.boot.info.*;

// Cloud
import org.springframework.boot.cloud.*;

// Conversion
import org.springframework.boot.convert.*;

// Diagnostics
import org.springframework.boot.diagnostics.*;

// System
import org.springframework.boot.system.*;

// Task execution
import org.springframework.boot.task.*;

// Web
import org.springframework.boot.web.server.*;
import org.springframework.boot.web.servlet.*;
import org.springframework.boot.web.error.*;

Key Characteristics

Thread Safety

  • All core services (ApplicationConversionService, SslBundles, etc.) are thread-safe
  • Events can be published from any thread
  • Configuration properties are immutable after binding

Lifecycle Guarantees

  • Events are published in guaranteed order during startup and shutdown
  • ApplicationReadyEvent signals the application is fully initialized
  • ContextClosedEvent signals the start of shutdown

Extension Points

  • EnvironmentPostProcessor: Customize environment before context refresh
  • ApplicationContextInitializer: Customize context before refresh
  • FailureAnalyzer: Provide custom failure analysis (via spring.factories)
  • ConfigDataLoader/ConfigDataLocationResolver: Load custom configuration formats
  • WebServerFactoryCustomizer: Customize embedded web server

Production Features

  • Graceful shutdown support for web servers
  • Startup performance metrics with nanosecond precision
  • JMX-based remote administration
  • SSL certificate hot-reloading
  • Comprehensive failure analysis and diagnostics

Related Documentation

  • Spring Framework: For core Spring features (dependency injection, AOP, transactions)
  • Spring Boot Autoconfigure: For auto-configuration of common libraries
  • Spring Boot Actuator: For production-ready monitoring and management endpoints

Version Information

  • Current version: 4.0.0
  • Minimum Java: 17
  • Java 21+ features: Virtual threads, improved process information
  • Breaking changes from 3.x: Web server factory API refactored for improved configurability