Spring Boot Basics — Complete Guide
In this tutorial, you will learn about Spring Boot Basics. We cover key concepts, practical examples, and best practices to help you master this topic.
Why Spring Boot?
Spring revolutionized Java enterprise development by introducing dependency injection and aspect-oriented programming, replacing the heavyweight EJB model. However, traditional Spring required extensive XML configuration, dependency management conflicts, and complex setup. Spring Boot emerged as the solution: it embeds Tomcat, auto-configures Spring based on classpath dependencies, provides production-ready metrics and health checks, and eliminates boilerplate configuration.
Spring Boot's philosophy is "opinionated defaults." It makes reasonable assumptions about your infrastructure and configures them automatically. If you have H2 on the classpath, you get an in-memory database. If you have spring-web on the classpath, you get an embedded Tomcat server. You only write configuration when you need to override the defaults.
flowchart TB
subgraph SB[Spring Boot Application]
AC[Auto-Configuration] --> Container[Embedded Tomcat/Jetty]
DI[Dependency Injection] --> Beans
Beans --> Controller[Web Controllers]
Beans --> Service[Service Layer]
Beans --> Repository[Data Repositories]
AC --> Actuator[Actuator - Metrics]
AC --> Config[Externalized Config]
end
Controller --> Service
Service --> Repository
Repository --> DB[(Database)]
Client[HTTP Client] --> Controller
Actuator --> Metrics[Metrics Endpoints]
Setting Up a Spring Boot Project
Using Spring Initializr
The quickest way to create a Spring Boot project is via start.spring.io or your IDE.
Maven Dependencies
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.3.0</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
The Main Application Class
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
@SpringBootApplication combines three annotations: @Configuration, @EnableAutoConfiguration, and @ComponentScan. When you run the main method, Spring Boot starts an embedded Tomcat server, scans for components, and auto-configures beans based on classpath dependencies.
Building a REST Controller
package com.example.demo.controller;
import org.springframework.web.bind.annotation.*;
import java.time.LocalDateTime;
import java.util.*;
@RestController
@RequestMapping("/api/hello")
public class HelloController {
@GetMapping
public Map<String, String> greet(@RequestParam(defaultValue = "World") String name) {
return Map.of(
"message", "Hello, " + name + "!",
"timestamp", LocalDateTime.now().toString()
);
}
@GetMapping("/{id}")
public String greetById(@PathVariable int id) {
return "Hello, user " + id;
}
}
Testing the Controller
curl http://localhost:8080/api/hello?name=Alice
Output:
{"message":"Hello, Alice!","timestamp":"2026-06-28T10:30:00"}
Dependency Injection in Spring
Spring manages object creation and wiring through its IoC container. Components declare their dependencies, and Spring injects them.
// Service interface
public interface GreetingService {
String generateGreeting(String name);
}
// Service implementation
@Service
public class FormalGreetingService implements GreetingService {
@Override
public String generateGreeting(String name) {
return "Good day, " + name + ".";
}
}
// Controller with dependency injection
@RestController
@RequestMapping("/api/greet")
public class GreetingController {
private final GreetingService greetingService;
// Constructor injection (preferred)
public GreetingController(GreetingService greetingService) {
this.greetingService = greetingService;
}
@GetMapping
public String greet(@RequestParam String name) {
return greetingService.generateGreeting(name);
}
}
Injection Types
| Type | Description | When to Use |
|---|---|---|
| Constructor | Final fields, explicit dependencies | Always preferred |
| Setter | Optional dependencies | For optional config |
| Field | Direct annotation on field | Discouraged (hard to test) |
Configuration and Properties
application.yml
server:
port: 9090
servlet:
context-path: /api
spring:
datasource:
url: jdbc:postgresql://localhost:5432/mydb
username: ${DB_USERNAME:appuser}
password: ${DB_PASSWORD:secret}
jpa:
hibernate:
ddl-auto: validate
show-sql: true
app:
feature-flags:
new-checkout: true
beta-program: false
Type-Safe Configuration Properties
@ConfigurationProperties(prefix = "app.feature-flags")
@Component
public class FeatureFlags {
private boolean newCheckout;
private boolean betaProgram;
// getters and setters
}
@Service
public class CheckoutService {
private final FeatureFlags featureFlags;
public CheckoutService(FeatureFlags featureFlags) {
this.featureFlags = featureFlags;
}
public void processCheckout(Order order) {
if (featureFlags.isNewCheckout()) {
// Use new checkout flow
} else {
// Use legacy checkout flow
}
}
}
Profiles
Profiles allow different configurations for different environments.
# application-dev.yml
spring:
datasource:
url: jdbc:h2:mem:testdb
jpa:
hibernate:
ddl-auto: create-drop
logging:
level:
com.example: DEBUG
# Run with dev profile
java -jar myapp.jar --spring.profiles.active=dev
# Or via environment variable
export SPRING_PROFILES_ACTIVE=dev,cloud
Spring Boot Actuator
Actuator provides production-ready endpoints for monitoring and management.
management:
endpoints:
web:
exposure:
include: health,info,metrics,env,loggers
endpoint:
health:
show-details: always
# Health check
curl http://localhost:8080/actuator/health
# Application info
curl http://localhost:8080/actuator/info
# Metrics
curl http://localhost:8080/actuator/metrics/jvm.memory.used
Common Mistakes
1. Scanning Too Many Packages
If @SpringBootApplication is placed in a package that does not cover your components, they will not be scanned.
// Main class at com.example.app
// Components at com.example.app.controller - works
// Components at com.example.legacy.controller - NOT scanned
Specify @SpringBootApplication(scanBasePackages = "com.example") if needed.
2. Circular Dependencies
Bean A depends on Bean B, and Bean B depends on Bean A. Spring can sometimes resolve this with lazy initialization, but it is a design smell.
3. Field Injection for Testing
// Hard to test: cannot easily mock greetingService
@RestController
public class TestController {
@Autowired
private GreetingService greetingService;
}
// Easy to test: inject mock in constructor
@RestController
public class TestController {
private final GreetingService greetingService;
public TestController(GreetingService greetingService) {
this.greetingService = greetingService;
}
}
4. Not Using the Right Starter
Spring Boot starters group dependencies logically. Using spring-boot-starter-web for a non-web application brings unnecessary dependencies.
5. Ignoring the Failure Analyzer
Spring Boot's failure analyzer provides actionable error messages. Read the full stack trace and analysis output when an application fails to start.
6. Exposing Actuator Endpoints in Production
# Restrict actuator access in production
management:
endpoints:
web:
exposure:
include: health,info
endpoint:
shutdown:
enabled: false
Practice Questions
- What does
@SpringBootApplicationencapsulate? What happens if you omit it and use each annotation individually? - How does Spring Boot's auto-configuration decide which beans to configure?
- What is the difference between
@Component,@Service,@Repository, and@Controller? - How do you externalize configuration in a Spring Boot application?
- What is the purpose of
spring-boot-starter-parent?
Challenge: Create a Spring Boot application that exposes a REST API for a task management system. Implement CRUD operations for tasks (id, title, description, status, dueDate), use an H2 in-memory database, and include validation. Add a custom health indicator that checks whether all database tables exist.
FAQ
Mini Project: RESTful Blog API
Build a RESTful blog API with Spring Boot that provides:
- User registration and authentication with JWT tokens
- CRUD operations for blog posts with pagination and sorting
- Category and tag management for posts
- Comment system on posts
- Search posts by title or content
- Swagger/OpenAPI documentation via springdoc-openapi
- Integration tests with @WebMvcTest and @DataJpaTest
Use Spring Data JPA for persistence, validation with Jakarta Bean Validation, and global Exception Handling with @ControllerAdvice.
What's Next
You have built a solid foundation with Spring Boot. In the next lesson, we will dive deeper into data access with Spring Data JPA, learning about repositories, entity relationships, and query methods.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro