Spring Boot
Java Backend Development — Complete Notes
IoC • REST APIs • JPA • Security • Microservices
From Setup to Production — Beginner to Job-Ready
Spring Boot 3.x • Java 17+
Java Backend with
Spring Boot
Comprehensive Study Notes for Students & Developers
Spring Core REST API Spring Data JPA Spring Security Maven/Gradle Microservices Docker
Pluto Academy
[Link] • @[Link] • MERN Stack & Java Backend Courses
■ Java Spring Boot — Complete Notes Pluto Academy • [Link]
■ Table of Contents
1. Introduction to Spring & Spring Boot
2. Project Setup — Spring Initializr & Project Structure
3. Dependency Injection & IoC Container
4. Spring Beans — Lifecycle, Scopes & Annotations
5. Building REST APIs with Spring MVC
6. Request Handling — Path Variables, Query Params, Request Body
7. Spring Data JPA & Hibernate
8. Database Configuration & Relationships
9. Exception Handling in Spring Boot
10. Spring Boot Validation
11. Spring Security — Authentication & Authorization
12. JWT — JSON Web Token Authentication
13. Spring Boot Testing
14. Spring Boot Actuator & Monitoring
15. Configuration — [Link] / YAML / Profiles
16. Spring Boot with Lombok
17. Pagination & Sorting
18. File Upload & Download
19. Spring Boot Scheduling & Async
20. Microservices with Spring Boot
21. Docker & Deployment
22. Key Annotations Cheat Sheet
Page 2 • Spring Boot 3.x • Java 17+
■ Java Spring Boot — Complete Notes Pluto Academy • [Link]
1. Introduction to Spring & Spring Boot
The Spring Framework is a comprehensive, lightweight Java framework for building enterprise applications. It
solves common problems like object creation, dependency management, database access, and web
development through a consistent, non-invasive programming model.
Spring Framework Spring Boot
Full enterprise framework. Requires extensive XML or Opinionated wrapper over Spring. Auto-configures
annotation configuration. Manual setup of every everything based on classpath. Embedded server
component (DataSource, Dispatcher Servlet, etc.). (Tomcat) — no WAR deployment needed.
Maximum control, maximum boilerplate. Production-ready in minutes.
What Spring Boot Gives You Out of the Box
Feature Description
Auto-Configuration Detects JARs on classpath and configures beans automatically
Embedded Server Tomcat / Jetty / Undertow embedded — just run the JAR
Starter
spring-boot-starter-web pulls Spring MVC + Jackson + Tomcat
Dependencies
Spring Initializr [Link] — generate project in seconds
Actuator Production metrics, health checks, info endpoints built-in
DevTools Hot reload during development
Externalized
[Link] / .yml / environment variables / profiles
Config
Spring Ecosystem Overview
Module Purpose
Spring Core IoC container, Dependency Injection — the heart of everything
Spring MVC Model-View-Controller web framework for REST & web apps
Spring Data JPA Abstraction over JPA/Hibernate — repositories & query methods
Spring Security Authentication, Authorization, OAuth2, JWT
Spring Cloud Microservices tools — service discovery, config server, gateway
Spring Batch Batch processing — read/process/write large data volumes
Spring WebFlux Reactive, non-blocking web framework (alternative to Spring MVC)
Spring AMQP Messaging with RabbitMQ
Spring Kafka Messaging with Apache Kafka
Page 3 • Spring Boot 3.x • Java 17+
■ Java Spring Boot — Complete Notes Pluto Academy • [Link]
2. Project Setup — Spring Initializr & Project Structure
Creating a Spring Boot Project
Spring Initializr ([Link]) is the fastest way to bootstrap a project. Select: Project (Maven/Gradle),
Language (Java), Spring Boot version, Group/Artifact, Java version, and Dependencies.
# Popular starter dependencies to add:
Spring Web → spring-boot-starter-web (REST APIs)
Spring Data JPA → spring-boot-starter-data-jpa
H2 Database → com.h2database:h2 (in-memory dev DB)
MySQL Driver → mysql:mysql-connector-java
Spring Security → spring-boot-starter-security
Spring Boot DevTools → spring-boot-devtools (hot reload)
Lombok → [Link]:lombok
Spring Boot Actuator → spring-boot-starter-actuator
Validation → spring-boot-starter-validation
Standard Project Structure (Maven)
my-app/
■■■ src/
■ ■■■ main/
■ ■ ■■■ java/com/example/myapp/
■ ■ ■ ■■■ [Link] ← @SpringBootApplication (entry point)
■ ■ ■ ■■■ controller/
■ ■ ■ ■ ■■■ [Link] ← REST endpoints (@RestController)
■ ■ ■ ■■■ service/
■ ■ ■ ■ ■■■ [Link] ← Interface
■ ■ ■ ■ ■■■ [Link] ← @Service implementation
■ ■ ■ ■■■ repository/
■ ■ ■ ■ ■■■ [Link] ← @Repository / JpaRepository
■ ■ ■ ■■■ model/ (or entity/)
■ ■ ■ ■ ■■■ [Link] ← @Entity (JPA / Hibernate)
Page 4 • Spring Boot 3.x • Java 17+
■ Java Spring Boot — Complete Notes Pluto Academy • [Link]
■ ■ ■ ■■■ dto/
■ ■ ■ ■ ■■■ [Link] ← Data Transfer Object
■ ■ ■ ■■■ exception/
■ ■ ■ ■ ■■■ [Link]
■ ■ ■ ■■■ config/
■ ■ ■ ■ ■■■ [Link]
■ ■ ■ ■■■ util/
■ ■ ■■■ resources/
■ ■ ■■■ [Link] ← or [Link]
■ ■ ■■■ [Link]
■ ■ ■■■ static/ templates/
■ ■■■ test/
■ ■■■ java/com/example/myapp/
■ ■■■ [Link]
■■■ [Link] ← Maven build file
■■■ Dockerfile
// [Link] — Main entry point
@SpringBootApplication
// = @Configuration + @EnableAutoConfiguration + @ComponentScan
public class MyAppApplication {
public static void main(String[] args) {
[Link]([Link], args);
■ Follow the layered architecture strictly: Controller → Service → Repository → Database. Never let Controller talk
directly to Repository.
Page 5 • Spring Boot 3.x • Java 17+
■ Java Spring Boot — Complete Notes Pluto Academy • [Link]
3. Dependency Injection & IoC Container
Inversion of Control (IoC): Instead of your code creating its own dependencies, the Spring IoC container
creates and manages objects for you. You declare what you need — Spring provides it. Dependency Injection
(DI) is Spring's mechanism for implementing IoC.
Three Types of Dependency Injection
// ■ WITHOUT Spring — you manually create objects (tight coupling)
class OrderService {
private PaymentService paymentService = new PaymentService(); // bad
// ■■ 1. CONSTRUCTOR INJECTION ■ (RECOMMENDED — mandatory deps)
@Service
public class OrderService {
private final PaymentService paymentService; // final = immutable
private final EmailService emailService;
// Spring injects via constructor automatically
public OrderService(PaymentService paymentService, EmailService emailService) {
[Link] = paymentService;
[Link] = emailService;
// ■■ 2. SETTER INJECTION (optional dependencies)
@Service
public class ReportService {
private CacheService cacheService;
@Autowired
public void setCacheService(CacheService cacheService) {
[Link] = cacheService;
Page 6 • Spring Boot 3.x • Java 17+
■ Java Spring Boot — Complete Notes Pluto Academy • [Link]
// ■■ 3. FIELD INJECTION (convenient but avoid in production)
@Service
public class ProductService {
@Autowired // Spring injects directly into the field
private ProductRepository productRepository;
Why Constructor Injection is Best
Aspect Constructor Injection ■ Field Injection ■
Immutability Fields can be final Cannot be final
Testing Easy — pass mocks via constructor Needs reflection / @InjectMocks
Circular
Detected at startup (fail-fast) Detected only at runtime
dependency
Null safety Guaranteed not null Can be null if Spring fails
Lombok @RequiredAr
Works perfectly Not applicable
gsConstructor
■ With Lombok @RequiredArgsConstructor, you don't even need to write the constructor! Spring detects the single
constructor and injects automatically.
Page 7 • Spring Boot 3.x • Java 17+
■ Java Spring Boot — Complete Notes Pluto Academy • [Link]
4. Spring Beans — Lifecycle, Scopes & Annotations
A Spring Bean is any object that is managed by the Spring IoC container. Spring creates, wires, manages, and
destroys beans based on configuration.
Bean Scopes
Scope Description Default?
singleton One instance per Spring container — shared everywhere. Default scope. ■ Yes
prototype New instance created every time the bean is requested. No
request One instance per HTTP request. Web applications only. No
session One instance per HTTP session. Web applications only. No
application One instance per ServletContext (entire app lifecycle). No
websocket One instance per WebSocket session. No
// Singleton (default) — most common
@Service // @Service is @Component with semantic meaning
public class UserService { } // → singleton by default
// Explicit scope
@Component
@Scope("prototype") // or ConfigurableBeanFactory.SCOPE_PROTOTYPE
public class ShoppingCart { }
// Declaring beans in @Configuration class
@Configuration
public class AppConfig {
@Bean // method name = bean name by default
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
@Bean
@Primary // preferred when multiple beans of same type exist
public DataSource primaryDataSource() { ... }
Page 8 • Spring Boot 3.x • Java 17+
■ Java Spring Boot — Complete Notes Pluto Academy • [Link]
@Bean
@Qualifier("backupDS")
public DataSource backupDataSource() { ... }
// Bean lifecycle hooks
@Component
public class DatabaseInitializer {
@PostConstruct // called after bean is created and wired
public void init() {
[Link]("Bean initialized — run startup logic here");
@PreDestroy // called before bean is destroyed
public void cleanup() {
[Link]("Bean destroyed — close connections here");
Page 9 • Spring Boot 3.x • Java 17+
■ Java Spring Boot — Complete Notes Pluto Academy • [Link]
5. Building REST APIs with Spring MVC
Spring MVC is the web framework inside Spring Boot. @RestController = @Controller + @ResponseBody. It
automatically serializes Java objects to JSON (via Jackson) and back.
HTTP Methods → CRUD Mapping
HTTP
Annotation Purpose Success Status
Method
GET @GetMapping Retrieve resource(s) 200 OK
POST @PostMapping Create new resource 201 Created
PUT @PutMapping Replace entire resource 200 OK
PATCH @PatchMapping Partial update 200 OK
DELETE @DeleteMapping Remove resource 204 No Content
Full CRUD Controller — User Management API
@RestController
@RequestMapping("/api/v1/users")
public class UserController {
private final UserService userService;
// Constructor injection (Lombok @RequiredArgsConstructor replaces this)
public UserController(UserService userService) {
[Link] = userService;
// GET all users
@GetMapping
public ResponseEntity> getAllUsers() {
return [Link]([Link]());
// GET single user
@GetMapping("/{id}")
public ResponseEntity getUserById(@PathVariable Long id) {
Page 10 • Spring Boot 3.x • Java 17+
■ Java Spring Boot — Complete Notes Pluto Academy • [Link]
return [Link]([Link](id));
// POST — create user
@PostMapping
public ResponseEntity createUser(@Valid @RequestBody CreateUserRequest req) {
UserDTO created = [Link](req);
URI location = [Link]("/api/v1/users/" + [Link]());
return [Link](location).body(created);
// PUT — update user
@PutMapping("/{id}")
public ResponseEntity updateUser(
@PathVariable Long id,
@Valid @RequestBody UpdateUserRequest req) {
return [Link]([Link](id, req));
// DELETE user
@DeleteMapping("/{id}")
public ResponseEntity deleteUser(@PathVariable Long id) {
[Link](id);
return [Link]().build();
// GET with query parameters
@GetMapping("/search")
public ResponseEntity> searchUsers(
@RequestParam(defaultValue = "") String name,
@RequestParam(defaultValue = "0") int page,
@RequestParam(defaultValue = "10") int size) {
Page 11 • Spring Boot 3.x • Java 17+
■ Java Spring Boot — Complete Notes Pluto Academy • [Link]
return [Link]([Link](name, page, size));
Page 12 • Spring Boot 3.x • Java 17+
■ Java Spring Boot — Complete Notes Pluto Academy • [Link]
6. Request Handling — Parameters, Body & Response
Extracting Data from Requests
// @PathVariable — from URL path: /users/42
@GetMapping("/users/{id}")
public User getUser(@PathVariable Long id) { ... }
// Multiple path variables: /orders/5/items/3
@GetMapping("/orders/{orderId}/items/{itemId}")
public Item getItem(@PathVariable Long orderId, @PathVariable Long itemId) { ... }
// @RequestParam — from query string: /users?name=Alice&active;=true
@GetMapping("/users")
public List search(
@RequestParam String name,
@RequestParam(required = false) Boolean active,
@RequestParam(defaultValue = "0") int page) { ... }
// @RequestBody — JSON body → Java object
@PostMapping("/users")
public User create(@RequestBody CreateUserRequest request) { ... }
// @RequestHeader — read HTTP headers
@GetMapping("/profile")
public User profile(@RequestHeader("Authorization") String token) { ... }
// @CookieValue — read cookies
@GetMapping("/session")
public String session(@CookieValue("SESSION_ID") String sessionId) { ... }
// HttpServletRequest — raw access to request
@GetMapping("/info")
public String info(HttpServletRequest request) {
Page 13 • Spring Boot 3.x • Java 17+
■ Java Spring Boot — Complete Notes Pluto Academy • [Link]
return [Link](); // client IP
ResponseEntity — Full Control Over HTTP Response
// Custom status + body + headers
return ResponseEntity
.status([Link]) // 201
.header("X-Custom-Header", "value")
.body(user);
// Common shortcuts
[Link](body) // 200 + body
[Link](locationUri).body(body) // 201 + Location header
[Link]().build() // 204 empty
[Link]().build() // 404 empty
[Link]().body(errorMsg) // 400 + body
// Generic type for cleaner code
public ResponseEntity> getUser(@PathVariable Long id) {
UserDTO user = [Link](id);
return [Link]([Link](user));
// Standard API Response wrapper (good practice)
public class ApiResponse {
private boolean success;
private String message;
private T data;
private LocalDateTime timestamp;
public static ApiResponse success(T data) {
return new ApiResponse<>(true, "Success", data, [Link]());
Page 14 • Spring Boot 3.x • Java 17+
■ Java Spring Boot — Complete Notes Pluto Academy • [Link]
Page 15 • Spring Boot 3.x • Java 17+
■ Java Spring Boot — Complete Notes Pluto Academy • [Link]
7. Spring Data JPA & Hibernate
JPA (Java Persistence API) is the standard specification for ORM in Java. Hibernate is the most popular JPA
implementation. Spring Data JPA wraps Hibernate and provides repositories — eliminating boilerplate CRUD
code entirely.
Entity Class — Mapping Java to Database
@Entity
@Table(name = "users",
uniqueConstraints = @UniqueConstraint(columnNames = "email"))
@Data // Lombok: getters, setters, equals, hashCode, toString
@NoArgsConstructor // Lombok: required by JPA
@AllArgsConstructor // Lombok
@Builder // Lombok: builder pattern
public class User {
@Id
@GeneratedValue(strategy = [Link])
private Long id;
@Column(nullable = false, length = 100)
private String name;
@Column(nullable = false, unique = true)
private String email;
@Column(nullable = false)
private String password;
@Enumerated([Link]) // store as 'ADMIN' not 0
@Column(nullable = false)
private Role role = [Link];
@Column(nullable = false, updatable = false)
@CreationTimestamp // Hibernate: auto-set on insert
Page 16 • Spring Boot 3.x • Java 17+
■ Java Spring Boot — Complete Notes Pluto Academy • [Link]
private LocalDateTime createdAt;
@UpdateTimestamp // Hibernate: auto-update on update
private LocalDateTime updatedAt;
@Column(name = "is_active", nullable = false)
private boolean active = true;
enum Role { USER, ADMIN, MODERATOR }
JpaRepository — Zero Boilerplate CRUD
@Repository
public interface UserRepository extends JpaRepository {
// JpaRepository gives you for FREE:
// save(entity), saveAll(), findById(id), findAll(), deleteById(id),
// delete(entity), count(), existsById(id) and more
// ■■ Derived Query Methods (no SQL needed — Spring generates queries)
Optional findByEmail(String email);
List findByActiveTrue();
List findByNameContainingIgnoreCase(String name);
List findByRoleOrderByNameAsc(Role role);
boolean existsByEmail(String email);
long countByRole(Role role);
void deleteByEmail(String email);
// ■■ Custom JPQL query
@Query("SELECT u FROM User u WHERE [Link] = :email AND [Link] = true")
Optional findActiveByEmail(@Param("email") String email);
// ■■ Native SQL query
@Query(value = "SELECT * FROM users WHERE created_at > :date",
Page 17 • Spring Boot 3.x • Java 17+
■ Java Spring Boot — Complete Notes Pluto Academy • [Link]
nativeQuery = true)
List findUsersCreatedAfter(@Param("date") LocalDateTime date);
// ■■ Modifying query (UPDATE/DELETE)
@Modifying
@Transactional
@Query("UPDATE User u SET [Link] = false WHERE [Link] = :id")
int deactivateUser(@Param("id") Long id);
// ■■ Pagination
Page findByRole(Role role, Pageable pageable);
Service Layer — Transactional Business Logic
@Service
@Transactional // all methods in this class are transactional by default
@RequiredArgsConstructor // Lombok — generates constructor for final fields
public class UserServiceImpl implements UserService {
private final UserRepository userRepository;
private final PasswordEncoder passwordEncoder;
@Override
@Transactional(readOnly = true) // optimization: no write lock
public List findAll() {
return [Link]()
.stream()
.map(this::toDTO)
.collect([Link]());
@Override
@Transactional(readOnly = true)
Page 18 • Spring Boot 3.x • Java 17+
■ Java Spring Boot — Complete Notes Pluto Academy • [Link]
public UserDTO findById(Long id) {
return [Link](id)
.map(this::toDTO)
.orElseThrow(() -> new ResourceNotFoundException("User", id));
@Override
public UserDTO create(CreateUserRequest req) {
if ([Link]([Link]()))
throw new DuplicateEmailException([Link]());
User user = [Link]()
.name([Link]())
.email([Link]())
.password([Link]([Link]()))
.role([Link])
.build();
return toDTO([Link](user));
private UserDTO toDTO(User user) {
return new UserDTO([Link](), [Link](), [Link](), [Link]());
Page 19 • Spring Boot 3.x • Java 17+
■ Java Spring Boot — Complete Notes Pluto Academy • [Link]
8. Database Configuration & JPA Relationships
[Link] — Database Config
# ■■ MySQL Configuration
[Link]=jdbc:mysql://localhost:3306/mydb?useSSL=false&serverTimezone;=UTC
[Link]=root
[Link]=secret
[Link]-class-name=[Link]
# ■■ JPA / Hibernate
[Link]-auto=update
# Options: none | validate | update | create | create-drop
# update — safe for dev (adds columns, doesn't drop)
# create-drop — drops and recreates on start/stop (use for tests)
# validate — production: verify schema matches entities
[Link]-sql=true # log SQL statements
[Link].format_sql=true
[Link]=[Link].MySQL8Dialect
# ■■ Connection Pool (HikariCP — default in Spring Boot)
[Link]-pool-size=10
[Link]-idle=2
[Link]-timeout=20000
# ■■ H2 In-Memory (for development / tests)
[Link]=jdbc:h2:mem:testdb
[Link]-class-name=[Link]
[Link]=true # access at /h2-console
JPA Relationships
// ■■ @OneToMany / @ManyToOne (Most Common)
Page 20 • Spring Boot 3.x • Java 17+
■ Java Spring Boot — Complete Notes Pluto Academy • [Link]
// One Department → Many Employees
@Entity
public class Department {
@Id @GeneratedValue(strategy = [Link])
private Long id;
private String name;
@OneToMany(mappedBy = "department", cascade = [Link], fetch = [Link])
@JsonManagedReference // prevents infinite recursion in JSON
private List employees = new ArrayList<>();
@Entity
public class Employee {
@Id @GeneratedValue(strategy = [Link])
private Long id;
private String name;
@ManyToOne(fetch = [Link])
@JoinColumn(name = "department_id") // FK column in employees table
@JsonBackReference
private Department department;
// ■■ @ManyToMany
@Entity
public class Student {
@ManyToMany(cascade = {[Link], [Link]})
@JoinTable(name = "student_course",
joinColumns = @JoinColumn(name = "student_id"),
inverseJoinColumns = @JoinColumn(name = "course_id"))
private Set courses = new HashSet<>();
Page 21 • Spring Boot 3.x • Java 17+
■ Java Spring Boot — Complete Notes Pluto Academy • [Link]
// ■■ @OneToOne
@Entity
public class User {
@OneToOne(cascade = [Link])
@JoinColumn(name = "profile_id", referencedColumnName = "id")
private UserProfile profile;
Annotation DB Relationship Example
@OneToOne One row ↔ One row User ↔ UserProfile
@OneToMany One row ↔ Many rows Department → Employees
@ManyToOne Many rows → One row Employee → Department (FK side)
Many rows ↔ Many rows
@ManyToMany Student ↔ Course
(join table)
■■ Always use [Link] for @OneToMany and @ManyToMany to avoid loading entire graphs. Use JOIN
FETCH in JPQL when you need the data.
Page 22 • Spring Boot 3.x • Java 17+
■ Java Spring Boot — Complete Notes Pluto Academy • [Link]
9. Exception Handling in Spring Boot
// ■■ Custom exception classes
public class ResourceNotFoundException extends RuntimeException {
public ResourceNotFoundException(String resource, Object id) {
super(resource + " not found with id: " + id);
public class DuplicateEmailException extends RuntimeException {
public DuplicateEmailException(String email) {
super("Email already in use: " + email);
// ■■ Error Response DTO
@Data @AllArgsConstructor
public class ErrorResponse {
private int status;
private String error;
private String message;
private LocalDateTime timestamp;
private String path;
// ■■ Global Exception Handler
@RestControllerAdvice // = @ControllerAdvice + @ResponseBody
public class GlobalExceptionHandler {
@ExceptionHandler([Link])
public ResponseEntity handleNotFound(
ResourceNotFoundException ex, HttpServletRequest request) {
Page 23 • Spring Boot 3.x • Java 17+
■ Java Spring Boot — Complete Notes Pluto Academy • [Link]
ErrorResponse err = new ErrorResponse(
404, "Not Found", [Link](),
[Link](), [Link]());
return [Link](HttpStatus.NOT_FOUND).body(err);
@ExceptionHandler([Link])
public ResponseEntity> handleValidation(
MethodArgumentNotValidException ex) {
Map errors = new HashMap<>();
[Link]().getFieldErrors()
.forEach(e -> [Link]([Link](), [Link]()));
return [Link]().body(errors);
@ExceptionHandler([Link])
public ResponseEntity handleDuplicate(
DuplicateEmailException ex, HttpServletRequest request) {
ErrorResponse err = new ErrorResponse(
409, "Conflict", [Link](),
[Link](), [Link]());
return [Link]([Link]).body(err);
@ExceptionHandler([Link]) // catch-all
public ResponseEntity handleGeneral(
Exception ex, HttpServletRequest request) {
ErrorResponse err = new ErrorResponse(
500, "Internal Server Error", "An unexpected error occurred",
[Link](), [Link]());
return [Link]().body(err);
Page 24 • Spring Boot 3.x • Java 17+
■ Java Spring Boot — Complete Notes Pluto Academy • [Link]
Page 25 • Spring Boot 3.x • Java 17+
■ Java Spring Boot — Complete Notes Pluto Academy • [Link]
10. Spring Boot Validation
// Dependency: spring-boot-starter-validation
// ■■ Request DTO with validation annotations
public class CreateUserRequest {
@NotBlank(message = "Name is required")
@Size(min = 2, max = 100, message = "Name must be 2-100 chars")
private String name;
@NotBlank(message = "Email is required")
@Email(message = "Invalid email format")
private String email;
@NotBlank(message = "Password is required")
@Size(min = 8, message = "Password must be at least 8 characters")
@Pattern(regexp = "^(?=.*[A-Z])(?=.*[0-9]).+$",
message = "Password must contain uppercase letter and digit")
private String password;
@NotNull(message = "Age is required")
@Min(value = 18, message = "Must be at least 18")
@Max(value = 120, message = "Invalid age")
private Integer age;
@NotNull
@Future(message = "Expiry date must be in the future")
private LocalDate expiryDate;
// ■■ Trigger validation with @Valid on controller parameter
@PostMapping
public ResponseEntity create(@Valid @RequestBody CreateUserRequest req) {
Page 26 • Spring Boot 3.x • Java 17+
■ Java Spring Boot — Complete Notes Pluto Academy • [Link]
return [Link](uri).body([Link](req));
Annotation Purpose
@NotNull Field must not be null
@NotBlank String must not be null or empty/whitespace
@NotEmpty Collection/String must not be empty (null allowed)
@Size(min,max) String/Collection length between min and max
@Min(value) / @Max(value) Numeric value constraints
@Email Valid email format
@Pattern(regexp) Must match regular expression
@Positive / @Negative Number must be positive/negative
@Past / @Future Date must be in past/future
@DecimalMin / @DecimalMax Decimal number range
@Valid Trigger cascade validation on nested objects
Page 27 • Spring Boot 3.x • Java 17+
■ Java Spring Boot — Complete Notes Pluto Academy • [Link]
11. Spring Security — Authentication & Authorization
Spring Security provides comprehensive authentication and authorization support. It works as a chain of filters
intercepting every HTTP request before it reaches your controllers.
Security Configuration (Spring Boot 3.x / Spring Security 6+)
@Configuration
@EnableWebSecurity
@EnableMethodSecurity // enables @PreAuthorize, @PostAuthorize
@RequiredArgsConstructor
public class SecurityConfig {
private final JwtAuthenticationFilter jwtFilter;
private final UserDetailsService userDetailsService;
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
return http
.csrf(csrf -> [Link]()) // disable CSRF for REST APIs
.sessionManagement(session ->
[Link]([Link]))
.authorizeHttpRequests(auth -> auth
.requestMatchers("/api/auth/**").permitAll() // public
.requestMatchers("/api/admin/**").hasRole("ADMIN")
.requestMatchers([Link], "/api/products/**").permitAll()
.anyRequest().authenticated() // everything else: auth
.addFilterBefore(jwtFilter, [Link])
.build();
@Bean
public PasswordEncoder passwordEncoder() {
Page 28 • Spring Boot 3.x • Java 17+
■ Java Spring Boot — Complete Notes Pluto Academy • [Link]
return new BCryptPasswordEncoder(12); // strength 12 (default 10)
@Bean
public AuthenticationManager authenticationManager(
AuthenticationConfiguration config) throws Exception {
return [Link]();
// UserDetailsService — load user from DB for authentication
@Service
@RequiredArgsConstructor
public class UserDetailsServiceImpl implements UserDetailsService {
private final UserRepository userRepository;
@Override
public UserDetails loadUserByUsername(String email) {
return [Link](email)
.orElseThrow(() -> new UsernameNotFoundException("User not found: " + email));
// User entity must implement UserDetails, or wrap it:
// return new [Link](
// [Link](), [Link](),
// [Link](new SimpleGrantedAuthority("ROLE_" + [Link]())));
Method-Level Security
@RestController
@RequestMapping("/api/users")
public class UserController {
Page 29 • Spring Boot 3.x • Java 17+
■ Java Spring Boot — Complete Notes Pluto Academy • [Link]
@GetMapping
@PreAuthorize("hasRole('ADMIN')") // only ADMIN can call this
public List getAll() { ... }
@GetMapping("/me")
@PreAuthorize("isAuthenticated()")
public UserDTO getMyProfile(Authentication auth) {
return [Link]([Link]());
@DeleteMapping("/{id}")
@PreAuthorize("hasRole('ADMIN') or #id == [Link]")
public ResponseEntity delete(@PathVariable Long id) { ... }
Page 30 • Spring Boot 3.x • Java 17+
■ Java Spring Boot — Complete Notes Pluto Academy • [Link]
12. JWT — JSON Web Token Authentication
JWT is a compact, self-contained token for securely transmitting information between parties. Structure:
[Link] (Base64 encoded, dot-separated).
JWT Flow — Login → Token → API Access
2. Server Creates 3. Client Stores 5. Server Validates
1. Login 4. API Request
JWT Token JWT
Verifies signature &
POST /api/auth/login Signs token with secret localStorage or Header: Authorization:
expiry, lets request
{email, password} key, returns JWT sessionStorage or cookie Bearer
through
JWT Utility Class & Filter
// Dependency: [Link]:jjwt-api, jjwt-impl, jjwt-jackson
@Component
public class JwtUtil {
@Value("${[Link]}")
private String secretKey;
@Value("${[Link]}") // default: 24 hours in ms
private long jwtExpiration;
private SecretKey getSigningKey() {
return [Link]([Link](secretKey));
public String generateToken(UserDetails userDetails) {
return [Link]()
.subject([Link]())
.issuedAt(new Date())
.expiration(new Date([Link]() + jwtExpiration))
.claim("role", [Link]())
.signWith(getSigningKey())
.compact();
Page 31 • Spring Boot 3.x • Java 17+
■ Java Spring Boot — Complete Notes Pluto Academy • [Link]
public String extractUsername(String token) {
return [Link]().verifyWith(getSigningKey()).build()
.parseSignedClaims(token).getPayload().getSubject();
public boolean isTokenValid(String token, UserDetails userDetails) {
final String username = extractUsername(token);
return [Link]([Link]()) && !isExpired(token);
private boolean isExpired(String token) {
return [Link]().verifyWith(getSigningKey()).build()
.parseSignedClaims(token).getPayload()
.getExpiration().before(new Date());
// JWT Filter — runs on every request
@Component @RequiredArgsConstructor
public class JwtAuthenticationFilter extends OncePerRequestFilter {
private final JwtUtil jwtUtil;
private final UserDetailsService userDetailsService;
@Override
protected void doFilterInternal(HttpServletRequest req,
HttpServletResponse res, FilterChain chain) throws ServletException, IOException {
String authHeader = [Link]("Authorization");
if (authHeader == null || ) {
[Link](req, res); return;
Page 32 • Spring Boot 3.x • Java 17+
■ Java Spring Boot — Complete Notes Pluto Academy • [Link]
String token = [Link](7);
String email = [Link](token);
if (email != null && [Link]().getAuthentication() == null) {
UserDetails userDetails = [Link](email);
if ([Link](token, userDetails)) {
UsernamePasswordAuthenticationToken authToken =
new UsernamePasswordAuthenticationToken(
userDetails, null, [Link]());
[Link](new WebAuthenticationDetailsSource().buildDetails(req));
[Link]().setAuthentication(authToken);
[Link](req, res);
Page 33 • Spring Boot 3.x • Java 17+
■ Java Spring Boot — Complete Notes Pluto Academy • [Link]
13. Spring Boot Testing
Test Type Annotation Loads Best For
@ExtendWith([Link]
Unit Test Nothing Service/Util logic in isolation
s)
Slice Test @WebMvcTest([Link]) Web layer only Controller + validation
Slice Test @DataJpaTest JPA layer + H2 Repository queries
Integration @SpringBootTest Full app context End-to-end flow
// ■■ Unit Test — Service with Mockito
@ExtendWith([Link])
class UserServiceTest {
@Mock private UserRepository userRepository;
@Mock private PasswordEncoder passwordEncoder;
@InjectMocks private UserServiceImpl userService;
@Test
void findById_existingUser_returnsDTO() {
// Arrange
User user = [Link]().id(1L).name("Alice").email("a@[Link]").build();
when([Link](1L)).thenReturn([Link](user));
// Act
UserDTO result = [Link](1L);
// Assert
assertThat([Link]()).isEqualTo("Alice");
verify(userRepository, times(1)).findById(1L);
@Test
void findById_nonExistingUser_throwsException() {
when([Link](99L)).thenReturn([Link]());
Page 34 • Spring Boot 3.x • Java 17+
■ Java Spring Boot — Complete Notes Pluto Academy • [Link]
assertThatThrownBy(() -> [Link](99L))
.isInstanceOf([Link]);
// ■■ Controller Slice Test with MockMvc
@WebMvcTest([Link])
class UserControllerTest {
@Autowired private MockMvc mockMvc;
@MockBean private UserService userService;
@Autowired private ObjectMapper objectMapper;
@Test
void getUser_returnsUser() throws Exception {
UserDTO dto = new UserDTO(1L, "Alice", "a@[Link]", [Link]);
when([Link](1L)).thenReturn(dto);
[Link](get("/api/v1/users/1")
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andExpect(jsonPath("$.name").value("Alice"))
.andExpect(jsonPath("$.email").value("a@[Link]"));
@Test
void createUser_invalidRequest_returns400() throws Exception {
CreateUserRequest req = new CreateUserRequest("", "bad-email", "weak", 15);
[Link](post("/api/v1/users")
.contentType(MediaType.APPLICATION_JSON)
.content([Link](req)))
.andExpect(status().isBadRequest());
Page 35 • Spring Boot 3.x • Java 17+
■ Java Spring Boot — Complete Notes Pluto Academy • [Link]
Page 36 • Spring Boot 3.x • Java 17+
■ Java Spring Boot — Complete Notes Pluto Academy • [Link]
14. Spring Boot Actuator & Monitoring
# [Link]
[Link]=health,info,metrics,env,beans
[Link]-details=always
[Link]=true
[Link]=My Spring App
[Link]=1.0.0
[Link]=Backend API
Endpoint URL What It Shows
/health /actuator/health App health, DB status, disk space
/info /actuator/info App info (version, description)
/metrics /actuator/metrics JVM memory, HTTP requests, threads
/env /actuator/env All environment properties
/beans /actuator/beans All Spring beans registered
/mappings /actuator/mappings All URL → handler mappings
/loggers /actuator/loggers View/change log levels at runtime
/httptrace /actuator/httptrace Last 100 HTTP request/response traces
Page 37 • Spring Boot 3.x • Java 17+
■ Java Spring Boot — Complete Notes Pluto Academy • [Link]
15. Configuration — Properties, YAML & Profiles
# [Link] — YAML format (hierarchical, cleaner)
server:
port: 8080
servlet:
context-path: /api
spring:
application:
name: my-app
datasource:
url: jdbc:mysql://localhost:3306/mydb
username: root
password: ${DB_PASSWORD} # reads from environment variable
jpa:
hibernate:
ddl-auto: update
show-sql: false
jwt:
secret: ${JWT_SECRET}
expiration: 86400000
# ■■ Spring Profiles
# [Link] → activated with [Link]=dev
# [Link] → activated with [Link]=prod
# Activate profile:
# 1. [Link]: [Link]=dev
# 2. JVM arg: -[Link]=prod
# 3. Environment variable: SPRING_PROFILES_ACTIVE=prod
Page 38 • Spring Boot 3.x • Java 17+
■ Java Spring Boot — Complete Notes Pluto Academy • [Link]
# ■■ Reading custom properties
@Value("${[Link]}")
private String jwtSecret;
# ■■ Binding a group of properties to a class
@ConfigurationProperties(prefix = "[Link]")
@Data @Component
public class MailProperties {
private String host;
private int port;
private String username;
Page 39 • Spring Boot 3.x • Java 17+
■ Java Spring Boot — Complete Notes Pluto Academy • [Link]
16. Spring Boot with Lombok
Annotation Generates
@Getter / @Setter Getter and/or setter methods for all fields
@Data @Getter + @Setter + @ToString + @EqualsAndHashCode + @RequiredArgsConstructor
@NoArgsConstructor No-argument constructor (required by JPA)
@AllArgsConstructor Constructor with all fields
@RequiredArgsConstructor Constructor for all final and @NonNull fields (DI-friendly)
@Builder Builder pattern — [Link]().field(val).build()
@Slf4j private static final Logger log = [Link](...)
@ToString toString() method (exclude = {"password"})
@EqualsAndHashCode equals() and hashCode() based on fields
@Value (Lombok) Immutable class — all fields private final, @Getter, no setters
@NonNull Null check with NullPointerException in constructor/setter
// Before Lombok — 50+ lines of boilerplate
// After Lombok — clean and readable
@Entity
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class Product {
@Id @GeneratedValue(strategy = [Link])
private Long id;
private String name;
private Double price;
private Integer stock;
// Usage with @Builder:
Product p = [Link]()
Page 40 • Spring Boot 3.x • Java 17+
■ Java Spring Boot — Complete Notes Pluto Academy • [Link]
.name("Laptop").price(49999.0).stock(10).build();
// @Slf4j for logging
@Service @Slf4j
public class OrderService {
public void placeOrder(Order order) {
[Link]("Placing order for user: {}", [Link]());
[Link]("Order details: {}", order);
[Link]("Payment failed for order: {}", [Link]());
Page 41 • Spring Boot 3.x • Java 17+
■ Java Spring Boot — Complete Notes Pluto Academy • [Link]
17. Pagination & Sorting
// Repository
public interface ProductRepository extends JpaRepository {
Page findByCategory(String category, Pageable pageable);
// Service
public Page getProducts(int page, int size, String sortBy, String dir) {
Sort sort = [Link]("desc")
? [Link](sortBy).descending()
: [Link](sortBy).ascending();
Pageable pageable = [Link](page, size, sort);
return [Link](pageable).map(this::toDTO);
// Controller
@GetMapping
public ResponseEntity> getProducts(
@RequestParam(defaultValue = "0") int page,
@RequestParam(defaultValue = "10") int size,
@RequestParam(defaultValue = "name") String sortBy,
@RequestParam(defaultValue = "asc") String direction) {
return [Link]([Link](page, size, sortBy, direction));
// API call: GET /api/products?page=0&size;=10&sortBy;=price&direction;=desc
// Page response includes:
// content: [...], totalElements: 100, totalPages: 10,
// size: 10, number: 0 (current page), first: true, last: false
Page 42 • Spring Boot 3.x • Java 17+
■ Java Spring Boot — Complete Notes Pluto Academy • [Link]
18. File Upload & Download
# [Link]
[Link]-file-size=10MB
[Link]-request-size=10MB
[Link]-dir=./uploads
// File Upload Controller
@RestController
@RequestMapping("/api/files")
@RequiredArgsConstructor
public class FileController {
@Value("${[Link]-dir}")
private String uploadDir;
@PostMapping("/upload")
public ResponseEntity> upload(
@RequestParam("file") MultipartFile file) throws IOException {
if ([Link]()) throw new IllegalArgumentException("File is empty");
String fileName = [Link]() + "_" + [Link]();
Path uploadPath = [Link](uploadDir);
if () [Link](uploadPath);
[Link]([Link](), [Link](fileName),
StandardCopyOption.REPLACE_EXISTING);
return [Link]([Link](
"fileName", fileName,
"fileType", [Link](),
"size", [Link]([Link]())));
Page 43 • Spring Boot 3.x • Java 17+
■ Java Spring Boot — Complete Notes Pluto Academy • [Link]
@GetMapping("/download/{fileName}")
public ResponseEntity download(@PathVariable String fileName) throws IOException {
Path filePath = [Link](uploadDir).resolve(fileName).normalize();
Resource resource = new UrlResource([Link]());
if (![Link]()) throw new ResourceNotFoundException("File", fileName);
String contentType = [Link](filePath);
return [Link]()
.contentType([Link](contentType))
.header(HttpHeaders.CONTENT_DISPOSITION,
"attachment; filename=\"" + [Link]() + "\"")
.body(resource);
Page 44 • Spring Boot 3.x • Java 17+
■ Java Spring Boot — Complete Notes Pluto Academy • [Link]
19. Spring Boot Scheduling & Async
// Enable scheduling in main class or config
@SpringBootApplication
@EnableScheduling
@EnableAsync
public class MyAppApplication { ... }
// ■■ @Scheduled — Cron Jobs
@Service @Slf4j
public class ScheduledTasks {
// Fixed rate: every 5 seconds (regardless of task duration)
@Scheduled(fixedRate = 5000)
public void heartbeat() {
[Link]("Heartbeat: {}", [Link]());
// Fixed delay: 5 seconds AFTER previous task completes
@Scheduled(fixedDelay = 5000)
public void cleanupTempFiles() { ... }
// Cron expression: second minute hour day month weekday
@Scheduled(cron = "0 0 2 * * ?") // every day at 2:00 AM
public void dailyReport() { ... }
@Scheduled(cron = "0 0 8 * * MON-FRI") // weekdays at 8 AM
public void sendDailyEmails() { ... }
@Scheduled(cron = "0 */30 * * * ?") // every 30 minutes
public void syncData() { ... }
// ■■ @Async — non-blocking background tasks
Page 45 • Spring Boot 3.x • Java 17+
■ Java Spring Boot — Complete Notes Pluto Academy • [Link]
@Service
public class EmailService {
@Async // runs in a separate thread — caller doesn't wait
public CompletableFuture sendWelcomeEmail(String email) {
// Simulate email sending (slow I/O operation)
[Link](2000);
[Link]("Email sent to: {}", email);
return [Link](true);
// In service — fire and forget
[Link]([Link]()); // returns immediately
// Or await the result
CompletableFuture future = [Link](email);
boolean result = [Link](5, [Link]); // wait max 5s
■ Always configure a custom thread pool for @Async tasks to avoid exhausting the default pool: @Bean public
Executor asyncExecutor() { return new ThreadPoolTaskExecutor(); }
Page 46 • Spring Boot 3.x • Java 17+
■ Java Spring Boot — Complete Notes Pluto Academy • [Link]
20. Microservices with Spring Boot
Microservices architecture decomposes an application into small, independently deployable services. Spring
Cloud provides tools to build production-grade microservices ecosystems.
Component Technology Purpose
Service Registry Eureka Server (Spring Cloud) Services register & discover each other
API Gateway Spring Cloud Gateway Single entry point; routing, auth, rate limiting
Config Server Spring Cloud Config Centralized configuration for all services
Load Balancer Spring Cloud LoadBalancer Client-side load balancing
Circuit Breaker Resilience4j Fault tolerance — fallback when service fails
Inter-service RestTemplate / WebClient /
HTTP calls between services
Comms FeignClient
Distributed
Micrometer + Zipkin Trace requests across services
Tracing
Message Queue RabbitMQ / Kafka Async communication between services
// ■■ Eureka Client — register service for discovery
@SpringBootApplication
@EnableEurekaClient
public class UserServiceApplication { ... }
# [Link] — User Service
[Link]: user-service
[Link]: [Link]
// ■■ FeignClient — declarative REST client (like an interface)
@FeignClient(name = "order-service") // name = service registered in Eureka
public interface OrderServiceClient {
@GetMapping("/api/orders/user/{userId}")
List getOrdersByUserId(@PathVariable Long userId);
// Use in service like a normal bean:
@Service @RequiredArgsConstructor
Page 47 • Spring Boot 3.x • Java 17+
■ Java Spring Boot — Complete Notes Pluto Academy • [Link]
public class UserService {
private final OrderServiceClient orderServiceClient;
public UserWithOrdersDTO getUserWithOrders(Long userId) {
UserDTO user = findById(userId);
List orders = [Link](userId);
return new UserWithOrdersDTO(user, orders);
// ■■ Circuit Breaker with Resilience4j
@CircuitBreaker(name = "orderService", fallbackMethod = "getOrdersFallback")
public List getOrdersByUserId(Long userId) {
return [Link](userId);
public List getOrdersFallback(Long userId, Exception ex) {
[Link]("Order service down. Returning empty list for user {}", userId);
return [Link](); // graceful degradation
Page 48 • Spring Boot 3.x • Java 17+
■ Java Spring Boot — Complete Notes Pluto Academy • [Link]
21. Docker & Deployment
# ■■ Dockerfile for Spring Boot app
FROM eclipse-temurin:17-jdk-alpine AS build
WORKDIR /app
COPY [Link] .
COPY src ./src
RUN ./mvnw package -DskipTests
FROM eclipse-temurin:17-jre-alpine
WORKDIR /app
COPY --from=build /app/target/*.jar [Link]
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "[Link]"]
# ■■ Build & run Docker image
docker build -t my-spring-app .
docker run -d -p 8080:8080 --name my-app \
-e SPRING_PROFILES_ACTIVE=prod \
-e DB_PASSWORD=secret \
my-spring-app
# ■■ [Link] — app + MySQL + Redis
version: '3.8'
services:
app:
build: .
ports:
- '8080:8080'
environment:
- SPRING_PROFILES_ACTIVE=prod
- DB_URL=jdbc:mysql://db:3306/mydb
Page 49 • Spring Boot 3.x • Java 17+
■ Java Spring Boot — Complete Notes Pluto Academy • [Link]
- DB_USERNAME=root
- DB_PASSWORD=secret
depends_on:
- db
- redis
db:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: secret
MYSQL_DATABASE: mydb
volumes:
- mysql-data:/var/lib/mysql
ports:
- '3306:3306'
redis:
image: redis:7-alpine
ports:
- '6379:6379'
volumes:
mysql-data:
# ■■ Commands
docker-compose up -d # start all services
docker-compose down # stop and remove containers
docker-compose logs -f app # follow app logs
Page 50 • Spring Boot 3.x • Java 17+
■ Java Spring Boot — Complete Notes Pluto Academy • [Link]
22. Key Annotations Cheat Sheet
■ Core / Component Scanning ■ Dependency Injection
@SpringBootApplica Main class: enables auto-config, @Autowired Inject Spring bean (prefer constructor
tion component scan, bean registration injection)
@Component Generic Spring-managed bean @Qualifier("name") Specify which bean to inject when
multiple exist
@Service @Component for service layer
(business logic) @Primary Default bean when multiple exist of
same type
@Repository @Component for DAO layer (exception
translation) @Value("${prop}") Inject a value from
[Link]
@Controller @Component for MVC controller
(returns views) @Scope("prototype" Change bean scope from singleton
)
@RestController @Controller + @ResponseBody
(returns JSON)
@Configuration Java config class that defines @Bean
methods
@Bean Declares a method that returns a
Spring-managed bean
■ Web / REST ■■ JPA / Persistence
@RequestMapping("/ Map URL path to class or method @Entity Marks class as a JPA database entity
path")
@Table(name='...') Specifies table name and constraints
@GetMapping / HTTP method shorthand
@Id Primary key field
@PostMapping /
@PutMapping / @GeneratedValue(ID Auto-generated primary key
@DeleteMapping / ENTITY)
@PatchMapping
@Column Map field to column (nullable, length,
@PathVariable Extract {id} from URL path unique)
@RequestParam Extract ?name=value from query string @OneToMany / JPA relationship types
@ManyToOne /
@RequestBody Deserialize JSON request body to Java
@ManyToMany /
object
@OneToOne
@ResponseBody Serialize return value to JSON
@JoinColumn(name=' Foreign key column definition
@ResponseStatus(Ht Set default HTTP response status ...')
[Link])
@Transactional Wraps method in database transaction
@CrossOrigin Enable CORS for the controller or
method
■ Security ■■ Scheduling / Async
@EnableWebSecurity Enable Spring Security @EnableScheduling Enable scheduled task support
@EnableMethodSecur Enable @PreAuthorize / @Scheduled(cron='. Cron-based or fixed-rate scheduled
ity @PostAuthorize ..') task
@PreAuthorize("exp Method-level auth check BEFORE @EnableAsync Enable async task support
ression") execution
@Async Run method in separate thread
@PostAuthorize("ex Method-level auth check AFTER
pression") execution
Page 51 • Spring Boot 3.x • Java 17+
■ Java Spring Boot — Complete Notes Pluto Academy • [Link]
■ Validation ■ Testing
@Valid Trigger validation on @RequestBody or @SpringBootTest Load full application context for
method parameter integration tests
@NotNull / Null/empty/blank checks @WebMvcTest(Contro Load only web layer (mock service
@NotBlank / [Link]) layer)
@NotEmpty
@DataJpaTest Load JPA layer with H2 in-memory
@Size(min,max) String/collection length constraint database
@Email / @Pattern Format validation @MockBean Create and register mock in Spring
context
@Min / @Max Numeric range
@Mock Create Mockito mock (unit tests without
Spring context)
@InjectMocks Inject @Mock dependencies into test
subject
■ You are now ready to build production Java backends!
Build real projects: Student Management System → E-Commerce API → Social Media Backend
Every concept in these notes should be implemented — not just read.
[Link] • @[Link] • MERN Stack & Java Backend Courses
Page 52 • Spring Boot 3.x • Java 17+