Introduction to Spring Boot
Why Spring Boot exists, Spring vs Spring Boot, the core Spring concepts, scaffolding a project with the Spring Initializr (start.spring.io), and writing your first Hello World controller.
After this you should be able to
- Explain what Spring Boot automates
- Create a starter application
Java · Spring Boot
Why the framework that runs most of the Java web exists, what it fixed about the Spring it grew out of, and how you get from an empty folder to a running web endpoint in one afternoon.
Choose your route#
Problem: a useful Java service should start with a small, runnable shape instead of a day of wiring. This is a lesson: budget 30 minutes to build it deeply or 12 minutes to revise it for interviews.
Recall first: before reading, name the four pieces Boot supplies around a controller. Prerequisite guidance: be comfortable reading an HTTP request; you may still continue now.
- Explain what Spring Boot automates.
- Create a starter application.
- Run and diagnose a first endpoint.
Shared core: a runnable web application#
Boot combines Spring’s container with opinionated dependency management, auto-configuration, and an embedded server. A starter describes a capability; Boot uses the classpath and properties to assemble a sensible default, while leaving the decision reversible.
Do not blur Spring and Spring Boot: Spring is the underlying framework and programming model; Boot is the convention-led layer that chooses common setup so you can begin quickly.
Failure trace: returning "OK" from @Controller looks like a response but is treated as a view name. Use @RestController (or @ResponseBody) when the value is the HTTP body.
Decision rule: start with a Boot starter and the embedded server for a new service; override configuration only when the default conflicts with a real constraint.
Version note: examples are reviewed against Spring Boot 4.x on 2026-08-28. Confirm migration notes before copying API details into a production upgrade.
Learn deeply: make the first request real#
Mission (20 minutes): generate a Spring Web project, add StatusController, and serve GET /status with a plain-text health message. Work in src/main/java and application.properties.
Acceptance checks: ./gradlew bootRun starts once; curl localhost:8080/status returns your message; changing server.port moves the endpoint deliberately.
- Start with one
@RestControllerand one@GetMapping. - If startup fails, identify whether it is a port clash or a compilation problem.
- Only then add a query parameter with a default value.
Solution shape, not a script
A single controller receives no dependencies yet, returns a value directly, and keeps transport concerns at the edge. Add a service only when behaviour deserves its own seam.
Transfer: change the status endpoint into /greeting?name=... and explain why missing input should have either a default or a 400 response.
Prepare for interviews: Boot in two minutes#
Two-minute summary: Boot is not a replacement for Spring; it packages common Spring choices into starters, auto-configuration, and an executable app with an embedded server.
Explain in 60 seconds: why does Boot reduce setup without removing control?
Primary question: what happens from adding spring-boot-starter-web to serving a controller? Follow-ups: how does auto-configuration back off, and when would you deploy a WAR instead?
Debug exercise: a method returns "UP" but the browser searches for a template called UP. Diagnose the annotation mismatch and state the trade-off between JSON APIs and server-rendered views.
Strong-answer outline
State the problem first, name the three Boot conveniences, show that classpath conditions and properties drive choices, then give one override rather than reciting annotations.
Timed mock: in 90 seconds, sketch a first endpoint and say how you would prove the embedded server is listening.
Exit check#
- Which Boot feature selects common configuration from the classpath?
- What does a web starter provide beyond one library jar?
- Why does
@RestControllerchange a String response? - What is the first distinction to make when port 8080 fails?
- When is overriding a Boot default justified?
Learn next: Use explain what spring boot automates as the base, then name the main application layers in The Layer Map. Interview next: Use explain what spring boot automates as the base, then explain inversion of control in Spring Core — IoC & Dependency Injection.
Continue this path · Switch paths from this topic · Review first: HTTP request flow
Spring gave Java power but demanded endless setup. Spring Boot is Spring with the setup done for you — it makes opinionated defaults, bundles a web server inside your app, and auto-wires the plumbing, so you write business code on day one instead of XML on day three.
Built from the Session 3 slide deck. It covers the first half of the agenda in depth: the case for Spring Boot, Spring vs Spring Boot, Spring Initializr, and your first controller. The deck's later sections — Spring Boot architecture (MVC/MVCS), building full REST APIs with DTOs and validation, and testing with Postman — were listed on the agenda but not present in the captured slides, so they are outlined here as a roadmap, not taught in full. [!] Ask again with those slides or the session transcript and this page will absorb them.
Section 1Notebook Summary#
Hand-copyable revision sheet · fully derivable from the detailed notes below
Why Spring Boot exists#
- Traditional Java pain → XML config + boilerplate + manual server setup + WAR deploy + dependency hell
- Spring (2003, Rod Johnson + Juergen Hoeller) → solved a lot via IoC + DI; gave data/web layers
- Catch → Spring itself still needed heavy config, manual servers, framework integration
- Spring Boot (2014) → Spring + defaults done for you
Spring vs Spring Boot#
- Spring = framework, fine-grained control, you configure
- Spring Boot = opinionated layer on Spring, convention
over config
- Auto-configuration → wires beans from the classpath
- Embedded server → Tomcat/Jetty/Undertow inside the jar (no external server)
- Starters → one dependency pulls a curated, version-matched set
- Actuator → production monitoring/health endpoints
- Aid: Spring = raw ingredients; Boot = meal-kit, pre-measured.
Core Spring concepts#
- IoC (Inversion of Control) → framework creates & owns objects, not you
- DI (Dependency Injection) → framework hands an object what it needs
- Aid: don't new your dependencies — ask and receive.
Spring Initializr — start.spring.io#
- Web tool → generates project skeleton + build file + deps as a .zip
- Pick: build (Gradle/Maven) · language · Boot version · group/artifact · deps
- Flow: configure → Generate → unzip → open in IDE → run
- Spring Web dep → brings MVC + embedded Tomcat for building web/REST APIs
First controller (Hello World)#
- @RestController → class returns data straight to the HTTP response body
- @GetMapping("/path") → maps HTTP GET on that path to a method
- @RequestParam → pulls
?name=...from the query string into an argument - Run →
./gradlew bootRun→ hitslocalhost:8080
Box these#
- ⭐Never new a dependency in Spring — declare it, let DI inject it. Testability lives here.
- ⚠@Controller ≠ @RestController. Plain @Controller returns a view name; @RestController returns the body (adds @ResponseBody).
- ⚠Port 8080 already in use = app won't start. Free the port or set
server.port. - 💡"Opinionated" = Boot's sane defaults you can still override — it's a starting posture, not a cage.
Doodle · Boot layers: draw 3 stacked boxes — [Your code] on top of [Spring Boot: auto-config + embedded server] on top of [Spring core: IoC/DI]. Arrow up the left: "less config."
Section 2Detailed Study Notes#
Picture your first week on a Java team in 2010. Before you write a single line that does anything a user cares about, you're editing three XML files to tell the framework which objects to build, downloading a Tomcat server and pointing your project at it, and chasing a version conflict between two libraries that refuse to agree. A day gone, and the app still just prints "hello." That friction — real, daily, and universal — is the entire reason Spring Boot exists. This lesson is the story of how Java web development stopped feeling like assembling furniture with no instructions.
2.1The problem: Java web development used to be mostly setup#
Before frameworks, building a serious Java application meant hand-wiring an enormous amount of plumbing before any real work began. A team spent its early days on four recurring chores, none of which delivered a feature:
- Complex configuration. Behaviour lived in XML files and repetitive boilerplate, not in readable code.
- Time-consuming setup. Servers, dependencies, and frameworks all had to be configured by hand before anything ran.
- Deployment headaches. The app had to be packaged and shipped to a separate server that someone else configured and maintained.
- Maintenance drag. As a project grew, keeping dependencies and configuration coherent became its own full-time tax.
Every one of these stole time from the actual product. Two engineers, Rod Johnson and Juergen Hoeller, wrote the Spring Framework to take that weight off developers. [+] Spring first appeared in 2003; the deck introduces it as the direct answer to this pain.
Traditional Java setup is like renting an empty commercial kitchen and, before you can cook, installing the ovens, running the gas line, and negotiating with the power company. Spring, and then Spring Boot, is the difference between that and walking into a kitchen where the appliances are already plumbed in and warm.
2.2Spring: the problem solver — and its catch#
Spring is a framework that takes over the tedious lifecycle work of creating and connecting your objects, so your code can focus on behaviour. It did the heavy lifting through two ideas that sit at its core, plus a set of ready-made infrastructure layers.
Inversion of Control (IoC)#
Normally your code is in charge: when it needs a helper object, it builds that object itself with
new. Inversion of Control flips that — the framework, not your code, is in charge
of creating and owning objects. You describe what should exist; Spring builds it, holds it,
and hands it over when needed. The "control" over object lifecycle has been inverted from you to the
framework.
Dependency Injection (DI)#
Dependency Injection is the delivery mechanism for IoC: instead of an object fetching the things
it depends on, those things are handed to it from the outside. If your
OrderService needs a PaymentClient, you don't build the client inside the
service — you declare that you need one, and Spring injects a ready-made instance. The two terms travel
together: IoC is the principle, DI is how Spring does it.
Think of a movie shoot. An actor (your class) doesn't go buy their own costume, props, and coffee. They show up, and the production crew (the framework) hands them exactly what the scene needs. The actor just acts. That hand-off is dependency injection; the crew being in charge of all of it is inversion of control.
The moment you stop writing new SomeDependency() inside a class and start accepting it
as a constructor parameter, that class becomes trivially testable — in a test you just pass a fake.
IoC/DI isn't abstract architecture astronautics; its everyday payoff is that your code can be tested
and swapped without editing the class itself.
The catch. Spring gave excellent features and fine-grained control, but that control came at a price. As projects grew, the deck names three fresh pains that Spring alone didn't solve:
- Complex project setup — multiple configuration files, manual dependency management, and version-compatibility issues between libraries.
- Server configuration — you still set up an external server (Tomcat, Jetty, …) by hand and deployed a WAR file to it.
- Integration challenges — stitching multiple frameworks together, on top of a complex build process.
These are what "paved the way" for Spring Boot in 2014.
2.3Spring Boot: Spring with the assumptions made for you#
Spring Boot is a layer built on top of Spring that removes the setup by taking an "opinionated" view — it makes reasonable assumptions about what most developers need and configures them automatically. You still get all of Spring underneath; you just stop paying the setup tax to reach it.
"Opinionated" is the key word. It means Boot ships with sensible defaults already chosen — a default server, default configuration, default project layout — so you can run immediately. Crucially these are defaults, not walls: you can override any of them when your case is unusual.
Wires itself#
Looks at what's on your classpath and configures common components automatically, so you don't write the wiring by hand.
Server inside the app#
Bundles Tomcat, Jetty, or Undertow into the application itself — no separate server to install or deploy a WAR to.
Actuator & config#
Ships monitoring and management endpoints (Actuator) and easy externalized configuration for real deployments.
Plain Spring is a well-stocked pantry: everything a great cook could want, but you measure and combine it all yourself. Spring Boot is the meal kit — the same quality ingredients, pre-measured, with a default recipe — so dinner is on the table fast, and you can still swap an ingredient if you want to.
A very common interview question is simply "what's the difference between Spring and Spring Boot?" The clean answer: Spring is the framework; Spring Boot is an opinionated way of using Spring that auto-configures defaults, embeds a server, and manages dependencies through starters. Boot doesn't replace Spring — it packages it. Say that and you've answered it.
2.4Spring vs Spring Boot, side by side#
The deck presents this contrast as its own overview slide. The distinction is about who does the configuring.
| Dimension | Spring | Spring Boot |
|---|---|---|
| Configuration | Manual — you write it (historically XML) | Auto-configured from the classpath |
| Server | External; you set up Tomcat/Jetty and deploy a WAR | Embedded inside the app; runs as a self-contained jar |
| Dependencies | Managed by hand; version conflicts are yours | Starters bundle curated, version-matched sets |
| Setup speed | Slow; lots of upfront wiring | Fast; runnable almost immediately |
| Stance | Flexible, fine-grained control | Opinionated defaults you can override |
| Relationship | The underlying framework | A layer built on top of Spring |
Don't describe Spring Boot as "a replacement for Spring" or "a different framework." It is Spring, with configuration and packaging handled for you. In an interview, calling them competing frameworks signals you don't understand the relationship — Boot depends on Spring entirely.
2.5Starting a project: Spring Initializr#
Spring Initializr is a web tool from the Spring team that generates a ready-to-run project skeleton for you. You describe the project in a form; it hands back a zip with the folder structure, the build file, and your chosen dependencies already wired in. It lives at start.spring.io.
It exists so that "start a new Spring Boot project" doesn't mean "hand-assemble a build file and a directory tree from memory." You pick your options and the correct, version-compatible skeleton is generated for you — the same convention-over-configuration philosophy, applied to the very first step.
What you choose on the form#
| Field | What it decides |
|---|---|
| Project | Build tool — Gradle or Maven |
| Language | Java, Kotlin, or Groovy |
| Spring Boot version | Which Boot release to target |
| Group / Artifact | Your package name and project name (project metadata) |
| Dependencies | The starters to include — e.g. Spring Web for web/REST work |
The Spring Web dependency is the one that turns a bare project into something that
can answer HTTP requests. It brings in Spring MVC (the request-handling machinery) and an embedded
Tomcat server. Without it, annotations like @RestController and
@GetMapping won't exist on your classpath. It's the near-universal first dependency for
any API project.
2.6Your first controller: Hello World#
A controller is the class that receives incoming web requests and decides what to send back. It's the front door of your application: a URL arrives, the controller matches it to a method, the method runs, and its return value becomes the response. The Hello World exercise builds exactly one.
The workflow from the deck: create a class such as HelloWorldController under
src/main/java/..., paste the controller code and resolve imports, run
./gradlew bootRun in the terminal, then visit the endpoint in a browser with a query
parameter attached.
@RestController
public class HelloWorldController {
@GetMapping("/helloworld")
public String getMethodName(@RequestParam String name) {
return new String("Hello World, I am " + name + "!");
}
}Three annotations do all the work here. Read plainly, before the jargon:
- The "answer-with-data" marker (
@RestController) tells Spring this class handles web requests and that whatever a method returns should be written straight into the HTTP response body — no separate view or template step. - The "when this URL is GET-ed" marker (
@GetMapping("/helloworld")) maps an HTTP GET request on/helloworldto this method. Visit that path and this method runs. - The "read a value from the URL" marker (
@RequestParam) pulls a value out of the query string — the?name=Grootpart — and hands it to the method as thenameargument.
So a request to http://localhost:8080/helloworld?name=Groot runs the method with
name = "Groot" and returns the text Hello World, I am Groot! straight to the
browser. [!] The deck's screenshot text shows the placeholder name as both
"Goot" and "Groot"; the intended name is Groot — the "Goot" is a slide typo.
@RestController is @Controller + @ResponseBody rolled into
one. A plain @Controller treats a returned string as the name of a view to
render; @RestController treats it as the actual response body. Use
@RestController for APIs that return data. Mixing them up gives you a confusing
"template not found" error instead of your text.
Spring Boot's embedded server defaults to port 8080. If another process already holds that port, the
app fails to start with a bind error. Either stop the other process or set a different port in
application.properties with server.port=8081. This is the single most
common "why won't it run" moment for beginners.
The deck's example returns new String("Hello World, I am " + name + "!"). The
new String(...) wrapper does nothing useful here — string concatenation already
produces a String, so return "Hello World, I am " + name + "!"; is
equivalent and cleaner. [+] Worth noticing so you don't copy the habit into
your own code.
2.7What comes next (agenda roadmap)#
The session agenda continues past this point; the following were listed but not present in the captured slides. Treat this as a map of where the lesson heads, not as taught material. [!]
Spring Boot MVC / MVCS#
How a request flows through layers — Controller → Service → (Repository) → Database — and why splitting responsibilities keeps an app maintainable.
DTOs, validation, exceptions#
Building real endpoints: shaping data with DTOs, validating incoming requests, and handling errors gracefully instead of leaking stack traces.
Postman#
Exercising your API by hand — sending GET/POST requests, setting query params and bodies, and reading responses without a front end.
QEats · Module 2 · Customer Registration API#
The applied project: a REST API to manage customer registration for an e-commerce platform, pulling all of the above together.
2.8Interview & practice questions#
The natural follow-ups this material invites. Answer each aloud before expanding it.
What is the difference between Spring and Spring Boot?
Spring is the underlying framework that provides IoC, dependency injection, and infrastructure layers. Spring Boot is an opinionated layer built on top of Spring that auto-configures common components from the classpath, embeds a web server, and manages dependencies through starters. Boot doesn't replace Spring — it packages it so you can start building immediately instead of hand-wiring configuration.
What do Inversion of Control and Dependency Injection mean, and how do they relate?
Inversion of Control is the principle that the framework — not your code — is responsible for creating and managing objects and their lifecycles. Dependency Injection is the mechanism that implements it: instead of an object building its own dependencies, they are supplied to it from outside. IoC is the "what," DI is the "how." The practical payoff is looser coupling and far easier testing.
What does "opinionated" mean in the context of Spring Boot?
It means Spring Boot ships with sensible default choices already made — a default embedded server, default configuration, a conventional project layout — based on assumptions about what most applications need. This lets you run immediately without deciding everything upfront. The defaults are overridable, so "opinionated" is a fast starting posture, not a restriction.
What is an embedded server and why is it useful?
An embedded server is a web server such as Tomcat, Jetty, or Undertow bundled directly inside your application, so the app runs as a single self-contained jar. It removes the need to install and configure an external server and deploy a WAR file to it. This simplifies both local development and deployment, since running the app is the same as starting the server.
What is Spring Initializr and what does it produce?
Spring Initializr is a web tool at start.spring.io that bootstraps a new Spring Boot project. You choose the build tool, language, Boot version, project metadata, and dependencies, and it generates a downloadable zip containing the folder structure, the build file, and the selected dependencies already wired in. You extract it, open it in an IDE, and run it.
What is the role of @RestController, @GetMapping, and @RequestParam?
@RestController marks a class as a web request handler whose method return values
become the HTTP response body directly. @GetMapping("/path") maps an HTTP GET on
that path to a specific method. @RequestParam binds a query-string value (like
?name=Groot) to a method argument. Together they route a request to code and shape
the response.
What is the difference between @Controller and @RestController?
@RestController is a convenience combination of @Controller and
@ResponseBody. With a plain @Controller, a returned string is
interpreted as a view name to render. With @RestController, the return value is
serialized straight into the response body. Use @RestController for REST APIs that
return data rather than rendered pages.
Which dependency lets a Spring Boot app handle web requests, and what does it include?
The Spring Web starter. It brings in Spring MVC — the request-mapping and handling machinery
behind annotations like @RestController and @GetMapping — along with
an embedded Tomcat server. It's the standard first dependency for building web applications or
REST APIs.
Your Spring Boot app fails to start with a port-in-use error. What happened and how do you fix it?
The embedded server defaults to port 8080, and another process is already bound to it, so the
server can't start. Either stop the process occupying 8080, or change your app's port by setting
server.port (for example server.port=8081) in
application.properties. Then restart.
2.9Key takeaways#
- Traditional Java development lost days to configuration, manual servers, and dependency conflicts before any feature got written.
- Spring (Rod Johnson & Juergen Hoeller) solved much of this through Inversion of Control and Dependency Injection, but still demanded heavy setup of its own.
- Spring Boot (2014) is Spring made opinionated: auto-configuration, an embedded server, dependency starters, and production-ready Actuator features.
- Spring Boot doesn't replace Spring — it's a convenience layer on top of it. That relationship is the most common interview trap.
- Spring Initializr at start.spring.io generates a runnable project skeleton so you never hand-assemble the first setup.
- A controller is your app's front door:
@RestControllerreturns data as the response body,@GetMappingroutes a URL,@RequestParamreads the query string.
Section 3Microexercises — Build the Muscle#
Spring Boot's whole promise is that you write business code on day one. So the practice is writing controllers, not reading about them. Attempt each drill before opening the walkthrough — type the controller, predict the error — then check yourself. Muscle memory beats recognition.
EX 1Extend the controller: an optional parameter with a default#
Building on the Hello World controller, write a GreetController exposing
GET /greet that takes a required name and an
optional lang (default en), returning a localized
greeting. Support en, es, hi; anything else falls back to
English.
@RestControllerreturning plain text.namerequired; a missingnameshould be a client error.langoptional, via@RequestParam(defaultValue = "en").
URLs to satisfy:
/greet?name=Ada→Hello, Ada!/greet?name=Ada&lang=es→¡Hola, Ada!/greet?name=Ada&lang=hi→नमस्ते, Ada!
Show the full walkthrough
Step 1 — class + mapping. Mark the class @RestController so
returns become the response body directly, and map the path with
@GetMapping("/greet").
Step 2 — the required param. @RequestParam String name is
required by default. If name is absent, Spring returns 400 Bad Request
automatically — you don't write that check yourself.
Step 3 — the optional param with a default.
@RequestParam(defaultValue = "en") String lang makes lang optional;
when the query omits it, Spring supplies "en". (Setting a defaultValue
also implies required = false.)
Step 4 — pick the greeting. A small switch, defaulting to English for any unknown language code.
@RestController
public class GreetController {
@GetMapping("/greet")
public String greet(@RequestParam String name, @RequestParam(defaultValue = "en") String lang) {
String hello = switch (lang) {
case "es" -> "¡Hola";
case "hi" -> "नमस्ते";
default -> "Hello";
};
return hello + ", " + name + "!";
}
}Trace the URLs:
/greet?name=Ada→langdefaults to"en"→Hello, Ada!/greet?name=Ada&lang=es→¡Hola, Ada!/greet?name=Ada&lang=hi→नमस्ते, Ada!/greet(noname) → Spring returns400before your method even runs.
Run it with ./gradlew bootRun, then hit the URLs in a browser or with curl. Because
Spring Web bundles embedded Tomcat, there's no separate server to start.
Pushing "optional with a fallback" into the annotation keeps the method body about the greeting, not about argument-plumbing. The framework does the parsing and defaulting — the same convention-over-configuration spirit, applied one parameter at a time.
EX 2Diagnose two "why won't it work" moments#
A teammate's endpoint returns an error page instead of text, and later the app won't boot at all. Diagnose both from the symptoms — these are the two most common beginner traps.
Symptom 1 — the wrong base annotation. Hitting /status gives a
500 / "Whitelabel Error Page" / "template not found" instead of the text OK.
@Controller // ← note: not @RestController
public class StatusController {
@GetMapping("/status")
public String status() {
return "OK";
}
}Symptom 2 — the app fails to start with:
Web server failed to start. Port 8080 was already in use.Show the full walkthrough
Symptom 1 — diagnose. @Controller treats the returned
String as a view name: Spring goes looking for a template called
OK to render, finds none, and errors. @RestController is
@Controller + @ResponseBody; it treats the return value as the
response body.
Fix: change the annotation to @RestController (or add
@ResponseBody to the method). Now /status returns OK as
plain text.
@RestController // ← now the return value IS the body
public class StatusController {
@GetMapping("/status")
public String status() {
return "OK";
}
}Symptom 2 — diagnose. Boot's embedded server defaults to port 8080, and another process already holds it — very often a previous run of this very app that never shut down. Two fixes:
- Free the port: find and stop the other process
(
lsof -i :8080to identify it). - Move your app: set
server.port=8081insrc/main/resources/application.properties.
One bug bites at request time (@Controller vs
@RestController), the other at boot time (port clash). When a Spring
Boot app misbehaves, first ask which phase failed — it narrows the cause
immediately.