Spring Boot Fundamentals - Complete Notes
A practical and interview-focused guide to Spring Boot project structure, starters, auto-configuration, dependency management, startup, external configuration, profiles, embedded servers, executable archives, DevTools, diagnostics, and production-ready foundations.
00. The Spring Boot mental model
Spring Boot is an opinionated application bootstrap layer on top of the Spring Framework. It chooses sensible defaults from the classpath and configuration, then backs away when the application supplies an explicit choice.
Spring Framework provides the IoC container, dependency injection, web framework, transactions, data access, testing, and integration foundations. Spring Boot makes those pieces faster to assemble into a runnable application. It manages compatible dependency versions, provides starter dependency groups, applies conditional auto-configuration, embeds common servers, and adds operational features.
Spring Framework is a professional workshop full of tools. Spring Boot is a prepared workstation where the commonly needed tools are compatible, connected, and placed within reach. You can replace a tool or rearrange the station, but you do not spend the first day building the bench.
| Spring Framework | Spring Boot |
|---|---|
| Core programming and infrastructure model | Opinionated application assembly |
| IoC, MVC, transactions, data access, testing | Starters, dependency management, auto-configuration |
| Can be configured in many ways | Chooses strong defaults while remaining configurable |
| Does not require Spring Boot | Builds on Spring Framework |
Your application still uses normal Java and Spring bean definitions. Auto-configuration is ordinary conditional configuration supplied by libraries. You can inspect, override, or exclude it.
01. Creating and structuring a project
Start with the smallest dependency set that supports the application. Every starter expands the classpath and can activate configuration.
Spring Initializr generates a Maven or Gradle project with selected dependencies, Java version, packaging, coordinates, and a main class. It is a project generator, not a runtime requirement. Review the generated build instead of treating it as hidden magic.
com.example.orders
├── OrdersApplication.java
├── order
│ ├── Order.java
│ ├── OrderService.java
│ └── OrderRepository.java
├── checkout
│ ├── CheckoutController.java
│ └── CheckoutService.java
└── infrastructure
└── payment
└── StripePaymentGateway.java
Put the application class in a root package. The default component scan and several auto-configuration package conventions begin there and include subpackages. Avoid the Java default package because scanning becomes broad and tool behavior becomes surprising.
Package by feature or layer?
Package-by-feature keeps related controller, service, model, and persistence code together and
gives modules a clearer boundary. Package-by-layer can be understandable in a small application,
but large global controller, service, and repository
packages often create weak cohesion.
02. @SpringBootApplication
The main annotation combines configuration, component scanning, and auto-configuration.
@SpringBootApplication
public class OrdersApplication {
public static void main(String[] args) {
SpringApplication.run(OrdersApplication.class, args);
}
}
@SpringBootApplication combines the intent of @SpringBootConfiguration,
@EnableAutoConfiguration, and @ComponentScan. Keep one primary
application annotation in normal applications. Multiple application roots can produce overlapping
scans and confusing tests.
It bootstraps discovery. Clear feature boundaries, dependency direction, and focused configuration still come from application design.
03. What SpringApplication.run does
SpringApplication prepares the environment, creates the correct context, loads
configuration, refreshes the context, and runs startup callbacks.
- Build a
SpringApplicationfrom primary source classes. - Determine the application type from the classpath, such as servlet, reactive, or non-web.
- Prepare bootstrap listeners and initializers.
- Create and populate the Spring
Environment. - Print the banner unless disabled.
- Create the appropriate
ApplicationContext. - Load bean definitions, including application and auto-configuration classes.
- Refresh the context, which creates eager singletons and starts infrastructure.
- Publish lifecycle events and call runners.
- Return the running application context.
public static void main(String[] args) {
SpringApplication app = new SpringApplication(OrdersApplication.class);
app.setBannerMode(Banner.Mode.OFF);
app.setDefaultProperties(Map.of("server.port", "8081"));
app.run(args);
}
Prefer declarative configuration for deploy-time values. Programmatic defaults are useful for library-owned or bootstrap settings but are harder for operators to discover and override.
04. Starter dependencies
A starter is a dependency descriptor that brings together a supported set of libraries for a capability.
| Starter | Typical capability |
|---|---|
spring-boot-starter |
Core Boot, logging, and configuration foundation |
spring-boot-starter-web |
Servlet web application, Spring MVC, JSON, embedded server |
spring-boot-starter-validation |
Jakarta Bean Validation implementation |
spring-boot-starter-data-jpa |
Spring Data JPA and Hibernate integration |
spring-boot-starter-security |
Spring Security foundation |
spring-boot-starter-actuator |
Operational endpoints and production observations |
spring-boot-starter-test |
Spring testing, JUnit, assertions, and common test tools |
A starter usually contains little or no implementation code. Removing it does not necessarily remove the feature if equivalent dependencies remain. Conversely, adding a starter does not guarantee a working integration when required properties or external services are missing.
05. Dependency management
Spring Boot publishes a tested dependency version set so related libraries work together.
Maven projects commonly inherit from spring-boot-starter-parent or import the Boot
dependency-management BOM. Gradle projects use the Boot plugin and supported dependency-management
mechanisms. Managed dependencies normally omit individual version numbers.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
A forced version may be binary-incompatible with Spring Framework, Jackson, Hibernate, logging, or a servlet container. Override only for a verified need, test the full application, and remove the override after moving to a supported Boot release.
06. Auto-configuration
Auto-configuration evaluates evidence and contributes beans only when its conditions match.
Important evidence includes classes on the classpath, existing or missing beans, properties, web
application type, resources, and parent configuration. For example, database configuration can
activate when JDBC classes and suitable properties exist, while backing away when the application
declares its own DataSource.
| Condition | Question |
|---|---|
@ConditionalOnClass |
Is a required library on the classpath? |
@ConditionalOnMissingBean |
Has the application already supplied this capability? |
@ConditionalOnProperty |
Does configuration enable or customize this feature? |
@ConditionalOnWebApplication |
Is this the correct kind of web application? |
@ConditionalOnResource |
Is a required resource present? |
The back-off principle
Auto-configuration is non-invasive: when an application defines a bean that represents the same choice, conditional configuration normally backs off. This is how sensible defaults coexist with explicit control.
Diagnosing decisions
Start with --debug or inspect the conditions evaluation report. A negative match is
not automatically an error. It explains why a configuration path did not apply. Search for the
capability you expected, then inspect its positive and negative conditions.
@SpringBootApplication(
exclude = DataSourceAutoConfiguration.class
)
public class BatchApplication { /* ... */ }
Exclusion is a precise escape hatch. Do not exclude configuration merely because startup reports a missing database if the application actually needs a database. Supply correct properties or dependencies instead.
07. Externalized configuration
The same application artifact should run in different environments by receiving different configuration.
Spring Boot can read properties and YAML files, environment variables, Java system properties, command-line arguments, imported configuration, test properties, and other property sources. Higher-precedence sources can override lower-precedence defaults.
Package safe defaults with the application. Supply environment-specific values outside the archive. Use command-line or platform overrides for the final deployment. Keep secrets in a secret manager or protected environment source, never in Git.
server:
port: 8080
orders:
payment:
base-url: https://payments.example
connect-timeout: 2s
ORDERS_PAYMENT_BASEURL=https://payments.prod.example
java -jar orders.jar \
--server.port=9090 \
--orders.payment.connect-timeout=1s
Relaxed binding maps common property-name styles to Java property names. Environment variable conversion generally replaces dots with underscores, removes dashes, and uses uppercase. Verify exact binding rules for lists and maps instead of inventing names.
08. Type-safe configuration properties
Group related settings into a validated type instead of scattering string keys across beans.
@ConfigurationProperties("orders.payment")
@Validated
public record PaymentProperties(
@NotNull URI baseUrl,
@NotNull Duration connectTimeout,
@Min(1) int maxAttempts
) {}
@SpringBootApplication
@ConfigurationPropertiesScan
public class OrdersApplication { /* ... */ }
Structured properties support conversion, metadata, validation, IDE completion, and a clear
configuration contract. Use @Value for a small isolated value or expression, not as
the main configuration model of a module.
A missing endpoint, impossible timeout, or invalid pool size should stop deployment before the first request. Silent defaults for security or money-related behavior are especially dangerous.
09. Profiles
Profiles activate selected beans or configuration documents for an environment or mode.
# application-prod.yaml
orders:
payment:
base-url: https://payments.prod.example
Activating prod considers base configuration and profile-specific configuration, with
profile-specific values overriding base values according to location and property-source rules. If
several profiles are active, later profiles can override earlier ones.
- Use profiles for coarse environment or feature modes.
- Use ordinary properties for values such as URLs, limits, and timeouts.
- Do not create a different build artifact for every environment.
- Do not hide dozens of independent feature flags inside one profile name.
- Log active profiles and validate environment-critical settings.
10. Embedded web servers
A web starter can run the server inside the application process, so the application starts as a normal Java process.
Servlet applications commonly use an embedded Tomcat server by default, with supported
alternatives available. Spring Boot creates and starts the server during context refresh. The
application can be packaged as an executable JAR and started with java -jar.
server:
port: 8080
shutdown: graceful
servlet:
context-path: /orders
A context path affects every endpoint and often complicates reverse-proxy routing and health checks. Prefer clear gateway routing unless the deployment contract requires a shared container path.
Executable JAR versus WAR
| Packaging | Deployment model | Strong default |
|---|---|---|
| Executable JAR | Application owns embedded server | Containers, services, and most new applications |
| WAR | External servlet container owns deployment | Existing organization-managed application servers |
11. Startup runners
ApplicationRunner and CommandLineRunner execute after the context has
started.
@Bean
ApplicationRunner verifyCatalog(ProductRepository products) {
return args -> {
if (products.count() == 0) {
throw new IllegalStateException("Product catalog is empty");
}
};
}
ApplicationRunner provides parsed option arguments.
CommandLineRunner receives the raw string array. Order multiple runners deliberately.
Do not run unbounded migrations, long imports, or non-idempotent remote calls during every
application startup.
12. Startup lifecycle and events
Boot publishes events around environment preparation, context creation, context refresh, runner execution, readiness, and failure.
Very early events occur before the context exists, so their listeners cannot be ordinary beans. Normal application behavior should usually react after the context is ready. Use readiness as an operational signal, not as permission to start arbitrary background work without lifecycle control.
Startup validation proves a point in time. Runtime resilience still needs timeouts, bounded retries, circuit breaking where appropriate, health observations, and clear failure behavior.
13. Logging fundamentals
Boot provides a logging abstraction and a supported default implementation through its starters.
logging:
level:
root: INFO
com.example.orders: DEBUG
pattern:
correlation: "[%X{traceId:-}]"
Log events with stable fields and enough context to act. Do not log secrets, access tokens, passwords, full payment data, or unbounded request bodies. A debug level that is safe locally may be expensive or sensitive in production.
14. DevTools
Spring Boot DevTools improves local feedback with restart and development-time defaults.
Restart uses classloader separation so application classes can reload faster than third-party libraries. It is not the same as production hot deployment. Mark DevTools as a development-only dependency and do not rely on its defaults in production.
Static caches, serialization, service loading, and libraries that retain application classes can behave differently across restart classloaders. Reproduce suspicious failures with restart disabled before blaming business logic.
15. Executable archives and container images
The Boot build plugins can repackage an application and its dependencies into an executable archive.
./mvnw clean verify
java -jar target/orders-1.0.0.jar
./gradlew clean bootJar
java -jar build/libs/orders-1.0.0.jar
Reproducible deployment means the artifact tested in CI is the artifact promoted to production. Inject environment configuration at runtime. Do not rebuild the JAR merely to change a URL.
Build plugins can also create OCI images using buildpacks. Container concerns still include non-root execution, memory limits, graceful shutdown, immutable images, vulnerability scanning, and a supported Java runtime.
16. AOT processing and native images
Ahead-of-time processing can analyze configuration and prepare runtime hints, including support for GraalVM native images.
Native images can improve startup time and memory footprint, but they change build complexity and closed-world assumptions around reflection, resources, serialization, and dynamic proxies. Measure the deployment need before accepting the tradeoff. Standard JVM deployment remains a strong default.
17. Failure analysis and debugging
| Symptom | Likely area | First diagnostic |
|---|---|---|
| Port already in use | Embedded server binding | Find the process or configure a different port |
| Bean missing | Scan, profile, condition, or dependency | Read the nested cause and condition report |
| Property failed to bind | Name, type conversion, or validation | Compare property prefix and target structure |
| Unexpected auto-configured bean | Classpath activated a condition | Inspect positive condition matches |
| Method or class not found | Dependency version conflict | Inspect the resolved dependency tree |
| Application exits immediately | Non-web type or no non-daemon work | Check starters and detected application type |
Read the deepest relevant cause, not only the top-level
ApplicationContextException. Boot failure analyzers often add an action section. Fix
the first causal configuration problem before reacting to downstream bean failures.
18. Production baseline
- Pin a supported Spring Boot line and let its dependency management control the platform.
- Use the smallest starter set and inspect the resolved dependency tree.
- Externalize environment values and keep secrets out of source control.
- Bind related settings to validated
@ConfigurationPropertiestypes. - Enable graceful shutdown and define platform termination timeouts.
- Add Actuator and expose only intentionally secured operational endpoints.
- Use health, metrics, structured logs, and correlation identifiers.
- Set network timeouts and bounded resource pools explicitly.
- Build once, test the artifact, scan it, and promote the same artifact.
- Review release notes and migration guides before framework upgrades.
19. Common mistakes
| Mistake | Consequence | Better approach |
|---|---|---|
| Adding many starters "just in case" | Larger attack surface and unexpected auto-configuration | Add dependencies for known capabilities |
| Forcing arbitrary library versions | Runtime linkage failures | Use Boot's managed set |
| Putting the main class in a nested package | Expected components are not scanned | Use a deliberate root package |
Scattering @Value strings |
No clear configuration contract | Use validated property types |
| Committing production secrets | Credential exposure and difficult rotation | Use protected runtime secret sources |
| Using profiles for every switch | Combinatorial environment behavior | Use typed properties and focused conditions |
| Excluding auto-configuration blindly | Required infrastructure silently disappears | Read the condition report and fix the cause |
20. Interview questions and answers
What problem does Spring Boot solve?
It reduces application setup and integration work through starters, managed dependency versions, conditional auto-configuration, embedded servers, executable packaging, externalized configuration, and production-oriented features.
What does @SpringBootApplication contain?
It represents Boot configuration, enables auto-configuration, and enables component scanning from its package. It is normally placed on the primary application class.
How does auto-configuration work?
Boot loads candidate configuration classes and evaluates conditions based on the classpath, beans, properties, resources, and application type. Matching configurations contribute beans. Missing-bean conditions let explicit application configuration replace defaults.
What is the difference between a starter and auto-configuration?
A starter groups dependencies. Auto-configuration contains conditional bean configuration. A starter often places the classes on the classpath that make an auto-configuration eligible, but they are separate concepts.
How do you find why auto-configuration did not apply?
Enable debug output or inspect the conditions evaluation report, find the expected configuration, and read its matched and unmatched conditions.
Why omit dependency versions in many Boot projects?
The Boot BOM manages a compatible, tested version set. Omitting individual versions lets that platform control them. Application-specific libraries outside the managed set still need explicit versions.
How are configuration values overridden?
Boot combines ordered property sources. Later or higher-precedence sources, such as selected runtime overrides, can replace packaged defaults. Exact precedence depends on source type and config-data location.
Why use @ConfigurationProperties instead of @Value?
It provides grouped type-safe binding, conversion, validation, metadata, and a visible
configuration contract. @Value remains useful for isolated values and expressions.
Does an executable JAR require an external Tomcat installation?
No. A typical servlet starter includes a supported embedded server, and the Boot archive starts it inside the application process. WAR deployment to an external container remains possible.
What happens if you define your own DataSource bean?
Relevant auto-configuration normally backs off because its missing-bean condition no longer matches. The application becomes responsible for correctly configuring that bean.
21. Practice exercises
- Generate a minimal web project and explain every direct dependency.
- Run with
--debugand locate three positive and three negative conditions. - Replace one auto-configured bean with an explicit bean and prove the back-off behavior.
- Bind and validate a nested property record containing a URI, duration, and list.
- Override one property using a file, environment variable, and command-line argument.
- Create local and production profile documents without changing the built JAR.
- Package an executable JAR and inspect its dependency layout.
- Diagnose an intentional dependency-version conflict using the dependency tree.
22. One-screen cheat sheet
- Spring Framework supplies the foundation; Boot supplies opinionated assembly.
- A starter groups dependencies; auto-configuration conditionally supplies beans.
@SpringBootApplicationmarks the primary configuration and scan root.- Auto-configuration backs off when the application supplies an explicit bean.
- Use the condition report to explain configuration decisions.
- Let Boot manage compatible dependency versions.
- Externalize deploy-time configuration and protect secrets.
- Use validated
@ConfigurationPropertiesfor related settings. - Profiles select coarse modes; properties carry normal values.
- Executable JARs commonly own an embedded server.
- Build once and promote the same tested artifact.