Call
Home>Blogs & Insights>Spring Boot Explained: Auto-Configuration, Starters, Dependency Injection, Actuator, and Production Basics
Spring Boot

Spring Boot Explained: Auto-Configuration, Starters, Dependency Injection, Actuator, and Production Basics

Understand modern Spring Boot through auto-configuration, starters, dependency injection, embedded servers, externalized configuration, transactions, Spring Security, Actuator, observability, testing, graceful shutdown, native images, and current Spring Boot 4.1.1 requirements.

June 30, 2024
12 min read
0 views
Lofingo Team
Spring Boot Explained: Auto-Configuration, Starters, Dependency Injection, Actuator, and Production Basics

Spring Boot Explained: Auto-Configuration, Starters, Dependency Injection, Actuator, and Production Basics

Spring Boot is the opinionated application layer around the broader Spring ecosystem. It helps Java developers build stand-alone Spring applications with sensible defaults, dependency management, embedded servers, externalized configuration, health/metrics tooling, and production-friendly packaging.

The important idea is not “Spring Boot removes configuration.” It is:

Spring Boot supplies conditional defaults that get out of the way when your application defines something more specific.

As of September 2026, the current stable Spring Boot release is 4.1.1. It requires Java 17 or newer and is compatible with Java releases through 26 according to the current official system requirements.

Spring vs Spring Boot

Spring Framework provides the core programming model:

  • dependency injection / inversion of control
  • application context
  • web MVC and reactive web support
  • transactions
  • data integration
  • validation
  • security integration
  • eventing and many infrastructure abstractions

Spring Boot sits on top and makes common application setup predictable.

Without Boot, a Spring application can still be built. Boot mainly reduces repeated integration/configuration work and standardizes how applications are started and operated.

A Spring Boot application starts from one main configuration class

A typical application looks like:

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

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

@SpringBootApplication combines several common behaviors, including Spring configuration, component scanning, and auto-configuration enablement.

Spring's current documentation recommends using one primary @SpringBootApplication or @EnableAutoConfiguration entry point.

Auto-configuration is conditional, not magic

Spring Boot examines things such as:

  • classes on the classpath
  • existing beans
  • configuration properties
  • application type

and applies matching configuration.

For example, if the expected database libraries are present and your application has not supplied its own DataSource, Boot may configure a suitable data source from application properties.

If you define your own bean, many auto-configurations back off through conditions such as:

ConditionalOnClass
ConditionalOnMissingBean
ConditionalOnProperty

That is why Spring Boot can be opinionated without permanently locking you into its defaults.

Use the conditions report when auto-configuration surprises you

One of the worst ways to debug Spring Boot is guessing why a bean exists.

Boot can expose a condition evaluation report that explains which auto-configurations matched or did not match.

Starting an application with debug auto-configuration logging can reveal:

configuration X matched because class Y exists
configuration Z did not match because bean A already exists

Learn this early. It turns “Spring magic” into inspectable conditions.

Starters package a useful dependency set

A starter is a dependency that pulls together libraries normally needed for one capability.

Examples include starters for:

  • web applications
  • validation
  • security
  • data access
  • messaging
  • Actuator

The value is not only fewer dependency lines. Spring Boot also manages compatible versions through its dependency-management model.

This reduces the chance that every application chooses unrelated versions of Spring libraries and supporting components.

Do not override managed dependency versions casually

Spring Boot publishes a curated dependency set.

You can override versions when a real requirement exists, but doing it casually can produce compatibility combinations the Boot release was not tested against.

Prefer:

choose supported Boot version
use its managed dependency versions
override only deliberately

For security fixes, check whether a newer supported Spring Boot patch release already updates the relevant dependency before forcing one library independently.

Dependency injection is still the core Spring model

Spring creates and wires application objects called beans.

Prefer constructor injection:

@Service
public class OrderService {
    private final OrderRepository orders;

    public OrderService(OrderRepository orders) {
        this.orders = orders;
    }
}

Constructor injection makes required dependencies explicit and makes the class easy to instantiate in tests.

Avoid hiding required dependencies in mutable global state or field injection unless there is a specific framework constraint.

Keep application boundaries clear even though Spring can inject anything

A large Spring application can become tightly coupled if every component injects arbitrary repositories, clients, and services from every package.

Use architectural boundaries such as:

controller / HTTP adapter
application service
business/domain logic
persistence adapter
external clients

The exact folder structure is less important than keeping responsibilities clear.

Spring's dependency injection should reduce wiring boilerplate, not encourage one giant object graph with no ownership boundaries.

Controllers should translate HTTP, not own every business rule

A controller can remain thin:

@RestController
@RequestMapping("/orders")
public class OrderController {
    private final OrderService orders;

    public OrderController(OrderService orders) {
        this.orders = orders;
    }

    @GetMapping("/{id}")
    public OrderResponse get(@PathVariable String id) {
        return orders.get(id);
    }
}

