Backend Development 19 min read

Service-to-Service Calls in Spring Cloud: RestTemplate, Feign, and Load‑Balancing Strategies

This tutorial demonstrates how to implement inter‑service communication in Spring Cloud using RestTemplate and Feign, covering project setup, bean configuration, three RestTemplate invocation patterns, load‑balancing with Ribbon, and switching strategies via code or configuration files.

Selected Java Interview Questions
Selected Java Interview Questions
Selected Java Interview Questions
Service-to-Service Calls in Spring Cloud: RestTemplate, Feign, and Load‑Balancing Strategies

1. Service‑to‑Service Calls

Microservices often require many instances to communicate with each other; the most common underlying mechanism is HttpClient . In Spring Cloud you can still use HttpClient , but it lacks load‑balancing and convenient wrappers.

2. RestTemplate Calls

2.1 Create Demonstration Projects

Three projects are needed: a Eureka registration server, a service provider (Server), and a service consumer (Client). Both Server and Client register themselves to Eureka.

# Server application.yml (excerpt)
server:
  port: 8001
spring:
  application:
    name: hello-service
eureka:
  client:
    service-url:
      defaultZone: http://localhost:7001/eureka/

A simple ServerController returns a string:

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class ServerController {
    @RequestMapping("/helloServer")
    public String hello() {
        return "hello-server";
    }
}

Running the server and accessing http://192.168.1.6:8001/helloServer returns the expected response, and Eureka shows the service registered.

The client project also defines a ClientController with a simple endpoint:

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class ClientController {
    @RequestMapping("/helloClient")
    public String hello() {
        return "hello-client";
    }
}

After registration, the client can be accessed at http://192.168.1.6:8002/helloClient , and Eureka confirms the client registration.

2.2 RestTemplate Bean Instantiation

To use RestTemplate , declare a bean in the client’s main class:

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.RestTemplate;

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

    @Bean
    public RestTemplate initRestTemplate() {
        return new RestTemplate();
    }
}

2.3 RestTemplate Call – Method 1 (Hard‑Coded URL)

Inject the bean and call the server directly:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

@RestController
public class ClientController {
    @Autowired
    private RestTemplate template;

    @RequestMapping("/helloClient1")
    public String helloClient1() {
        String result = template.getForObject("http://127.0.0.1:8001/helloServer", String.class);
        return result;
    }
}

This works but ties the client to a fixed address.

2.4 RestTemplate Call – Method 2 (Using Eureka for Address Discovery)

Inject LoadBalancerClient to obtain the service instance from Eureka and build the URL dynamically:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

@RestController
public class ClientController {
    @Autowired
    private RestTemplate template;
    @Autowired
    private LoadBalancerClient loadBalancerClient;

    @RequestMapping("/helloClient2")
    public Object helloClient2() {
        ServiceInstance si = loadBalancerClient.choose("hello-server");
        String url = String.format("http://%s:%s/helloServer", si.getHost(), si.getPort());
        return template.getForObject(url, String.class);
    }
}

This removes the hard‑coded address and relies on Eureka’s service name.

2.5 RestTemplate Call – Method 3 (Load‑Balanced RestTemplate)

Annotate the RestTemplate bean with @LoadBalanced . Spring Cloud will replace the service name in the URL with the actual instance address automatically:

@Bean
@LoadBalanced
public RestTemplate initRestTemplate() {
    return new RestTemplate();
}

Now a call such as template.getForObject("http://hello-server/helloServer", String.class) works without manual instance lookup.

3. Load‑Balancing Strategies

3.1 Default Strategy (Round‑Robin)

When @LoadBalanced is used, Ribbon’s default rule is round‑robin. Adding a second server instance (e.g., on port 8003) shows alternating responses, confirming the default behavior.

3.2 Coding‑Based Strategy (RandomRule)

Define an IRule bean returning new RandomRule() to switch the algorithm to random selection:

@Bean
public IRule initIRule() {
    return new RandomRule();
}

After restarting the client, repeated calls produce non‑sequential results, indicating the random strategy is active.

3.3 Configuration‑Based Strategy

Alternatively, specify the rule in application.yml of the client:

hello-server:
  ribbon:
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule

With the code‑based bean removed, the client now follows the rule defined in the configuration file.

4. Feign Calls

Feign provides a declarative HTTP client. Add the dependency:

<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-openfeign</artifactId>
  <version>2.1.1.RELEASE</version>
</dependency>

Enable Feign in the main class with @EnableFeignClients and keep the @LoadBalanced RestTemplate bean if needed.

Define a Feign client interface:

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

@FeignClient(name = "hello-server")
public interface ServerApi {
    @RequestMapping("/helloServer")
    String helloServer();
}

Inject the interface into a controller and call it directly:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class ClientFeignController {
    @Autowired
    private ServerApi serverApi;

    @RequestMapping("/helloClient4")
    public String helloClient4() {
        return serverApi.helloServer();
    }
}

When the load‑balancing rule is set to random (as shown in section 3), the Feign call returns responses from either server instance, demonstrating that Feign also respects Ribbon’s strategy.

All source code referenced in this article is available at https://github.com/xiaoyususu/springcloud-resttemplate-feign.gi .

JavamicroservicesLoad balancingfeignSpring CloudRestTemplate
Selected Java Interview Questions
Written by

Selected Java Interview Questions

A professional Java tech channel sharing common knowledge to help developers fill gaps. Follow us!

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.