Spring Boot — Complete Feature Guide by Bhargav K // for Java developers
🌱 Section 1

What is Spring Boot?

Spring Boot = Spring Framework + sensible defaults + zero XML config + embedded server. It takes the power of the Spring ecosystem and removes all the setup pain so you can write business logic from minute one.

Plain Spring Framework required hundreds of lines of XML or Java config just to get a REST endpoint running. Spring Boot uses "convention over configuration" — it guesses what you need based on what's on your classpath and auto-configures everything.

Embedded Server
Tomcat/Jetty/Undertow built into the JAR. No deploying WAR files to external servers. Just java -jar app.jar and it starts on port 8080.
🔧
Auto-Configuration
Add spring-boot-starter-data-jpa to classpath → Spring auto-configures Hibernate, DataSource, EntityManager. You write zero boilerplate config.
📦
Starters
Curated dependency bundles. spring-boot-starter-web pulls in Spring MVC + Jackson + Tomcat. One dependency = everything needed.
🏭
Production-Ready
Actuator gives health checks, metrics, env inspection out of the box. Integrates with Prometheus, Grafana, AWS CloudWatch instantly.
A complete REST API in ~15 linesJava
@SpringBootApplication
public class MyApp {
  public static void main(String[] args) {
    SpringApplication.run(MyApp.class, args);
  }
}

@RestController
@RequestMapping("/api/users")
public class UserController {
  @GetMapping("/{id}")
  public User getUser(@PathVariable Long id) {
    return userService.findById(id);
  }
}

// That's it. Tomcat starts, REST endpoint is live. No XML. No web.xml.
⚙️ Section 2

Auto-Configuration

The magic behind Spring Boot. It scans your classpath and automatically creates beans you'd otherwise configure manually. Understanding this prevents "why did Spring create that?" confusion.

Auto-configuration works via @EnableAutoConfiguration (bundled inside @SpringBootApplication). Spring Boot has 130+ auto-configuration classes in spring-boot-autoconfigure.jar. Each one activates conditionally.

How conditional auto-config works under the hoodJava
// Spring Boot has classes like this internally:
@Configuration
@ConditionalOnClass(DataSource.class) // only if DataSource is on classpath
@ConditionalOnMissingBean(DataSource.class) // only if YOU haven't defined one
public class DataSourceAutoConfiguration {
  @Bean
  public DataSource dataSource() {
    return // creates HikariCP pool from application.properties
  }
}

// ✅ When you add 'spring-boot-starter-data-jpa':
// → DataSource, EntityManagerFactory, TransactionManager — all auto-created
// ✅ When you define your OWN @Bean DataSource — auto-config backs off
Debug auto-config: Add --debug flag or set debug=true in application.properties. Spring Boot prints a full report of which auto-configs activated and which were skipped (and why). Extremely useful when something isn't wiring up as expected.
📦 Section 3

Spring Boot Starters

Starters are curated dependency packs. Instead of figuring out which 8 libraries you need for JPA, you add one starter and get the right versions, all compatible.

StarterWhat it bringsUse when
starter-webSpring MVC, Tomcat, Jackson (JSON)Building REST APIs
starter-data-jpaHibernate, Spring Data JPA, HikariCPSQL database access
starter-securitySpring Security, auth filtersAuthentication & authorization
starter-testJUnit 5, Mockito, AssertJ, MockMvcTesting (always include)
starter-actuatorHealth, metrics, env endpointsProduction monitoring
starter-validationHibernate Validator (Bean Validation)Request body validation
starter-cacheSpring Cache abstraction + providersCaching (with Redis/Caffeine)
starter-amqpRabbitMQ / Spring AMQPMessage queues
🏗️ Section 4

IoC Container

Inversion of Control = you don't create objects, Spring creates and manages them. The container (ApplicationContext) is the heart of Spring. It creates beans, injects dependencies, manages lifecycle.

Without IoC, you'd write UserService svc = new UserService(new UserRepo(new DataSource(...))) everywhere. With IoC, you declare what you need and Spring wires the whole graph automatically.

