Tutorial: How to implement Service Discovery with Eureka (Java)

CornerRight 4 min


Icons/Position/Pos. No. 1

Digital Products


Icons/Technology/Tech No.1

AI

What is Service Discovery?

When developing a system with many services, we need to specify our target while performing requests. But if the location of this service gets changed, then we also have to change our configuration to make requests to the new location. And what if we have multiple workers performing the same job? Changing configuration each time can be troublesome.
Service Discovery is about getting service details given some of its meta-data (i.e. name qualifying the service). Service that needs to be called needs to send its info to register with meta-data which will help retrieve needed details. This meta-data should be unmodifiable. Instead of performing requests directly (Figure 1.), we will fetch data from Service Discovery Register and then use this data (Figure 2.).

 

Figure 1. Architecture without Service Discovery

 

Figure 2. Architecture with Service Discovery

 

In this tutorial, we will create a mini system that will use Eureka for communication between services.
1.Eureka Service Registry

2. Eureka Client

3.Using Eureka for Service Discovery

Source code is available here: https://gitlab.4soft.tech/service-discovery-eureka

1. Eureka Service Registry

First, we need to create a registry for services, which will be called by those to register and get information about other services.

Requirements

  • JDK (preferable 16)
  • IDE or text editor

Project Generation

To generate the project we can use spring initializr but I will use a plugin to IntelliJ IDEA which is IDE that I will be using in this article.

In the `New Project` window select the option ‘Spring Iitializr’, then fill in the general settings of the project according to our needs and preferences. and click `Next`.
 

Next, search for Eureka Server dependency, select it, then click on ‘finish’.

Application configuration

To enable the Service Discovery register, you need to add @EnableEurekaServer annotation to your main class.

package co.soft.eureka;r
r
import org.springframework.boot.SpringApplication;r
import org.springframework.boot.autoconfigure.SpringBootApplication;r
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;r
@EnableEurekaServerr
@SpringBootApplicationr
public class EurekaServerApplication {r
    public static void main(String[] args) {r
        SpringApplication.run(EurekaServerApplication.class, args);r
    }r
r
r
}

In the application.properties file, disable the eureka client since our server will work only as a register.

eureka.client.register-with-eureka=falser
eureka.client.fetch-registry=false

You can also set the port to a specific number to avoid overlapping when running on the same machine.
 

server.port=8761

Testing

To start the application you can use your IDE or Gradle/Maven. In the given example we used Gradle so the given command would be ‘Gradle bootJar’ in the root directory or ‘./gradlew bootJar’ while using the Gradle wrapper.

When we visit http://localhost:8761/ we can see eureka UI which provides details about our registry.

Done! Now, we will explore this view more during client creation.

2. Greetings Service

We have built a Eureka Service Registry, so now it is time to create a client which will use it.

Requirements

  • JDK (preferable 16)
  • IDE or text editor

Project Generation

We can generate this project the same way we did with Registry Server, but we will select Eureka Discovery Client and Spring Web dependencies this time.

Application configuration

To enable the Service Discovery client we need to add @EnableEurekaClient annotation to our main class.

 

package co.soft.eurekaclient;r
r
import org.springframework.boot.SpringApplication;r
import org.springframework.boot.autoconfigure.SpringBootApplication;r
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;r
r
@EnableDiscoveryClientr
@SpringBootApplicationr
public class GreetingsApplication {r
r
r
    public static void main(String[] args) {r
        SpringApplication.run(GreetingsApplication.class, args);r
    }r
r
}

In `application.properties` we can specify the service registry URL.

eureka.client.serviceUrl.defaultZone=http://localhost:8761/eureka/

Also, we can specify the name which will be registered which by default is fetched from the application name property.

spring.application.name=greetings-service

Testing

Like previously, to start the application, you can use your IDE or Gradle/Maven. In the given example we used Gradle so the given command would be ‘Gradle bootJar’ in the root directory or ‘./gradlew bootJar’ while using Gradle wrapper.

When we visit http://localhost:8761/ we can see that our client is registered.

3. Using Eureka for Service Discovery

Now we can create a Eureka Service Registry and integrate with it using our clients. This time we will use multiple clients to communicate with each other in the system.

Requirements

  • JDK (preferable 16)
  • IDE or text editor

Project generation

We will now create a second service that will register itself within Eureka. This one will get info about other services from Eureka and then it will make a call to our already created Greetings Service.

Create a second service, we will call it Common Service, the same wa as you created Greetings Service. After that, open application.properties file and make sure that you specified needed properties.

