o7planning

Understanding Spring Cloud Discovery Eureka Client with Example

  1. Objective of lesson
  2. Create Spring Boot project
  3. @EnableEurekaClient
  4. Controller
  5. Run the application on the Eclipse
  6. Run replicas
  7. Test Discovery

1. Objective of lesson

In a Distributed System, the services (applications) need to be registered with "Service Registration" so that they can discover each other.
In the previous lesson, we have created a "Service Registration" using the Netflix technology (Spring Cloud Netflix Eureka Server). You can view this lesson using the link below:
OK, in this lesson, we will discuss how to configure a service (application) in a distributed system so that it becomes an Eureka Client. This means that it will be registered with "Registration Serivce" (Eureka Server).
Eureka Clients will have the list of other Eureka Clients, we will manipulate these lists with the Java code.

2. Create Spring Boot project

On the Eclipse, create a Spring Boot project.
  • Name: SpringCloudDiscoveryEurekaClient
  • Group: org.o7planning
  • Artifact: SpringCloudDiscoveryEurekaClient
  • Description: Spring Cloud Discovery (Eureka Client)
  • Package: org.o7planning.eurekaclient
Project has been created:
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
    http://maven.apache.org/xsd/maven-4.0.0.xsd">
    
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.o7planning</groupId>
    <artifactId>SpringCloudDiscoveryEurekaClient</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>SpringCloudDiscoveryEurekaClient</name>
    <description>Spring Cloud Discovery (Eureka Client)</description>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.9.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
        <spring-cloud.version>Edgware.RELEASE</spring-cloud.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>


</project>

3. @EnableEurekaClient

Using @EnableEurekaClient to annotate on the application, you will turn this application into an Eureka Client.
SpringCloudDiscoveryEurekaClientApplication.java
package org.o7planning.eurekaclient;

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

@EnableEurekaClient
@SpringBootApplication
public class SpringCloudDiscoveryEurekaClientApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringCloudDiscoveryEurekaClientApplication.class, args);
    }
    
}
application.yml
spring:
  application:
    name: ABC-SERVICE # ==> This is Service-Id
    

---
# Items that apply to ALL profiles:   
eureka:
  instance:
    appname: ABC-SERVICE  # ==> This is a instance of ABC-SERVICE
  client:    
    fetchRegistry: true
    serviceUrl:
#      defaultZone: http://my-eureka-server.com:9000/eureka
      defaultZone: http://my-eureka-server-us.com:9001/eureka
#      defaultZone: http://my-eureka-server-fr.com:9002/eureka
#      defaultZone: http://my-eureka-server-vn.com:9003/eureka
server:
  port: 8000  
 
---
spring:
  profiles: abc-service-replica01
eureka:
  instance:
    appname: ABC-SERVICE  # ==> This is a instance of ABC-SERVICE
  client:    
    fetchRegistry: true
    serviceUrl:
      defaultZone: http://my-eureka-server-us.com:9001/eureka  
server:
  port: 8001   
    
---
spring:
  profiles: abc-service-replica02
eureka:
  instance:
    appname: ABC-SERVICE  # ==> This is a instance of ABC-SERVICE
  client:    
    fetchRegistry: true
    serviceUrl:
      defaultZone: http://my-eureka-server-us.com:9001/eureka    
server:
  port: 8002
 
---
spring:
  profiles: abc-service-replica03
eureka:
  instance:
    appname: ABC-SERVICE  # ==> This is a instance of ABC-SERVICE
  client:    
    fetchRegistry: true
    serviceUrl:
      defaultZone: http://my-eureka-server-us.com:9001/eureka    
server:
  port: 8003
 
---
spring:
  profiles: abc-service-replica04
eureka:
  instance:
    appname: ABC-SERVICE  # ==> This is a instance of ABC-SERVICE
  client:    
    fetchRegistry: true
    serviceUrl:
      defaultZone: http://my-eureka-server-us.com:9001/eureka    
server:
  port: 8004  
 
---
spring:
  profiles: abc-service-replica05
eureka:
  instance:
    appname: ABC-SERVICE  # ==> This is a instance of ABC-SERVICE
  client:    
    fetchRegistry: true
    serviceUrl:
      defaultZone: http://my-eureka-server-us.com:9001/eureka    
server:
  port: 8005

4. Controller

When Eureka Clients register with Eureka Server (Service Registration), they can get the list of other Eureka Clients registered with the Eureka Server.
@Autowired
private DiscoveryClient discoveryClient;