The controller should mainly:

  • parse HTTP input
  • validate request shape
  • establish authenticated context
  • invoke an application operation
  • map result/errors to HTTP

Database transactions, pricing rules, order state transitions, and cross-resource authorization should not be duplicated independently across controllers.

Externalized configuration is a core Boot feature

Spring Boot can read configuration from multiple sources such as:

  • properties/YAML files
  • environment variables
  • command-line arguments
  • system properties
  • external configuration providers integrated by your platform

Use this for environment-specific settings:

database URL
server port
feature flags
provider endpoints
timeouts

Do not store passwords, signing keys, or production credentials in committed application.yml files.

Use a secret-management mechanism and inject secret values at runtime.

Prefer typed configuration properties

Instead of reading random string property names throughout the application, bind related settings into a typed configuration object.

Conceptually:

payments.timeout
payments.base-url
payments.max-retries

becomes one validated PaymentsProperties object.

Typed configuration improves:

  • discoverability
  • IDE assistance
  • validation
  • testing
  • refactoring

Fail fast during startup when required configuration is invalid rather than discovering it on the first customer request.

Profiles are useful, but do not turn them into a second programming language

Spring profiles can activate selected beans/configuration for environments or features.

Use them sparingly for meaningful environment differences.

Avoid a configuration maze such as:

prod + region-a + premium + new-auth + migration-mode

where developers can no longer predict which beans exist.

Prefer explicit configuration properties or feature flags for runtime product behavior.

Embedded servers simplify deployment

Spring Boot applications can run as executable JARs with embedded servlet containers.

Typical deployment becomes:

java -jar application.jar

Current Spring Boot 4.1.1 documentation supports embedded servlet options including Tomcat 11 and Jetty 12.1.

Boot also supports traditional deployments where needed, but executable application packaging is one reason Spring Boot fits containers and ordinary service deployments well.

Servlet MVC vs reactive WebFlux are different programming models

Spring Boot supports both traditional Spring MVC and reactive WebFlux stacks.

Do not choose reactive programming merely because it sounds more scalable.

Spring MVC is an excellent default for many database-backed services.

WebFlux becomes useful when the whole request path benefits from non-blocking/reactive I/O and compatible libraries.

Putting blocking JDBC or other blocking work inside an event-loop-oriented reactive path can erase the expected benefit and create hard-to-debug saturation.

Choose the model from workload and dependencies.

Database access still needs normal database engineering

Spring Data can make repositories concise, but an ORM/repository abstraction does not remove the need to understand:

  • indexes
  • query plans
  • transaction isolation
  • connection pools
  • lock contention
  • N+1 query behavior
  • pagination
  • migrations

A repository method that looks like one Java call can still execute an expensive SQL query.

Measure the database, not only the Java code.

Use explicit transaction boundaries

Spring supports declarative transactions through @Transactional.

Use transactions around one business invariant:

create order
create order items
reserve local inventory state
write outbox event

Avoid holding a database transaction open while performing slow remote calls.

Also remember proxy semantics: transaction annotations are applied through Spring's interception model. Self-invocation and object construction outside the Spring context can surprise developers if they assume the annotation is magic syntax.

Understand connection pooling

Database connections are limited resources.

Spring Boot configures common connection-pool integrations, but the correct pool size depends on the database, workload, and concurrency.

A larger pool is not always faster.

Too many active database connections can increase:

  • lock contention
  • memory
  • context switching
  • query queueing inside the database

Size application concurrency and connection pools together.

Validation belongs at the API boundary and domain boundary

Spring integrates Jakarta Bean Validation for request DTO validation.

Useful request constraints include:

  • required values
  • string length
  • numeric ranges
  • structured formats
  • collection size

Then validate business rules separately:

customer owns address
order may transition from pending to cancelled
inventory is sufficient

Schema validation cannot express every business invariant.

Security is not automatic because Spring Security is installed

Spring Security provides a strong framework for:

  • authentication
  • authorization
  • CSRF protection
  • session security
  • method/request policies
  • OAuth2/OIDC integrations

But the application still needs correct policy design.

For multi-tenant/resource APIs, always ask:

Can this authenticated user access this specific tenant/resource/action?

A logged-in session is not authorization to every object ID.

Actuator provides production management features

Spring Boot Actuator is the standard production-management module.

Current Spring Boot documentation describes Actuator as the place for production-ready features and provides endpoints/integrations for concerns such as:

  • health
  • metrics
  • environment/configuration diagnostics
  • loggers
  • application information
  • thread/heap diagnostics depending on setup

Add the Actuator starter when those features are required rather than implementing separate custom health and metrics frameworks from scratch.

Do not expose every Actuator endpoint publicly

Management endpoints can reveal sensitive operational information.

Expose only what is needed, and secure management access appropriately.

Common public-facing health behavior may be intentionally minimal while deeper diagnostics remain restricted to trusted operators.

Do not expose environment/configuration endpoints containing secret values to the internet.

