Spring Boot

Spring Boot for Microservices

Spring Boot is the most popular Java framework for building microservices. It provides auto-configuration (opinionated defaults that get your application running with minimal setup), embedded servers (Tomcat, Jetty, or Undertow), and a comprehensive ecosystem of starters for databases, messaging, security, monitoring, and cloud-native patterns. This article covers building a RESTful microservice with Spring Boot.

Setting Up a Spring Boot Application

A Spring Boot application starts with the @SpringBootApplication annotation on a main class. This single annotation combines @Configuration, @EnableAutoConfiguration, and @ComponentScan. The SpringApplication.run() call bootstraps the application, starts the embedded web server, and initializes the Spring context. By convention, the main class is placed in the root package so that component scanning covers all subpackages automatically.

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class UserServiceApplication {
    public static void main(String[] args) {
        SpringApplication.run(UserServiceApplication.class, args);
    }
}

Building REST Controllers

Spring MVC controllers are annotated with @RestController and define request mappings with @GetMapping, @PostMapping, @PutMapping, and @DeleteMapping. Request data is bound to method parameters using @PathVariable (URL parameters), @RequestParam (query parameters), and @RequestBody (JSON body). Spring Boot automatically serializes Java objects to JSON using Jackson when the spring-boot-starter-web dependency is included.

@RestController
@RequestMapping("/api/users")
public class UserController {
    private final UserService userService;
    public UserController(UserService userService) {
        this.userService = userService;
    }
    @GetMapping
    public List<User> getAllUsers() {
        return userService.findAll();
    }
    @GetMapping("/{id}")
    public User getUser(@PathVariable Long id) {
        return userService.findById(id)
            .orElseThrow(() -> new ResponseStatusException(NOT_FOUND));
    }
    @PostMapping
    @ResponseStatus(CREATED)
    public User createUser(@Valid @RequestBody CreateUserRequest request) {
        return userService.create(request);
    }
}

Data Access with Spring Data JPA

Spring Data JPA eliminates boilerplate data access code. You define a repository interface that extends JpaRepository, and Spring automatically provides implementations for CRUD operations, pagination, sorting, and custom query methods derived from method names. For example, findByEmail(String email) generates a query automatically. For complex queries, use @Query with JPQL or native SQL.

Configuration and Actuator

Externalized configuration with application.yml lets you change behavior without recompiling. The Actuator module provides production-ready monitoring endpoints: /actuator/health for readiness probes, /actuator/metrics for JVM metrics, and /actuator/prometheus for Prometheus scraping. Spring Boot’s convention-over-configuration philosophy and embedded server mean you run java -jar app.jar and your service is live — no external servlet container needed.

Testing and Production-Ready Configuration

Spring Boot’s testing support includes @SpringBootTest (full application context), @WebMvcTest (controller layer only with mocked services), and @DataJpaTest (JPA repository testing with in-memory database). Test slices load only the relevant beans, making tests fast and focused. The @TestConfiguration annotation provides test-specific bean overrides. For integration tests, Testcontainers library spins up PostgreSQL, Redis, or Kafka containers via Docker. In production, configure Spring Boot with externalized configuration: application.yml for defaults, environment variables for secrets, and cloud config servers for distributed configuration. The spring-boot-maven-plugin packages the application as a fat JAR with an embedded server, and the layered JAR feature (Spring Boot 2.3+) optimizes Docker image layers for faster rebuilds—dependencies change less frequently than application code, so they can be cached separately in Docker layer caching.

# application.yml with environment-specific overrides
spring:
  datasource:
    url: ${DB_URL}
    username: ${DB_USER}
    password: ${DB_PASS}
  jpa:
    hibernate:
      ddl-auto: validate  # Never 'create-drop' in production
    show-sql: false
logging:
  level:
    root: WARN
    com.myapp: INFO

Reactive Programming with WebFlux

For high-concurrency applications, Spring WebFlux provides a reactive alternative to the Servlet stack. WebFlux uses Project Reactor (Mono/Flux) for non-blocking, backpressure-aware data flows. A reactive endpoint returns Mono or Flux instead of the actual data—the framework handles thread scheduling automatically. WebFlux shines for applications with many concurrent connections where thread-per-request would require excessive memory. Spring Data R2DBC provides reactive database access. For most microservices (under 100 concurrent requests), the traditional Servlet stack is simpler and performs adequately.

Spring Boot Configuration and Properties

Spring Boot’s externalized configuration supports multiple sources in priority order: command-line arguments, JNDI attributes, system properties, environment variables, application-{profile}.properties, and application.properties. This hierarchy allows overriding defaults per environment without touching code. The @ConfigurationProperties annotation binds entire property groups to typed Java objects with validation—no more scattered @Value annotations. Spring Boot Actuator exposes the /actuator/configprops endpoint showing the resolved configuration for debugging what value was actually applied. The spring.profiles.active property activates environment-specific configuration. Spring Cloud Config provides a centralized configuration server for distributed systems, and Spring Vault integrates with HashiCorp Vault for secrets management. The Relaxed Binding feature allows flexible property naming (kebab-case, camelCase, underscore) matching environment variables that use uppercase with underscores.

Spring Boot Testing Best Practices

Spring Boot integration testing starts with @SpringBootTest which loads the full application context. For faster tests, slice annotations load only relevant beans: @WebMvcTest loads controllers and MVC infrastructure, @DataJpaTest loads JPA repositories, @RestClientTest loads REST client beans. Testcontainers provides disposable PostgreSQL, Redis, and Kafka containers for integration tests that match your production database version. @MockBean and @SpyBean replace real beans with mocks. The MockMvc API tests controllers with HTTP assertions. For reactive applications, WebTestClient replaces MockMvc. WireMock simulates external HTTP services. The @TestConfiguration annotation adds test-specific beans without modifying production configuration. Spring Boot tests should follow the test pyramid: many unit tests (fast, isolated), fewer integration tests (context loading), and few end-to-end tests (full system).

Leave a Reply

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