Spring Boot

Interactive Spring Boot Course SPA

Spring Boot Mastery Course

Welcome to the Spring Boot Mastery course. This interactive guide provides a complete overview of the curriculum, from core concepts to a final, deployable project. Use the dashboard below to see a breakdown of course topics, or use the navigation to drill down into specific modules and lessons.

Core Modules

4

Total Lessons

28

Capstone Project

1

Course Topic Distribution

This chart visualizes the number of lessons dedicated to each key topic, giving you an at-a-glance understanding of the course’s focus. Hover over any bar to see the exact lesson count.

This module demystifies the “magic” of Spring Boot. You’ll set up a professional development environment and learn the fundamental concepts of Inversion of Control (IoC), Dependency Injection (DI), and configuration management that power every Spring application.

1. The Spring Ecosystem Explained +

The Big Picture

Before writing code, it’s crucial to understand what we are using. Spring Framework is a powerful, comprehensive framework for Java development, but it is famous for being “heavy” on configuration. In the old days, setting up a Spring project required massive XML files and hours of setup.

Spring Boot changed the game. It is an extension of the Spring Framework that prioritizes Convention over Configuration. It comes with “Opinionated Defaults”—meaning it makes reasonable decisions for you (like which server to use or which library versions work together) so you can start writing business logic immediately.

It also includes an Embedded Server (usually Tomcat). This means you don’t need to install a separate web server on your machine. You simply run the Java application, and it starts its own server internally.

2. Environment Setup & “Hello World” +

To build modern Spring Boot applications, you need the right tools: JDK 17 or 21 (LTS versions) and an IDE like IntelliJ IDEA.

Step 1: Spring Initializr

We don’t create project folder structures manually. We use start.spring.io. Select Maven, Java, Spring Boot 3.x, and add the “Spring Web” dependency. Generate and open the project.

Step 2: The Entry Point

Open Application.java. You will see the @SpringBootApplication annotation. This is a “meta-annotation” that combines three key configurations:

  • @Configuration: Marks the class as a source of definitions.
  • @EnableAutoConfiguration: Tells Boot to start adding beans based on classpath settings.
  • @ComponentScan: Tells Spring to look for other components in your package.

Step 3: Writing “Hello World”

Create a new class named HelloController.java. We use the @RestController annotation to tell Spring this class handles web requests.

package com.example.demo;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HelloController {

    @GetMapping("/hello")
    public String sayHello() {
        return "Hello, Spring Boot!";
    }
}

Run your DemoApplication class. You should see logs indicating Tomcat started on port 8080. Open your browser to http://localhost:8080/hello to see your message!

3. Dependency Management (Maven/Gradle) +

If you look at your pom.xml file, you won’t see hundreds of library versions. Instead, you see Starters.

Starters are convenient dependency descriptors. For example, the spring-boot-starter-web starter imports Spring MVC, Jackson (for JSON), Tomcat (embedded server), and logging libraries automatically.

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

The Parent POM manages the versions of these dependencies, ensuring you never face “dependency hell” where libraries are incompatible with each other.

4. Core Concepts: Dependency Injection (DI) & IoC +

This is the heart of Spring. Inversion of Control (IoC) means that instead of your code creating objects (e.g., new Service()), the framework (Spring) creates the objects and manages them.

Dependency Injection (DI) is how the framework “injects” the dependencies an object needs.

The Wrong Way (Tightly Coupled):

public class UserController {
    // Hard to test, tightly coupled!
    private UserService userService = new UserService(); 
}

The Spring Way (Constructor Injection):

@RestController
public class UserController {
    private final UserService userService;

    // Spring passes the service automatically!
    public UserController(UserService userService) {
        this.userService = userService;
    }
}

5. Spring Beans: Scopes and Lifecycle +

Objects managed by Spring are called Beans. By default, they are Singletons (one shared instance). However, sometimes you need different behaviors.

1. Singleton Lifecycle (The Default)

Since Singletons are created once and live for the entire application duration, their lifecycle looks like this:

  1. Instantiation: Spring creates the object (new Service()).
  2. Dependency Injection: Spring injects required fields/constructors.
  3. Initialization: @PostConstruct method runs.
  4. Service: The bean handles requests (Shared by all threads).
  5. Destruction: Application shuts down, @PreDestroy runs.