@Component
Generic stereotype. Marks class as a Spring-managed bean. Spring will create one instance and make it available for injection.
@Service
Specialization of @Component for business logic layer. Semantically meaningful — same behavior but conveys intent.
@Repository
For data access layer. Same as @Component but also enables Spring's exception translation (converts SQL exceptions to Spring DataAccessException).
@Controller / @RestController
For web layer. @RestController = @Controller + @ResponseBody. Marks class as HTTP request handler.
@Configuration + @Bean
For manual bean creation. Use when you need to instantiate third-party classes that don't have @Component (e.g., RestTemplate, ModelMapper).
@ComponentScan
Tells Spring which packages to scan for @Component classes. @SpringBootApplication auto-scans the current package and all sub-packages.
💉 Section 5

Dependency Injection

DI is how Spring gives beans their dependencies. Three ways to inject: constructor (best), setter, or field. You should almost always use constructor injection.

3 Types of DI — and why constructor winsJava
// ✅ BEST — Constructor Injection (recommended)
@Service
public class OrderService {
  private final OrderRepository orderRepo;
  private final PaymentService paymentSvc;

  // Spring injects via constructor — no @Autowired needed in modern Spring
  public OrderService(OrderRepository repo, PaymentService pmt) {
    this.orderRepo = repo;
    this.paymentSvc = pmt;
  }
}

// ❌ AVOID — Field Injection (hard to test, hides dependencies)
@Autowired
private OrderRepository orderRepo; // bad — can't use final, can't mock easily
💡 Why constructor injection? Dependencies are immutable (final), explicit (you can see them in constructor), and easily testable — just new OrderService(mockRepo, mockPayment) in unit tests without needing Spring context.
🔄 Section 6

Bean Lifecycle & Scopes

Spring manages beans from creation to destruction. You can hook into lifecycle events. Bean scope defines how many instances get created.

Instantiate
Inject deps
@PostConstruct
In Use
@PreDestroy
Destroyed
ScopeInstances CreatedUse When
@Singleton (default)One per application contextStateless services, repositories — 99% of cases
@PrototypeNew instance every injectionStateful objects that shouldn't be shared
@RequestScopeOne per HTTP requestRequest-specific data (user context, request ID)
@SessionScopeOne per HTTP sessionUser session data (shopping cart, preferences)
Lifecycle hooks with @PostConstruct / @PreDestroyJava
@Service
public class CacheWarmupService {
  @PostConstruct // runs after bean is fully initialized
  public void warmupCache() {
    // load frequently-accessed data into cache on startup
    cacheRepo.loadProducts();
  }

  @PreDestroy // runs before bean is destroyed (app shutdown)
  public void flushCache() {
    cacheRepo.flush();
  }
}
🌐 Section 7

REST Controllers & Mappings

Spring MVC handles HTTP request routing, parameter binding, response serialization — all declaratively via annotations.

Complete REST Controller with all annotationsJava
@RestController
@RequestMapping("/api/products")
public class ProductController {

  // GET /api/products?category=electronics&page=0
  @GetMapping
  public Page<ProductDTO> getAll(
      @RequestParam(defaultValue = "0") int page,
      @RequestParam(required = false) String category) {
    return productService.findAll(page, category);
  }

  // GET /api/products/42
  @GetMapping("/{id}")
  public ResponseEntity<ProductDTO> getById(@PathVariable Long id) {
    return productService.findById(id)
      .map(ResponseEntity::ok)
      .orElse(ResponseEntity.notFound().build());
  }

  // POST /api/products with JSON body
  @PostMapping
  @ResponseStatus(HttpStatus.CREATED)
  public ProductDTO create(@Valid @RequestBody CreateProductRequest req) {
    return productService.create(req);
  }

  // DELETE /api/products/42
  @DeleteMapping("/{id}")
  @ResponseStatus(HttpStatus.NO_CONTENT)
  public void delete(@PathVariable Long id) {
    productService.delete(id);
  }
}
❌ Section 8

Global Exception Handling

Instead of try-catch in every controller, use @ControllerAdvice to handle exceptions globally and return consistent error responses.

Global Exception HandlerJava
@RestControllerAdvice
public class GlobalExceptionHandler {

