Skip to content

Spring Cloud OpenFeign With Eureka#

Why Spring Cloud OpenFeign With Eureka?#

  • Assume that in a micro-service system, you have an adapter service which are used by 4 or 5 other services. By default, these services will use Spring Cloud OpenFeign to call to adapter service based on the deployed route (Ex: https://example.domain.com:8080). Then one day, the business team decided to bring this adapter service to another domain and change current domain URL of adapter service (Ex: https://example.new.domain.com:8080). So for now, the developers have to update all configuration files of all services that are using the adapter service in the micro-service system and have to restart all of these services to fetch the latest configurations. This take a lot of time and efforts for developers and business side also have to stop all activities and wait for developer team finish updating.
  • Thus, to avoid this issue, in micro-service system, we can use Spring Cloud OpenFeign together with Spring Cloud Netflix Eureka Server-Client. Then if there is any change happen to the domain URL, so every services in system will know and will be updated automatically.

Spring Cloud OpenFeign With Eureka Example#

  • Let's take an example for using Spring Cloud OpenFeign With Eureka. We will need to create 3 services. One Eureka Server and 2 Eureka Clients in which 1 Eureka Clients will be an adapter service which connects to Database and the other will try to communicate to it by using service name in OpenFeign Client.

 #zoom

Eureka Server#

  • To create Eureka Server, let's add some dependencies as below.
  • Note Netflix Eureka Server dependencies require you to add Spring Cloud dependency first as mentioned in Spring Cloud Introduction. So maybe you have to add the dependency below first.
pom.xml
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
<properties>
    <spring.cloud-version>2021.0.0</spring.cloud-version>
</properties>
<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>
  • Then to use Netflix Eureka Server in your Spring Boot application. You will need to add some dependencies as below
pom.xml
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
<dependencies>

    <!-- ...other dependencies -->

    <dependency>  
   <groupId>org.springframework.cloud</groupId>  
   <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>  
    </dependency>  

    <dependency>  
         <groupId>com.google.code.gson</groupId>  
         <artifactId>gson</artifactId>  
         <version>2.8.9</version>  
    </dependency>

    <!-- ...other dependencies -->

</dependencies>
  • Now, you will need to add annotation @EnableEurekaServer into your main class as below.
ServerApplication.java
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
package com.eureka.server;  

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

@SpringBootApplication  
@EnableEurekaServer  
public class ServerApplication {  

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

}
  • Then In your application.yml. Let's add some configuration. The details of configuration are put in the comments.
application.yml
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
#server run at port 8761
server:
  port: 8761

spring:
  application:
    #application name
    name: eureka-server

eureka:
  client:
    #self register is false
    register-with-eureka: false
    #self fetch registry is false
    fetch-registry: false

Blog Application Adapter#

  • Like Eureka Server, you also need to add a dependency for Spring Cloud.
  • Note Netflix Eureka Client dependencies require you to add Spring Cloud dependency first as mentioned in Spring Cloud Introduction. So maybe you have to add the dependency below first.
pom.xml
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
<properties>
    <spring.cloud-version>2021.0.0</spring.cloud-version>
</properties>
<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>
  • Then to use Netflix Eureka Client in your Spring Boot application. You will need to add some dependencies as below
pom.xml
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<dependencies>

    <!-- ...other dependencies -->

    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    </dependency>

    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-core</artifactId>
        <version>2.13.1</version>
    </dependency>

    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-annotations</artifactId>
        <version>2.13.1</version>
    </dependency>

    <dependency>
        <groupId>com.google.code.gson</groupId>
        <artifactId>gson</artifactId>
        <version>2.8.9</version>
    </dependency>

    <!-- ...other dependencies -->

</dependencies>
  • Now, Let's add annotation @EnableDiscoveryClient into main class.
AdapterApplication.java
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
package com.application.adapter;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

@SpringBootApplication
@EnableDiscoveryClient
public class AdapterApplication {

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

}
  • Then in this service, we will create a simple controller with an api as below.
HelloController.java
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
package com.application.adapter.controller;

import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HelloController {

    @RequestMapping(method = RequestMethod.GET, path = "/v1/hello")
    public ResponseEntity<String> getHello() {
        return new ResponseEntity<>("Hello from blog application adapter", HttpStatus.OK);
    }

}
  • Then add some configuration in application.yml as below to connect to Eureka Server. The property “eureka.client.serviceUrl.defaultZone” will be the url for register of eureka server.
application.yml
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
#service run at port 8080
server:
  port: 8080

spring:
  application:
    #service name which will be used for registering and showed on eureka server dashboard
    name: blog-adapter-service
  #Enable Spring Cloud Discovery
  cloud:
    discovery:
      enabled: true

#register this service to eureka server by url
eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/

Application BFF Service#

  • Like the Blog Application Adapter, we will also need to add some dependencies below for Spring Cloud and Eureka Client
pom.xml
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
<properties>
    <spring.cloud-version>2021.0.0</spring.cloud-version>
</properties>
<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>
  • Then to use Netflix Eureka Client in your Spring Boot application. You will need to add some dependencies as below
pom.xml
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<dependencies>

    <!-- ...other dependencies -->

    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    </dependency>

    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-core</artifactId>
        <version>2.13.1</version>
    </dependency>

    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-annotations</artifactId>
        <version>2.13.1</version>
    </dependency>

    <dependency>
        <groupId>com.google.code.gson</groupId>
        <artifactId>gson</artifactId>
        <version>2.8.9</version>
    </dependency>

    <!-- ...other dependencies -->

</dependencies>
  • Then we can add this dependency below for Spring Cloud OpenFeign.
pom.xml
1
2
3
4
5
<dependency>  
   <groupId>org.springframework.cloud</groupId>  
   <artifactId>spring-cloud-starter-openfeign</artifactId>  
   <version>2.2.6.RELEASE</version>  
</dependency>
  • Now, to enable Spring Cloud OpenFeign and Eureka Client, we will add @EnableFeignClients and @EnableDiscoveryClient into the main class as below
BffApplication.java
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
package com.application.bff;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;

@EnableDiscoveryClient
@EnableFeignClients
@SpringBootApplication
public class BffApplication {

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

}
  • Next, we will create an adapter interface to configure OpenFeign with target api as below:
AdapterServerApi.java
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
package com.application.bff.adapters;

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

// name of this feign client adapter which should be the adapter service name which registered with Eureka Server
@FeignClient(name = "${adapter.service.name}")
public interface AdapterServerApi {

    @RequestMapping(method = RequestMethod.GET, value = "/v1/hello")
    String getHelloResponse();

}
  • The application.yml will contain the adapter service name that we want to call to.
application.yml
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#service run at port 9090
server:
  port: 9090

spring:
  application:
    #service name which will be showed on eureka server dashboard
    name: application-bff-service
  #Enable Spring Cloud Discovery
  cloud:
    discovery:
      enabled: true

#register this service to eureka server by url
eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/

#adapter service name which registered with Eureka Server
adapter:
  service:
    name: blog-adapter-service
  • Now, we created the FeignClient interface. So you can inject for any service classes by @Autowired and methods for using. So let's create a simple controller and Inject AdapterServerApi for using as below.
ApiController.java
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package com.application.bff.controller;

import com.application.bff.adapters.AdapterServerApi;
import com.application.bff.service.AdapterService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class ApiController {

    @Autowired
    private AdapterServerApi adapterServerApi;


    @RequestMapping(method = RequestMethod.GET, path = "/v1/client/hello")
    public ResponseEntity<String> getHelloFromAdapter() {
        return new ResponseEntity<>(adapterServerApi.getHelloResponse(), HttpStatus.OK);
    }

}

Testing#

  • Now, let's start all services and go to http://localhost:8761 to check the Eureka Clients registered to Eureka Server successfully.

 #zoom

  • Then we will try to call the api /v1/client/hello from BFF Service then we should see the message from the Adapter Service as below.

 #zoom

  • So, It means applying Spring Cloud OpenFeign and Eureka worked correctly, and the BFF doesn't need to care about what is the endpoint of Adapter service is, It just needs the Adapter service name.
  • Now, let's try to change the Adapter Service Endpoint by changing the Port in the application.yml as below.
application.yml
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
#service run at port 7000
server:
  port: 7000

spring:
  application:
    #service name which will be used for registering and showed on eureka server dashboard
    name: blog-adapter-service
  #Enable Spring Cloud Discovery
  cloud:
    discovery:
      enabled: true

#register this service to eureka server by url
eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/
  • Then Let's restart the Adapter Service, but still keep Eureka Server and BFF service running.
  • Then call the api /v1/client/hello from BFF Service again. You may got the error as below.

 #zoom

  • But if you wait for 30s and call again, you will receive a successful result.

 #zoom

  • So Spring Cloud Eureka Server will help you to maintain Eureka Clients in the system. However, it has some delay for syncing the current status of an Client to the Eureka servers and subsequently in other Eureka clients. That why after restarting the Adapter service 30s, you will receive successful calls.

See Also#

References#