2. Thread Safety & Multiple Users

Crucial: Because there is only one instance of a Singleton bean, if 1,000 users send requests simultaneously, 1,000 threads will access that same object at the same time.

Therefore, Singleton beans must be Stateless. You should never store user-specific data in class fields.

❌ Bad Practice (Not Thread Safe):
@Service
public class UnsafeService {
    // DANGER! This field is shared by ALL users.
    // If User A sets it to "A", User B might overwrite it to "B"
    // before User A is done using it.
    private String currentUser; 

    public void process(String user) {
        this.currentUser = user; // Race Condition!
    }
}
✅ Good Practice (Stateless):
@Service
public class SafeService {
    // No instance variables holding state.
    
    public void process(String user) {
        // Variables inside methods are stored in 'Stack Memory'.
        // Each thread gets its own Stack, so this is 100% safe.
        String processedUser = user.toUpperCase();
        saveToDb(processedUser);
    }
}

3. Practical Examples of Other Scopes

When you need state, use these scopes:

A. Prototype Scope (New Instance per Injection)

Useful for stateful objects that aren’t thread-safe or need independent state.

@Component
@Scope("prototype")
public class TicketGenerator {
    private int ticketId = 0;
    public int getNext() { return ticketId++; }
}
// Service A gets Generator 1. Service B gets Generator 2.
// They are completely independent objects.
B. Request Scope (Web Only)

Data lives only as long as the HTTP request (e.g., ~50ms). Useful for tracking data per API call.

@Component
@RequestScope
public class RequestLog {
    private String requestId = UUID.randomUUID().toString();
    // Every single HTTP request gets a unique ID instance.
}
C. Session Scope (Web Only)

Data lives across multiple requests from the same user (e.g., Shopping Cart, Login Info).

@Component
@SessionScope
public class UserCart {
    private List<String> items = new ArrayList<>();
    
    public void addItem(String item) {
        items.add(item);
    }
    // Items persist even if the user refreshes the page.
}

6. Configuration Management +

Hardcoding values (like database URLs or API keys) in Java code is bad practice. Spring Boot uses application.properties (or application.yml) located in src/main/resources.

server.port=8081
app.welcomeMessage=Welcome to our Blog!

You can inject these values into your code using the @Value annotation:

@Value("${app.welcomeMessage}")
private String message;

7. Profiles & Environment Isolation +

You rarely run the same configuration locally as you do in production. Spring Boot Profiles solve this allowing you to have separate property files:

  • application-dev.properties (Local DB, debug logging)
  • application-prod.properties (Prod DB, minimal logging)

To activate a specific profile, you can set it in your main properties file:

spring.profiles.active=dev

Or pass it as a command-line argument when deploying: java -jar myapp.jar --spring.profiles.active=prod.

This module focuses on building clean, robust, and standard-compliant RESTful APIs. You’ll learn to handle web requests, manage JSON data, implement the DTO pattern, and create a global exception handling strategy for a professional-grade API.

8. REST Architecture & Controller Basics +

REST (Representational State Transfer) relies on standard HTTP verbs. Here is how to implement all standard CRUD operations in a single Controller.

@RestController
@RequestMapping("/api/posts")
public class PostController {

    // 1. GET: Retrieve all resources
    // Endpoint: GET /api/posts
    @GetMapping
    public List<String> getAllPosts() {
        return List.of("Intro to Java", "Spring Boot Basics");
    }

    // 2. GET: Retrieve a single resource by ID
    // Endpoint: GET /api/posts/1
    @GetMapping("/{id}")
    public String getPostById(@PathVariable Long id) {
        return "Fetching details for Post ID: " + id;
    }

    // 3. POST: Create a new resource
    // Endpoint: POST /api/posts
    @PostMapping
    public String createPost(@RequestBody String content) {
        // In real apps, you'd save this to a DB
        return "Created new post with content: " + content;
    }

    // 4. PUT: Update an existing resource (Replace fully)
    // Endpoint: PUT /api/posts/1
    @PutMapping("/{id}")
    public String updatePost(@PathVariable Long id, @RequestBody String newContent) {
        return "Updated Post " + id + " with: " + newContent;
    }