r
eureka.client.serviceUrl.defaultZone=http://localhost:8761/eureka/r
eureka.services.greetings-service.name=greetings-servicer
spring.application.name=common-serivcer
#While running all services on single machine, make sure that different ports are being usedr
server.port=8081

For readability, we will use Lombok, which will generate some boilerplate code for us. Add Lombok dependencies into the build.gradle file (or pom.xml if you are using Maven) and enable annotation processing in your IDE settings
 

    compileOnly 'org.projectlombok:lombok'r
    annotationProcessor 'org.projectlombok:lombok'r
    annotationProcessor "org.springframework.boot:spring-boot-configuration-processor"

 

After initial configuration, on eureka UI you should see something like this:

Basic communication

Now we will create a simple endpoint in the Greetings Service.

package co.soft.eurekaclient.api;r
r
import org.springframework.http.ResponseEntity;r
import org.springframework.web.bind.annotation.GetMapping;r
import org.springframework.web.bind.annotation.RequestMapping;r
import org.springframework.web.bind.annotation.RestController;r
r
@RestControllerr
@RequestMapping("/greetings")r
public class GreetingsController {r
r
    @GetMappingr
    public ResponseEntity<String> greetings() {r
        return ResponseEntity.ok("Welcome");r
    }r
}

 

In Common Service we will also create an endpoint, This one within its underneath logic, will make a call to our Greetings Service. 

package co.soft.commonservice.api;r
r
import co.soft.commonservice.service.GreetingsService;r
import lombok.RequiredArgsConstructor;r
import org.springframework.http.ResponseEntity;r
import org.springframework.web.bind.annotation.GetMapping;r
import org.springframework.web.bind.annotation.RequestMapping;r
import org.springframework.web.bind.annotation.RestController;r
r
@RequiredArgsConstructorr
@RequestMapping("/greetings")r
@RestControllerr
public class GreetingsController {r
r
    private final GreetingsService service;r
r
    @GetMappingr
    public ResponseEntity<String> getGreetings() {r
        return ResponseEntity.ok(service.getGreetings());r
    }r
r
}

Now, we will create GreetingsService class

OtherEurekaClientService.java

package co.soft.commonservice.service;r
r
import com.netflix.discovery.EurekaClient;r
import lombok.RequiredArgsConstructor;r
import org.springframework.beans.factory.annotation.Value;r
import org.springframework.stereotype.Service;r
import org.springframework.web.client.RestTemplate;r
r
@Servicer
@RequiredArgsConstructorr
public class GreetingsService {r
r
    private final RestTemplate restTemplate;r
    private final EurekaClient eurekaClient;r
r
    @Value("${eureka.services.greetings-service.name}")r
    private String clientVirtualHostname;r
r
    public String getGreetings() {r
        String url = eurekaClient.getNextServerFromEureka(clientVirtualHostname, false)r
                             .getHomePageUrl() + "/greetings";r
        final String greetingFromGreetingMicroservice = restTemplate.getForObject(url, String.class);r
        return String.format("Greeting service says: %s", greetingFromGreetingMicroservice);r
    }r
r
}

First, we fetch the URL of our service given virtual hostname (which by default is spring.application.name defined in properties of the first service) using

eurekaClient.getNextServerFromEureka(clientVirtualHostname, false);

The first parameter is the virtual hostname and the second is the security option which will be described in one of the next articles.

Then we call

restTemplate.getForObject(url, String.class);

to get a response from the service.

Also, we need to define the service name in `application.properties` and configure the rest template to perform requests with it.

eureka.services.greetings-service.name=greetings-service

RestTemplateConfiguration.java

package co.soft.othereurekaclient.configuration;r
r
import lombok.RequiredArgsConstructor;r
import org.springframework.boot.web.client.RestTemplateBuilder;r
import org.springframework.context.annotation.Bean;r
import org.springframework.context.annotation.Configuration;r
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;r
import org.springframework.web.client.RestTemplate;r
r
r
@Configurationr
@RequiredArgsConstructorr
public class RestTemplateConfiguration {r
r
    private final RestTemplateBuilder restTemplateBuilder;r
r
    @Beanr
    public RestTemplate restTemplate() {r
        return restTemplateBuilderr
                .requestFactory(HttpComponentsClientHttpRequestFactory::new)r
                .build();r
    }r
}

Testing

First, we can call the service that will be called using Postman to see if it works properly.

Then, we can call the other service which will fetch data of the first one from the registry.

And we can see that it works as expected.

Summary

That’s it. I hope the tutorial was helpful! If you have any questions or would like us to elaborate more on this, just let us know in the comments.

Similar blog posts