  @ExceptionHandler(ResourceNotFoundException.class)
  @ResponseStatus(HttpStatus.NOT_FOUND)
  public ErrorResponse handleNotFound(ResourceNotFoundException ex) {
    return new ErrorResponse("NOT_FOUND", ex.getMessage());
  }

  @ExceptionHandler(MethodArgumentNotValidException.class)
  @ResponseStatus(HttpStatus.BAD_REQUEST)
  public ErrorResponse handleValidation(MethodArgumentNotValidException ex) {
    List<String> errors = ex.getBindingResult().getFieldErrors()
      .stream().map(FieldError::getDefaultMessage).toList();
    return new ErrorResponse("VALIDATION_FAILED", errors);
  }

  @ExceptionHandler(Exception.class)
  @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
  public ErrorResponse handleAll(Exception ex) {
    log.error("Unhandled exception", ex);
    return new ErrorResponse("INTERNAL_ERROR", "Something went wrong");
  }
}
✅ Section 9

Bean Validation

Validate request bodies declaratively with annotations. Add @Valid in controller, annotate your DTO fields, Spring handles the rest.

Validation annotations on DTOsJava
public class CreateUserRequest {
  @NotBlank(message = "Name is required")
  @Size(min=2, max=50)
  private String name;

  @NotBlank
  @Email(message = "Invalid email format")
  private String email;

  @NotNull
  @Min(18) @Max(120)
  private Integer age;

  @Pattern(regexp = "^[6-9]\\d{9}$", message = "Invalid Indian mobile number")
  private String phone;
}
🗄️ Section 10

JPA & Spring Data

Spring Data JPA eliminates 90% of boilerplate database code. Define an interface extending JpaRepository and get 50+ methods for free. Write zero SQL for common operations.

Entity, Repository & Query MethodsJava
// Entity — maps to DB table
@Entity
@Table(name = "users")
public class User {
  @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
  private Long id;

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

  @Enumerated(EnumType.STRING)
  private UserStatus status;

  @OneToMany(mappedBy = "user", cascade = CascadeType.ALL)
  private List<Order> orders;
}

// Repository — Spring generates ALL implementations
public interface UserRepository extends JpaRepository<User, Long> {
  // Spring parses method names → generates SQL
  Optional<User> findByEmail(String email);
  List<User> findByStatusAndAgeGreaterThan(UserStatus status, int age);
  Page<User> findByCityOrderByCreatedAtDesc(String city, Pageable p);

  @Query("SELECT u FROM User u WHERE u.email LIKE %:domain")
  List<User> findByEmailDomain(@Param("domain") String domain);
}
🔒 Section 11

@Transactional

Wraps a method in a database transaction. If any exception occurs, everything rolls back atomically. One of Spring's most important features.

Transaction managementJava
@Service
public class TransferService {

  @Transactional // entire method = one transaction
  public void transferMoney(Long fromId, Long toId, BigDecimal amount) {
    accountRepo.debit(fromId, amount); // step 1
    accountRepo.credit(toId, amount); // step 2
    // if step 2 throws → step 1 auto-rolls back!
  }

  // Read-only for better performance (no dirty-checking, read replicas)
  @Transactional(readOnly = true)
  public List<Account> getAllAccounts() { ... }

  // Requires a NEW transaction even if called within existing one
  @Transactional(propagation = Propagation.REQUIRES_NEW)
  public void logAuditEvent(String event) { ... }
}
⚙️ Section 12

Configuration — application.properties & @Value

Externalize all config from code. Spring Boot reads application.properties (or .yml), maps values to beans, and makes everything overridable via environment variables.

application.propertiesProperties
# Server
server.port=8080
spring.application.name=my-api

# Database (auto-configures HikariCP + JPA)
spring.datasource.url=jdbc:postgresql://localhost:5432/mydb
spring.datasource.username=postgres
spring.datasource.password=${DB_PASSWORD} # env variable
spring.jpa.hibernate.ddl-auto=validate

# Custom app config
app.jwt.secret=${JWT_SECRET}
app.jwt.expiry-minutes=60
app.max-file-size-mb=10
@ConfigurationProperties — type-safe config bindingJava
// Better than @Value for groups of related config
@ConfigurationProperties(prefix = "app.jwt")
@Component
public class JwtProperties {
  private String secret;
  private int expiryMinutes;
  // getters/setters or use @Value + @ConfigurationPropertiesScan with records
}