    // 5. DELETE: Remove a resource
    // Endpoint: DELETE /api/posts/1
    @DeleteMapping("/{id}")
    public String deletePost(@PathVariable Long id) {
        return "Deleted Post " + id;
    }
}

Key Annotations:

  • @RestController: Marks the class as a web handler returning JSON.
  • @RequestMapping: Sets the base URL path.
  • @PathVariable: Extracts values from the URL (e.g., ID).
  • @RequestBody: Extracts the JSON payload from the request.

9. Handling Requests: Path Variables & Query Parameters +

There are two main ways to pass data in the URL:

1. Path Variables (@PathVariable)

Used to identify a specific resource. Example: /api/posts/1

@GetMapping("/{id}")
public String getPostById(@PathVariable Long id) {
    return "Fetching post " + id;
}

2. Query Parameters (@RequestParam)

Used for sorting, filtering, or pagination. Example: /api/posts?category=tech

@GetMapping
public String getPosts(@RequestParam(required = false) String category) {
    return "Filtering by " + category;
}

10. Handling Request Bodies & Serialization +

When creating data (POST), we send JSON in the request body. Spring automatically converts this JSON into a Java Object using the @RequestBody annotation and the Jackson library.

We also use ResponseEntity to return specific HTTP status codes (like 201 Created).

@PostMapping
public ResponseEntity<Post> createPost(@RequestBody Post newPost) {
    // logic to save post...
    return ResponseEntity.status(HttpStatus.CREATED).body(newPost);
}

11. The DTO Pattern (Data Transfer Objects) +

Never expose your Database Entities directly. It creates security risks and tight coupling. Instead, use DTOs—simple POJOs that carry only the data needed for that specific request.

// Don't use the 'User' Entity here!
public ResponseEntity<UserResponseDTO> register(@RequestBody UserRequestDTO request) {
    User user = new User();
    user.setUsername(request.getUsername());
    // Manual mapping or use ModelMapper/MapStruct
    return ResponseEntity.ok(new UserResponseDTO(user));
}

12. Input Validation & Error Handling +

Don’t trust user input. Use the spring-boot-starter-validation dependency to validate DTOs using annotations.

public class UserRequestDTO {
    @NotNull
    @Email
    private String email;
    
    @Size(min = 8)
    private String password;
}

Then, enable it in the Controller using @Valid:

public ResponseEntity<?> create(@Valid @RequestBody UserRequestDTO dto) { ... }

13. Global Exception Handling +

Instead of writing try-catch blocks in every controller method, use a global @ControllerAdvice. This acts as an interceptor for exceptions thrown anywhere in the application.

@RestControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(ResourceNotFoundException.class)
    public ResponseEntity<String> handleNotFound(ResourceNotFoundException ex) {
        return ResponseEntity.status(404).body(ex.getMessage());
    }
}

14. Service Layer Business Logic +

Controllers should be thin. They should only handle HTTP traffic. All business logic (calculations, transformations, database calls) belongs in the Service Layer.

@Service
public class PostService {
    public Post createPost(PostDTO dto) {
        // complex business logic here
        return repository.save(entity);
    }
}

// Controller injects the Service
@RestController
public class PostController {
    private final PostService postService; // injected via constructor
}

Learn to persist data efficiently using Spring Data JPA and Hibernate. This module covers everything from basic database configuration and entity creation to complex relational mappings (One-to-Many, Many-to-Many) and production-grade database migrations with Flyway.

15. Database Connection & Configuration +

Configure your database in application.properties. For local development, H2 (in-memory) is common. For production, use PostgreSQL or MySQL.

H2 Configuration (Dev):

spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
# Console at /h2-console
spring.h2.console.enabled=true

16. JPA Entities Fundamentals +

JPA allows you to map Java classes directly to database tables using annotations.

@Entity
@Table(name = "users")
public class User {
    
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(nullable = false, unique = true)
    private String email;

    // Getters and Setters...
}

17. Spring Data JPA Repositories +

No need to write SQL implementation code. Just extend JpaRepository.

public interface UserRepository extends JpaRepository<User, Long> {
    // Standard CRUD (save, delete, findById) are already included!
}

