Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

Building Microservices with Spring Boot and Service Discovery

Tech May 8 3

Microservices Architecture Overview

Microservices architecture structures an application as a collection of loosely coupled services, where each service implements a specific business capability and can be developed, deployed, and scaled independently. Spring Boot provides comprehensive support for building microservices in the Java ecosystem, including service registration, discovery, and inter-service communication.

Setting Up Service Discovery with Eureka

Service discovery allows microservices to locate each other without hardcoding network locations. Netflix Eureka serves as a central registry where services can register themselves and query for other available services.

Eureka Server Configuration

package com.example.eurekaserver;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;

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

Add the following configuration in application.yml:

server:
  port: 8761

eureka:
  instance:
    hostname: localhost
  client:
    register-with-eureka: false
    fetch-registry: false

Service Provider Implementation

The service provider registers with Eureka and exposes REST endpoints that other services can consume.

package com.example.productservice;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

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

@RestController
class ProductController {
    
    @GetMapping("/products/{id}")
    public Product getProduct(@PathVariable Long id) {
        return new Product(id, "Sample Product", 99.99);
    }
    
    record Product(Long id, String name, double price) {}
}

Configure the provider in application.yml:

server:
  port: 8081

spring:
  application:
    name: product-service

eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/

Service Consumer Implementation

The consumer uses the discovered service through a load-balanced client.

package com.example.orderservice;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestClient;

@SpringBootApplication
@EnableDiscoveryClient
public class OrderServiceApplication {
    public static void main(String[] args) {
        SpringApplication.run(OrderServiceApplication.class, args);
    }
    
    @Bean
    RestClient.Builder restClientBuilder() {
        return RestClient.builder();
    }
}
package com.example.orderservice;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestClient;

@RestController
class OrderController {
    
    private final RestClient restClient;
    
    public OrderController(RestClient.Builder builder) {
        this.restClient = builder.baseUrl("http://product-service").build();
    }
    
    @GetMapping("/orders/{orderId}")
    public OrderResponse getOrder(@PathVariable Long orderId) {
        var product = restClient.get()
            .uri("/products/1")
            .retrieve()
            .body(Product.class);
        
        return new OrderResponse(orderId, product);
    }
    
    record Product(Long id, String name, double price) {}
    record OrderResponse(Long orderId, Product product) {}
}

Key Benefits of Microservices

Independent Deployment: Services can be deployed and updated without coordinating with other teams or services.

Technology Flexibility: Teams can choose different programming languages, frameworks, or databases for individual services based on specific requirements.

Scalability: Each service scales independently based on its own load characteristics, optimizing resource utilization.

Fault Isolation: Failure in one service doesn't cascade to other services, improving overall system resilience.

Configuraton Files Summary

For a complete microservices setup, ensure each service has proper Eureka client configuration pointing to the registry server. The Eureka server itself should run independently before starting any client services.

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.