Health checks should distinguish liveness and readiness

In orchestrated environments, two questions matter:

Liveness

Is this process stuck and should it be restarted?

Readiness

Should new traffic be sent to this instance right now?

A database outage should not always cause the process to be killed repeatedly. Often it should make the instance temporarily unready while preserving useful diagnostics and allowing recovery.

Design health groups according to your deployment platform rather than one generic /health response for every purpose.

Metrics should describe operations, not customer IDs

Spring Boot integrates with Micrometer for application metrics.

Useful tags/dimensions include:

HTTP route template
status
method
service
instance/region where appropriate

Avoid high-cardinality labels such as:

user ID
order ID
raw URL
exception message

Those can make monitoring systems expensive and may leak sensitive data.

Distributed tracing needs context propagation

For a service chain:

API
  order service
  inventory service
  payment service

propagate trace context so one request can be followed through dependencies.

Spring Boot's observability integrations can work with Micrometer/OpenTelemetry-compatible tracing setups depending on your stack.

Instrument meaningful boundaries such as HTTP, database, messaging, and RPC calls rather than creating spans for every trivial helper method.

Graceful shutdown matters in deployments

During a rolling deployment, instances should stop taking new work and let bounded in-flight requests finish where possible.

Otherwise each release can create unnecessary connection resets and failed requests.

Pair server graceful shutdown with:

  • load-balancer draining
  • readiness changes
  • maximum termination grace period
  • idempotent client retry behavior

No server should wait forever for one stuck request.

Use integration tests for framework wiring

Unit tests are excellent for business logic.

Spring Boot integration tests are useful when you need to verify:

  • application context wiring
  • security filters
  • controller serialization
  • transaction/repository behavior
  • configuration properties

Do not start the entire application context for every tiny pure function test. Boot context startup has a cost.

Use focused test slices and ordinary unit tests where they give faster, clearer feedback.

Test against real infrastructure semantics where correctness depends on them

An in-memory database may behave differently from PostgreSQL/MySQL in:

  • SQL syntax
  • locking
  • isolation
  • indexes
  • constraints

For database-sensitive code, run integration tests against the actual supported database engine, often through disposable test containers or CI services.

Mocks are useful for boundaries. They should not pretend to validate behavior they do not implement.

Spring Boot 4 is a real platform upgrade

Current Spring Boot 4.1.1 runs on Spring Framework 7 and requires at least Java 17.

Boot 4 also aligns with newer servlet/platform generations and supports current build/runtime tooling.

When upgrading from older Boot generations, review migration notes carefully instead of changing the version and fixing compiler errors only.

Major upgrades can affect:

  • dependencies
  • removed/deprecated configuration
  • Jakarta APIs
  • observability/security integrations
  • testing APIs
  • third-party starters

Use staged compatibility testing for production applications.

Native images are an option, not the default answer

Current Spring Boot supports GraalVM native-image builds.

Native images can improve startup time and reduce some runtime footprint characteristics, which can be useful for selected serverless/CLI/scale-to-zero workloads.

Trade-offs can include:

  • longer/more complex build process
  • different reflection/dynamic behavior constraints
  • library compatibility considerations
  • profiling/debugging differences

Benchmark your actual workload before replacing a normal JVM deployment.

The JVM remains an excellent production runtime for many long-running backend services.

A practical Spring Boot project boundary

A maintainable service might separate code conceptually as:

web
  controllers
  request/response DTOs

application
  use cases/services

domain
  business types and rules

persistence
  repositories/queries

integration
  HTTP/gRPC/message clients

config
  Spring wiring and typed properties

Do not copy this structure mechanically. The principle is to keep transport, business rules, persistence, and integrations separable enough to test and evolve.

Spring Boot production checklist

Before shipping a Spring Boot service, verify:

  • the Boot version is supported and patched
  • Java/runtime version is supported
  • auto-configuration is understood rather than blindly accepted
  • configuration is typed and validated
  • secrets are externalized
  • controllers remain thin
  • transaction boundaries are deliberate
  • database pools/queries are capacity-tested
  • resource-level authorization is tested
  • Actuator endpoints are exposed minimally and secured
  • readiness and liveness semantics are correct
  • metrics avoid high-cardinality tags
  • trace context crosses dependencies
  • graceful shutdown/draining works
  • integration tests cover real framework/database behavior
  • major upgrades follow official migration notes

Spring Boot is most valuable when teams use its conventions to remove repeated infrastructure work while keeping business boundaries, database behavior, security, and failure semantics explicit. The framework should make a service easier to operate—not hide how the service works.

Official references

Tags:Spring BootJavaSpring FrameworkBackend DevelopmentActuatorEnterprise Java
Lofingo Team
Written by

Lofingo Team

Official writer and content strategist at Lofingo. Dedicated to delivering high-quality insights on technology and market trends.

Share your thoughts:

Discussion (0)

No comments yet. Be the first to start the discussion!