Java Spring Boot: Building Microservices

June 20, 2025

Java Spring Boot: Building Microservices

Spring Boot has revolutionized Java development by providing a convention-over-configuration approach to building enterprise applications. Let's explore how to create microservices with Spring Boot.

Why Spring Boot?

Spring Boot offers:

  • Auto-configuration: Minimal setup required
  • Embedded servers: No need for external Tomcat/Jetty
  • Production-ready features: Health checks, metrics, monitoring
  • Microservices support: Easy to build and deploy independently

Project Setup

Create a new Spring Boot project using Spring Initializr:

# Using Spring CLI
spring init --dependencies=web,jpa,h2,actuator my-microservice
cd my-microservice

Or add dependencies to your pom.xml:

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>
    <dependency>
        <groupId>com.h2database</groupId>
        <artifactId>h2</artifactId>
        <scope>runtime</scope>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>
</dependencies>

Creating a RESTful Service

Let's build a simple Product microservice:

// Product.java - Entity class
@Entity
@Table(name = "products")
public class Product {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    @Column(nullable = false)
    private String name;
    
    @Column(nullable = false)
    private BigDecimal price;
    
    private String description;
    
    // Constructors, getters, and setters
    public Product() {}
    
    public Product(String name, BigDecimal price, String description) {
        this.name = name;
        this.price = price;
        this.description = description;
    }
    
    // Getters and setters...
}

Repository Layer

Create a JPA repository:

// ProductRepository.java
@Repository
public interface ProductRepository extends JpaRepository<Product, Long> {
    
    List<Product> findByNameContainingIgnoreCase(String name);
    
    List<Product> findByPriceBetween(BigDecimal minPrice, BigDecimal maxPrice);
    
    @Query("SELECT p FROM Product p WHERE p.price < :maxPrice")
    List<Product> findCheapProducts(@Param("maxPrice") BigDecimal maxPrice);
}

Service Layer

Implement business logic:

// ProductService.java
@Service
@Transactional
public class ProductService {
    
    private final ProductRepository productRepository;
    
    public ProductService(ProductRepository productRepository) {
        this.productRepository = productRepository;
    }
    
    public List<Product> getAllProducts() {
        return productRepository.findAll();
    }
    
    public Optional<Product> getProductById(Long id) {
        return productRepository.findById(id);
    }
    
    public Product createProduct(Product product) {
        return productRepository.save(product);
    }
    
    public Product updateProduct(Long id, Product productDetails) {
        return productRepository.findById(id)
            .map(product -> {
                product.setName(productDetails.getName());
                product.setPrice(productDetails.getPrice());
                product.setDescription(productDetails.getDescription());
                return productRepository.save(product);
            })
            .orElseThrow(() -> new ProductNotFoundException("Product not found with id: " + id));
    }
    
    public void deleteProduct(Long id) {
        productRepository.deleteById(id);
    }
}

REST Controller

Create RESTful endpoints:

// ProductController.java
@RestController
@RequestMapping("/api/products")
@CrossOrigin(origins = "*")
public class ProductController {
    
    private final ProductService productService;
    
    public ProductController(ProductService productService) {
        this.productService = productService;
    }
    
    @GetMapping
    public ResponseEntity<List<Product>> getAllProducts() {
        List<Product> products = productService.getAllProducts();
        return ResponseEntity.ok(products);
    }
    
    @GetMapping("/{id}")
    public ResponseEntity<Product> getProductById(@PathVariable Long id) {
        return productService.getProductById(id)
            .map(product -> ResponseEntity.ok(product))
            .orElse(ResponseEntity.notFound().build());
    }
    
    @PostMapping
    public ResponseEntity<Product> createProduct(@Valid @RequestBody Product product) {
        Product savedProduct = productService.createProduct(product);
        return ResponseEntity.status(HttpStatus.CREATED).body(savedProduct);
    }
    
    @PutMapping("/{id}")
    public ResponseEntity<Product> updateProduct(@PathVariable Long id, 
                                               @Valid @RequestBody Product product) {
        try {
            Product updatedProduct = productService.updateProduct(id, product);
            return ResponseEntity.ok(updatedProduct);
        } catch (ProductNotFoundException e) {
            return ResponseEntity.notFound().build();
        }
    }
    
    @DeleteMapping("/{id}")
    public ResponseEntity<Void> deleteProduct(@PathVariable Long id) {
        productService.deleteProduct(id);
        return ResponseEntity.noContent().build();
    }
}

Configuration

Configure your application properties:

# application.properties
server.port=8080
spring.application.name=product-service

# Database configuration
spring.datasource.url=jdbc:h2:mem:productdb
spring.datasource.driver-class-name=org.h2.Driver
spring.h2.console.enabled=true

# JPA configuration
spring.jpa.hibernate.ddl-auto=create-drop
spring.jpa.show-sql=true

# Actuator endpoints
management.endpoints.web.exposure.include=health,info,metrics

Exception Handling

Add global exception handling:

// GlobalExceptionHandler.java
@ControllerAdvice
public class GlobalExceptionHandler {
    
    @ExceptionHandler(ProductNotFoundException.class)
    public ResponseEntity<ErrorResponse> handleProductNotFound(ProductNotFoundException ex) {
        ErrorResponse error = new ErrorResponse("PRODUCT_NOT_FOUND", ex.getMessage());
        return ResponseEntity.status(HttpStatus.NOT_FOUND).body(error);
    }
    
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ResponseEntity<ErrorResponse> handleValidationException(MethodArgumentNotValidException ex) {
        ErrorResponse error = new ErrorResponse("VALIDATION_ERROR", "Invalid input data");
        return ResponseEntity.badRequest().body(error);
    }
}

Running the Application

Start your Spring Boot application:

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

Testing Your Microservice

Test your endpoints:

# Get all products
curl http://localhost:8080/api/products

# Create a product
curl -X POST http://localhost:8080/api/products \
  -H "Content-Type: application/json" \
  -d '{"name":"Laptop","price":999.99,"description":"Gaming laptop"}'

# Health check
curl http://localhost:8080/actuator/health

Next Steps

To build production-ready microservices, consider:

  • Service Discovery: Eureka, Consul
  • API Gateway: Spring Cloud Gateway
  • Configuration Management: Spring Cloud Config
  • Circuit Breakers: Hystrix, Resilience4j
  • Distributed Tracing: Zipkin, Jaeger
  • Containerization: Docker, Kubernetes

Spring Boot provides an excellent foundation for building scalable, maintainable microservices!