...

// Get All Service Ids
List<String> serviceIds = this.discoveryClient.getServices();


// (Need!!) eureka.client.fetchRegistry=true
List<ServiceInstance> instances = this.discoveryClient.getInstances(serviceId);


for (ServiceInstance serviceInstance : instances) {
    System.out.println("URI: " + serviceInstance.getUri();
    System.out.println("Host: " + serviceInstance.getHost();
    System.out.println("Port: " + serviceInstance.getPort();
}
MainController.java
package org.o7planning.eurekaclient.controller;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class MainController {

    @Autowired
    private DiscoveryClient discoveryClient;

    @ResponseBody
    @RequestMapping(value = "/", method = RequestMethod.GET)
    public String home() {

        return "<a href='showAllServiceIds'>Show All Service Ids</a>";
    }

    @ResponseBody
    @RequestMapping(value = "/showAllServiceIds", method = RequestMethod.GET)
    public String showAllServiceIds() {

        List<String> serviceIds = this.discoveryClient.getServices();

        if (serviceIds == null || serviceIds.isEmpty()) {
            return "No services found!";
        }
        String html = "<h3>Service Ids:</h3>";
        for (String serviceId : serviceIds) {
            html += "<br><a href='showService?serviceId=" + serviceId + "'>" + serviceId + "</a>";
        }
        return html;
    }

    @ResponseBody
    @RequestMapping(value = "/showService", method = RequestMethod.GET)
    public String showFirstService(@RequestParam(defaultValue = "") String serviceId) {

        // (Need!!) eureka.client.fetchRegistry=true
        List<ServiceInstance> instances = this.discoveryClient.getInstances(serviceId);

        if (instances == null || instances.isEmpty()) {
            return "No instances for service: " + serviceId;
        }
        String html = "<h2>Instances for Service Id: " + serviceId + "</h2>";

        for (ServiceInstance serviceInstance : instances) {
            html += "<h3>Instance: " + serviceInstance.getUri() + "</h3>";
            html += "Host: " + serviceInstance.getHost() + "<br>";
            html += "Port: " + serviceInstance.getPort() + "<br>";
        }

        return html;
    }

    // A REST method, To call from another service.
    // See in Lesson "Load Balancing with Ribbon".
    @ResponseBody
    @RequestMapping(value = "/hello", method = RequestMethod.GET)
    public String hello() {

        return "<html>Hello from ABC-SERVICE</html>";
    }

}

5. Run the application on the Eclipse

First of all, you have to ensure that you have run the Eureka Server:
See the previous lesson to run an Eureka Server:
Then you can run the Eureka Client directly on the Eclipse. It will be registered with the Eureka Server.
Access the URL below, and you can see the Eureka Clients registered with the Eureka Server.

6. Run replicas

Use the "Maven Install" function to create jar file from project. Right click on the project, select:
  • Run As/Maven Install
And you have a jar file in the target directory of the project.
Copy the jar file just created to a directory and create 2 BAT files:
  • abc-service-replica01.bat
  • abc-service-replica02.bat
  • abc-service-replica03.bat
  • abc-service-replica04.bat
  • abc-service-replica05.bat
abc-service-replica01.bat
java -jar -Dspring.profiles.active=abc-service-replica01 SpringCloudDiscoveryEurekaClient-0.0.1-SNAPSHOT.jar
abc-service-replica02.bat
java -jar -Dspring.profiles.active=abc-service-replica02 SpringCloudDiscoveryEurekaClient-0.0.1-SNAPSHOT.jar
abc-service-replica03.bat
java -jar -Dspring.profiles.active=abc-service-replica03 SpringCloudDiscoveryEurekaClient-0.0.1-SNAPSHOT.jar
abc-service-replica04.bat
java -jar -Dspring.profiles.active=abc-service-replica04 SpringCloudDiscoveryEurekaClient-0.0.1-SNAPSHOT.jar
abc-service-replica05.bat
java -jar -Dspring.profiles.active=abc-service-replica05 SpringCloudDiscoveryEurekaClient-0.0.1-SNAPSHOT.jar
Run the 2 BAT files:
On the Eureka Monitor, you can see the Eureka Clients registered with the Eureka Server.

7. Test Discovery

OK, after running the Eureka Client, you can view how it discovers other Eureka Clients.
Visit the URL below (Note: wait for 30 seconds to ensure that the Eureka Server and the Eureka Client have updated each other's statuses fully).