Introduction to Spring & Spring Boot
Reviewed & published by Brayan K
Spring is the most widely used Java framework — an IoC container plus a vast ecosystem — and Spring Boot is the opinionated layer that makes spinning up a real, production-ready app fast and almost configuration-free.
Part of the free Java course at LearnCodingFast — hands-on lessons with worked examples and the output they print, plus practice exercises and a quick quiz.
Before You Start
This track assumes you understand dependency injection and interfaces, since Spring is fundamentally a DI container. Familiarity with annotations will make the syntax feel natural.
What You'll Learn
- What the Spring Framework is and its IoC core
- How Spring Boot layers on top of Spring
- Auto-configuration and convention over configuration
- Starters: curated dependency bundles
- Embedded servers and runnable jars
- What @SpringBootApplication and run() do
The Big Idea — A Kit Car vs a Car That Drives Off the Lot
💡 Analogy: Plain Spring is a superb engine you must bolt into a chassis yourself — powerful, but you wire the fuel lines, pick a server, and write the configuration. Spring Boot is the same engine delivered in a car that already starts: the wiring is done with sensible defaults, the server is built in, and you can drive away in minutes — yet you can still open the bonnet and change anything you like.
Boot does not hide Spring; it pre-assembles it. Underneath, the same IoC container is doing the work.
1️⃣ What Spring Is
At its core Spring is a dependency-injection container: you declare your objects as beans and Spring creates and wires them for you (Inversion of Control). Around that core is a large ecosystem — web (Spring MVC), data (Spring Data), security, messaging and more — all built on the same container.
// "Plain" Spring Framework wiring used to look like a lot of ceremony:
// XML files or a verbose @Configuration class, a manually started context,
// and an externally installed servlet container to deploy a WAR into.
// Spring Boot collapses all of that into ONE annotation + ONE main method,
// while still using the very same IoC container underneath. You opt OUT of
// the defaults only where your app genuinely differs.2️⃣ A Spring Boot Application in One Class
Every Boot app has a class annotated with @SpringBootApplication and a main that calls SpringApplication.run(...). That single line bootstraps the container, runs auto-configuration, and starts the embedded server.
// The entry point of every Spring Boot application.
// (Conceptual — needs Spring Boot on the classpath to run.)
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication // = @Configuration + @EnableAutoConfiguration + @ComponentScan
public class DemoApplication {
public static void main(String[] args) {
// Boots the IoC container, runs auto-configuration, and (for a web app)
// starts the embedded server — all from one line.
SpringApplication.run(DemoApplication.class, args);
}
}3️⃣ Starters — Dependencies Made Simple
Rather than hand-picking compatible library versions, you add a starter — one coordinate that pulls in a curated bundle. spring-boot-starter-web brings Spring MVC, JSON support and an embedded Tomcat all at once.
<!-- pom.xml: a STARTER pulls in a curated, compatible set of libraries. -->
<dependency>
<groupId>org.springframework.boot</groupId>
<!-- spring-boot-starter-web => Spring MVC + Jackson (JSON) + embedded Tomcat -->
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<!-- adds JPA + Hibernate for talking to a database -->
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!-- You add a handful of starters; Boot's auto-configuration wires the rest. -->4️⃣ What Happens on Startup
Understanding the startup sequence demystifies Boot: it is just creating the IoC container, scanning for your beans, applying conditional auto-configuration, and (for web apps) starting the server.
// MENTAL MODEL of what SpringApplication.run(...) does at startup:
//
// 1. Create the ApplicationContext (the IoC container).
// 2. Scan packages for @Component / @Service / @Repository / @Controller beans.
// 3. Run AUTO-CONFIGURATION: look at the classpath + your beans, and wire
// sensible defaults (a DataSource, a DispatcherServlet, JSON support...).
// 4. For a web app, start the EMBEDDED server (Tomcat by default).
// 5. Hand control to your application — it is now running.
//
// You never call 'new' on your services; the container builds the object graph.5️⃣ The Container, in Plain Java (runnable)
Everything above is conceptual because it needs Spring on the classpath. The two ideas underneath it do not: a bean is just an object the container creates and hands out by type, and auto-configuration is a conditional default that backs off the moment you define your own. Both fit in a few dozen lines of ordinary Java, compiled and run here with nothing but the JDK.
// A hand-rolled IoC container in plain Java — no Spring on the classpath.
// It shows the two ideas Boot is built on: beans live in a container that
// hands them out by type, and auto-configuration BACKS OFF when you have
// already defined a bean of that type yourself.
import java.util.LinkedHashMap;
import java.util.Map;
public class IocDemo {
interface Greeter { String greet(String name); }
static class PoliteGreeter implements Greeter {
public String greet(String name) { return "Good day, " + name + "."; }
}
static class DefaultGreeter implements Greeter {
public String greet(String name) { return "Hello, " + name + "!"; }
}
// The "ApplicationContext": a map from a type to the ONE bean of that type.
static class Container {
private final Map<Class<?>, Object> beans = new LinkedHashMap<>();
<T> void register(Class<T> type, T bean) {
beans.put(type, bean);
System.out.println(" bean " + type.getSimpleName() + " = " + bean.getClass().getSimpleName());
}
<T> T getBean(Class<T> type) { return type.cast(beans.get(type)); }
// What @EnableAutoConfiguration does for a Greeter: a CONDITIONAL default.
void autoConfigure() {
if (beans.containsKey(Greeter.class)) {
System.out.println("auto-config: Greeter already defined, backing off");
} else {
System.out.println("auto-config: no Greeter found, using default");
register(Greeter.class, new DefaultGreeter());
}
}
}
public static void main(String[] args) {
System.out.println("App A registers its own Greeter first:");
Container appA = new Container();
appA.register(Greeter.class, new PoliteGreeter());
appA.autoConfigure();
System.out.println("A: " + appA.getBean(Greeter.class).greet("Ada"));
System.out.println();
System.out.println("App B defines nothing and accepts the default:");
Container appB = new Container();
appB.autoConfigure();
System.out.println("B: " + appB.getBean(Greeter.class).greet("Ada"));
}
}🎯 YOUR TURN — Wire a service through the container
Register the greeter under its interface type, let the container hand it to WelcomeService, then fetch the service by its own type. Replace each ___ with the value in its hint, then compile and run it.
// 🎯 YOUR TURN — wire two beans through the tiny container.
// WelcomeService does not create its Greeter; it is HANDED one (constructor
// injection), which is exactly what Spring does with @Autowired constructors.
import java.util.LinkedHashMap;
import java.util.Map;
public class WelcomeApp {
interface Greeter { String greet(String name); }
static class PoliteGreeter implements Greeter {
public String greet(String name) { return "Good day, " + name + "."; }
}
static class WelcomeService {
private final Greeter greeter;
WelcomeService(Greeter greeter) { this.greeter = greeter; } // injected
String welcome(String name) { return greeter.greet(name) + " Welcome aboard!"; }
}
static class Container {
final Map<Class<?>, Object> beans = new LinkedHashMap<>();
<T> void register(Class<T> type, T bean) { beans.put(type, bean); }
<T> T getBean(Class<T> type) { return type.cast(beans.get(type)); }
}
public static void main(String[] args) {
Container context = new Container();
// 1) Register the greeter under its INTERFACE type, not the concrete class.
context.register(___, new PoliteGreeter()); // 👉 replace ___ with Greeter.class
// 2) Build the service by asking the container for the Greeter it needs.
WelcomeService service = new WelcomeService(context.getBean(___)); // 👉 replace ___ with Greeter.class
context.register(WelcomeService.class, service);
// 3) Ask the container for the service by ITS type and use it.
System.out.println(context.getBean(___).welcome("Ada")); // 👉 replace ___ with WelcomeService.class
System.out.println("beans in the container: " + context.beans.size());
}
}
// ✅ Expected output:
// Good day, Ada. Welcome aboard!
// beans in the container: 2🧠 Quick Recall
Predict before you peek.
Answer: No — Boot is a layer on top of Spring. It uses the same IoC container and adds auto-configuration, starters and an embedded server.
Answer: @Configuration, @EnableAutoConfiguration and @ComponentScan.
Answer: Boot embeds the server inside the runnable jar, so java -jar app.jar starts everything.
Common Misconceptions
- ❌ "Boot is a different framework." It is a layer on Spring using the same container. Fix: think of it as pre-assembled Spring.
- ❌ Putting the main class deep in a package. Component scanning starts from the main class's package. Fix: keep it at the root of your packages.
- ❌ Pinning every dependency version yourself. Starters and the BOM manage compatible versions. Fix: rely on starters.
- ❌ Fighting auto-configuration. It backs off when you define your own bean. Fix: override only what differs.
- ❌ Expecting a web server with no web starter. No web starter means no embedded server. Fix: add spring-boot-starter-web for REST.
Pro Tips
- 💡 Start every project at start.spring.io (Spring Initializr) to pick starters and generate the skeleton.
- 💡 Keep the main class at the package root so component scanning finds everything.
- 💡 Add Actuator early for free /health and /metrics endpoints in production.
- 💡 Lean on the defaults — only configure what genuinely differs from convention.
📋 Quick Reference
| Concept | Syntax / idea | Note |
|---|---|---|
| app annotation | @SpringBootApplication | On the main class |
| launch | SpringApplication.run(...) | Boots the container |
| web starter | spring-boot-starter-web | MVC + JSON + Tomcat |
| data starter | spring-boot-starter-data-jpa | JPA + Hibernate |
| auto-config | @EnableAutoConfiguration | Defaults from classpath |
| component scan | @ComponentScan | Finds your beans |
| embedded server | Tomcat in the jar | java -jar app.jar |
| ops endpoints | Actuator | /health, /metrics |
📚 Resources / Keep Learning
- 📘 Spring Boot Reference Documentation (docs.spring.io)
- 📗 Building an Application with Spring Boot — spring.io guide
- 📗 Spring Initializr — generate a new project
🎉 Lesson Complete!
You now know what the Spring Framework is, how Spring Boot layers auto-configuration, starters and an embedded server on top, and what @SpringBootApplication plus SpringApplication.run() do at startup.
Practice quiz
What is the Spring Framework, at its core?
- A build tool like Maven
- An IoC/dependency-injection container plus a large ecosystem of modules
- A web browser
- A relational database
Answer: An IoC/dependency-injection container plus a large ecosystem of modules. Spring's heart is its IoC container, which creates and wires beans; around it sits a huge ecosystem (web, data, security, etc.).
How does Spring Boot relate to the Spring Framework?
- It replaces Spring entirely
- It is an opinionated layer on top of Spring that adds auto-configuration and starters
- It is an unrelated language
- It only works without Spring
Answer: It is an opinionated layer on top of Spring that adds auto-configuration and starters. Spring Boot builds ON Spring, adding auto-configuration, starter dependencies, and an embedded server to remove boilerplate.
What problem does Spring Boot's 'auto-configuration' solve?
- It writes your business logic
- It configures sensible defaults based on the jars on the classpath
- It compiles Java to native code
- It encrypts the database
Answer: It configures sensible defaults based on the jars on the classpath. Auto-configuration inspects the classpath and existing beans, then wires reasonable defaults so you write far less setup code.
What is a 'starter' in Spring Boot?
- A main method
- A curated set of dependencies bundled under one coordinate (e.g. spring-boot-starter-web)
- A test runner
- A database driver only
Answer: A curated set of dependencies bundled under one coordinate (e.g. spring-boot-starter-web). A starter is a convenient dependency descriptor that pulls in a compatible group of libraries for a use case.
What does an 'embedded server' in Spring Boot mean?
- You must install Tomcat separately
- The servlet container (e.g. Tomcat) ships inside your runnable jar
- There is no web server
- It runs only in the cloud
Answer: The servlet container (e.g. Tomcat) ships inside your runnable jar. Spring Boot embeds a server like Tomcat so the app runs as a self-contained jar with java -jar, no external install.
Which is NOT a typical benefit Spring Boot advertises?
- Fast project bootstrapping
- Opinionated defaults
- Production-ready features like metrics and health checks
- Automatic generation of correct business requirements
Answer: Automatic generation of correct business requirements. Boot speeds setup and adds production tooling, but it cannot invent your domain logic or requirements for you.
The principle that an external container creates and wires your objects is called...
- Inversion of Control (IoC)
- Polymorphism
- Garbage collection
- Reflection
Answer: Inversion of Control (IoC). IoC means the framework controls object creation and wiring; dependency injection is how Spring implements IoC.
What is 'convention over configuration'?
- Forcing XML everywhere
- Providing sensible defaults so you only configure the exceptions
- Disabling all defaults
- Requiring manual wiring of every bean
Answer: Providing sensible defaults so you only configure the exceptions. Boot favours defaults: follow the conventions and you write almost no config, overriding only what differs.
Which module would you reach for to build REST web endpoints?
- spring-boot-starter-batch
- spring-boot-starter-web
- spring-boot-starter-mail
- spring-boot-starter-quartz
Answer: spring-boot-starter-web. spring-boot-starter-web bundles Spring MVC and an embedded server for building web and REST applications.
Spring Boot Actuator primarily provides...
- A GUI builder
- Production-ready endpoints such as /health and /metrics
- A new programming language
- Automatic UI styling
Answer: Production-ready endpoints such as /health and /metrics. Actuator exposes operational endpoints (health, metrics, info) to monitor and manage a running application.
Continue this course
- Previous: Checkpoint: Practical Java
- Next: Setting Up a Spring Boot Project — Spring Initializr, starters, @SpringBootApplication and the project layout
- Quick reference: Java cheat sheet
- From the blog: C++ vs Java: Which Should You Learn First?
Frequently asked questions
What is the difference between Spring and Spring Boot?
The Spring Framework is the foundation: its core is an Inversion-of-Control (IoC) container that creates and wires your objects (beans), plus a large ecosystem of modules for web, data access, security, messaging and more. Spring Boot is an opinionated layer built on top of that framework. It does not replace Spring — it uses the very same container — but it removes the historical boilerplate by adding auto-configuration (sensible defaults based on what's on your classpath), starter dependencies (one coordinate that pulls in a compatible set of libraries), and an embedded server so your app runs as a self-contained jar. In short: Spring gives you the engine; Spring Boot gives you the car with the engine already installed and tuned.
What does the @SpringBootApplication annotation actually do?
@SpringBootApplication is a convenience meta-annotation that combines three things: @Configuration (marks the class as a source of bean definitions), @EnableAutoConfiguration (turns on Boot's auto-configuration so defaults are wired from the classpath), and @ComponentScan (tells Spring to scan the current package and sub-packages for your @Component, @Service, @Repository and @Controller beans). Placing it on your main class, then calling SpringApplication.run(...) in main, is what bootstraps the entire application: it builds the IoC container, performs auto-configuration, and for a web application starts the embedded server.
What is auto-configuration and why is it useful?
Auto-configuration is Spring Boot's mechanism for guessing how you probably want things wired, based on the jars present and the beans you have (or haven't) defined. If spring-boot-starter-web is on the classpath, Boot configures Spring MVC, a JSON message converter, and an embedded Tomcat; if a database driver and JPA are present, it sets up a DataSource and an EntityManager. Crucially these are conditional defaults — the moment you define your own bean of a given type, Boot backs off and uses yours. This is the 'convention over configuration' philosophy: you only write configuration for the parts that differ from the sensible defaults.
Do I still need to install a server like Tomcat?
Not for the common case. A Spring Boot web application embeds the servlet container (Tomcat by default, with Jetty or Undertow as alternatives) directly inside the build, so the output is a single executable jar you launch with java -jar app.jar. There is no separate server install and no WAR deployment step. This makes the app trivial to run locally, ship in a container image, or deploy to a cloud platform. You can still build a traditional WAR for an external server if your environment requires it, but the embedded model is the default and what most new projects use.
Is Spring Boot only for web applications?
No. Although building REST APIs is the most common use, Spring Boot supports many application types: command-line and batch jobs, scheduled tasks, messaging consumers, and more. The web server only starts if a web starter is on the classpath; a plain Boot application without spring-boot-starter-web runs your code and then exits, which is ideal for batch or CLI tools. The shared benefit across all of these is the IoC container plus auto-configuration: regardless of the kind of app, Boot handles object wiring and sensible defaults so you focus on your own logic.