// Inject and use:
public class JwtService {
  private final JwtProperties jwtProps; // injected
  public String generateToken(String sub) {
    return Jwts.builder()
      .setExpiration(...jwtProps.getExpiryMinutes()...)
      .signWith(jwtProps.getSecret())
      .compact();
  }
}
🌍 Section 13

Spring Profiles

Profiles let you have different configurations for dev, test, and prod. Spring loads the right config file based on the active profile.

Multi-environment config filesProperties
application.properties → base config (all envs)
application-dev.properties → dev overrides (H2 in-memory DB)
application-prod.properties → prod overrides (RDS PostgreSQL)

--- application-dev.properties ---
spring.datasource.url=jdbc:h2:mem:testdb
spring.jpa.show-sql=true
logging.level.root=DEBUG

--- application-prod.properties ---
spring.datasource.url=jdbc:postgresql://${RDS_HOST}:5432/mydb
spring.jpa.show-sql=false
logging.level.root=WARN

--- Activate profile ---
$ java -jar app.jar --spring.profiles.active=prod
$ SPRING_PROFILES_ACTIVE=prod java -jar app.jar
🔐 Section 14

Spring Security + JWT

Spring Security handles authentication and authorization. Modern approach uses JWT tokens — stateless, works perfectly with microservices and cloud deployments.

SecurityConfig — JWT-based stateless securityJava
@Configuration
@EnableWebSecurity
public class SecurityConfig {

  @Bean
  public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    return http
      .csrf(AbstractHttpConfigurer::disable) // JWT = stateless, no CSRF needed
      .sessionManagement(s -> s.sessionCreationPolicy(STATELESS))
      .authorizeHttpRequests(auth -> auth
        .requestMatchers("/api/auth/**").permitAll() // login/register open
        .requestMatchers("/api/admin/**").hasRole("ADMIN")
        .anyRequest().authenticated() // everything else needs JWT
      )
      .addFilterBefore(jwtFilter, UsernamePasswordAuthenticationFilter.class)
      .build();
  }
}
📊 Section 15

Spring Boot Actuator

Actuator adds production-ready monitoring endpoints to your app instantly. Critical for Kubernetes health checks, AWS ALB, and integrating with Prometheus/Grafana.

EndpointURLUse
/actuator/healthGETK8s liveness/readiness & ALB health check
/actuator/metricsGETJVM memory, GC, HTTP stats — for Prometheus
/actuator/infoGETApp version, build info
/actuator/envGETAll config properties (secure in prod)
/actuator/loggersGET/POSTChange log level at runtime without restart
/actuator/prometheusGETPrometheus-formatted metrics (add micrometer)
⚡ Section 16

Async Processing & @Scheduled

Run tasks asynchronously (non-blocking) or on a schedule — built directly into Spring Boot.

@Async + @ScheduledJava
@SpringBootApplication
@EnableAsync
@EnableScheduling
public class MyApp { ... }

@Service
public class EmailService {
  @Async // runs in separate thread — doesn't block HTTP response
  public CompletableFuture<Void> sendWelcomeEmail(String email) {
    // takes 2 seconds but caller returns immediately
    mailSender.send(email);
    return CompletableFuture.completedFuture(null);
  }
}

@Component
public class ReportJob {
  @Scheduled(cron = "0 0 8 * * MON-FRI") // 8 AM weekdays
  public void generateDailyReport() {
    reportService.generate();
  }

  @Scheduled(fixedDelay = 30000) // every 30 seconds
  public void syncWithExternalService() { ... }
}
📍 Spring Boot Mental Model
@SpringBootApplication → starts everything
IoC Container → creates and wires all beans
@Service / @Repository / @Controller → declare beans
Constructor injection → preferred DI method
@RestController + @GetMapping → handle HTTP
@Transactional → atomic DB operations
JpaRepository → zero-boilerplate DB access
application.properties + Profiles → environment config
@ControllerAdvice → centralized error handling
Actuator → production health + metrics