18. Derived Queries & JPQL +

Spring Data generates SQL based on method names (Derived Queries) or custom JPQL.

public interface UserRepository extends JpaRepository<User, Long> {
    
    // 1. Derived Query (Magic!)
    Optional<User> findByEmail(String email);

    // 2. Custom JPQL Query
    @Query("SELECT u FROM User u WHERE u.active = true")
    List<User> findAllActiveUsers();
}

19. Modeling Relationships: One-to-Many +

Handling parent-child relationships (e.g., One User has Many Posts).

@Entity
public class User {
    @OneToMany(mappedBy = "user", cascade = CascadeType.ALL)
    private List<Post> posts;
}

@Entity
public class Post {
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "user_id")
    private User user; // The Owning Side
}

20. Modeling Relationships: Many-to-Many +

A Post can have many Tags, and a Tag can belong to many Posts. This requires a Join Table.

@Entity
public class Post {
    @ManyToMany
    @JoinTable(
        name = "post_tags",
        joinColumns = @JoinColumn(name = "post_id"),
        inverseJoinColumns = @JoinColumn(name = "tag_id")
    )
    private Set<Tag> tags;
}

21. Database Migrations with Flyway +

In production, never rely on Hibernate to auto-create tables. Use Flyway for version control of your schema.

  1. Add flyway-core dependency.
  2. Create SQL files in src/main/resources/db/migration.

File Name: V1__Create_User_Table.sql

CREATE TABLE users (
    id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
    email VARCHAR(255) NOT NULL UNIQUE
);

This advanced module prepares your application for production. You will secure your API with Spring Security and JWT, ensure quality with comprehensive Unit and Integration testing, and finally, learn to containerize your application with Docker for deployment.

22. Introduction to Spring Security +

Spring Security is a filter-based framework. In Spring Boot 3, we configure it by defining a SecurityFilterChain bean rather than extending a configuration class.

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    http
        .csrf(csrf -> csrf.disable()) // Disable for stateless APIs
        .authorizeHttpRequests(auth -> auth
            .requestMatchers("/api/public/**").permitAll() // Open endpoints
            .anyRequest().authenticated() // Lock everything else
        )
        .httpBasic(Customizer.withDefaults());
    return http.build();
}

23. Stateless Authentication with JWT +

For REST APIs, we avoid Sessions/Cookies and use JSON Web Tokens (JWT). The server signs a token, and the client sends it in the Authorization header.

Generating a Token (using jjwt library):

public String generateToken(String username) {
    return Jwts.builder()
            .setSubject(username)
            .setIssuedAt(new Date())
            .setExpiration(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 10)) // 10 hours
            .signWith(Keys.hmacShaKeyFor(secretKey.getBytes()))
            .compact();
}

24. Authorization & Roles +

Once authenticated, we need to control who can do what. We use Role-Based Access Control (RBAC) via method-level security.

First, enable it in your config with @EnableMethodSecurity.

// Only Admins can delete users
@PreAuthorize("hasRole('ADMIN')")
@DeleteMapping("/{id}")
public void deleteUser(@PathVariable Long id) {
    service.delete(id);
}

// Current user can only edit their own profile
@PreAuthorize("#username == authentication.name")
@PutMapping("/{username}")
public void updateProfile(@PathVariable String username) { ... }

25. Unit Testing with JUnit 5 & Mockito +

Unit tests focus on a single class. We use Mockito to simulate external dependencies (like the Repository) so we don’t hit the real database.

@ExtendWith(MockitoExtension.class)
class UserServiceTest {
    @Mock UserRepository repository; // Mock the DB
    @InjectMocks UserService service; // Inject mock into Service

    @Test
    void shouldSaveUser() {
        User user = new User("test@example.com");
        when(repository.save(any(User.class))).thenReturn(user);
        
        User result = service.register(user);
        assertEquals("test@example.com", result.getEmail());
    }
}

26. Integration Testing +

Integration tests load the full Spring Context. We use @SpringBootTest and MockMvc to simulate HTTP requests against our controllers.

@SpringBootTest
@AutoConfigureMockMvc
class AuthControllerIntegrationTest {
    @Autowired MockMvc mockMvc;

    @Test
    void shouldReturnUnauthorizedForPublic() throws Exception {
        mockMvc.perform(get("/api/secure-data"))
               .andExpect(status().isForbidden());
    }
}

27. Observability with Spring Boot Actuator +

Actuator adds production-ready features like health checks and metrics. Add the spring-boot-starter-actuator dependency.

Configure exposed endpoints in properties:

# Expose health and metrics endpoints
management.endpoints.web.exposure.include=health,info,metrics
# Detailed health info
management.endpoint.health.show-details=always

Visit /actuator/health to see if your app (and DB) is up.

28. Dockerizing the Application +

To run your app anywhere, package it as a Docker container. Here is a standard Dockerfile for Spring Boot.

# Use a lightweight JDK base image
FROM eclipse-temurin:17-jdk-alpine
# Create a volume for temporary files
VOLUME /tmp
# Copy the built JAR file
COPY target/*.jar app.jar
# Run the app
ENTRYPOINT ["java","-jar","/app.jar"]

Build it with: docker build -t my-spring-app .

The capstone project, “The TechBlog Platform,” is where you will combine all the skills from the previous modules. You will build a complete, fully functional blogging engine from scratch, including user authentication, content management, and relational data.

Project Requirements

1. User Management

Registration, Login (JWT), and Profile management.

2. Blog Post CRUD

Create, Read, Update, and Delete (CRUD) posts.

3. Comments

Users can comment on posts (One-to-Many relationship).

4. Categories/Tags

Organize posts (Many-to-Many relationship).

5. Search

Filter posts by keyword or category.

6. Security

Only authors can edit their own posts; Admin can moderate all.

Project Phase Breakdown

The project is structured in a clear, step-by-step process, moving from design to deployment.

1

Modeling & Design

2

Service Layer

3

API Layer

4

Security

5

Deployment

Ace your next technical interview. Here are the most common Spring Boot questions asked by hiring managers, covering Core, Web, and Data topics.

1. What is the difference between Spring and Spring Boot? +

Spring Framework provides the core features (DI, IoC, AOP) but requires significant XML or Java configuration to set up (e.g., configuring a view resolver, transaction manager).

Spring Boot is an extension of Spring that focuses on “Convention over Configuration.” It provides:

  • Auto-configuration: Automatically configures beans based on classpath dependencies.
  • Embedded Server: Includes Tomcat/Jetty directly in the JAR (no external server installation needed).
  • Starters: Pre-packaged sets of dependencies to simplify build configuration.

2. Explain the @SpringBootApplication annotation. +

It is a convenience meta-annotation that combines three other annotations:

  • @Configuration: Indicates the class can contain bean definitions.
  • @EnableAutoConfiguration: Enables Spring Boot’s automatic configuration mechanism.
  • @ComponentScan: Scans the package (and sub-packages) for components like Controllers, Services, and Repositories.

3. What is Dependency Injection (DI)? +

DI is a design pattern used to implement IoC (Inversion of Control). It allows the creation of dependent objects outside of a class and provides those objects to a class in different ways.

Instead of a class instantiating its own dependencies (e.g., new Service()), Spring creates the instance (Bean) and “injects” it via the Constructor, Setter, or Field.

4. Difference between @Controller and @RestController? +

  • @Controller: Used for traditional Spring MVC. It usually returns a View (HTML page). To return JSON, you must add @ResponseBody to every method.
  • @RestController: A convenience annotation that combines @Controller and @ResponseBody. It is used for RESTful APIs where the return value is automatically serialized to JSON/XML in the HTTP response body.

5. What are Spring Bean Scopes? +

The scope defines the lifecycle and visibility of a bean:

  • Singleton (Default): Only one instance of the bean is created per Spring IoC container.
  • Prototype: A new instance is created every time the bean is requested.
  • Request: One instance per HTTP request (Web only).
  • Session: One instance per HTTP Session (Web only).

6. How does Spring Boot handle configuration? +

Spring Boot looks for a file named application.properties or application.yml in the src/main/resources folder. It loads these properties into the Spring Environment.

You can also use Profiles (e.g., application-dev.yml) to separate configuration for different environments (Dev, Test, Prod).

Leave a Reply

Your email address will not be published. Required fields are marked *