DEV Community

Marcin Piczkowski
Marcin Piczkowski

Posted on

3 3

Spring Cloud step-by-step (part 5)

This is a continuation of previous blog posts:
This is a continuation of previous blog posts:

In previous blog post I showed you how to invoke other services using EurekaClient, but there is a simpler way.

RestTemplate is smart enough to resolve service URI from Eureka server itself.

Ribbon is a client-side load balancer and SpringTemplate supports it by simply adding one annotation: @LoadBalanced.

Let's create version 2 of Rental Service controller which will look this way:

@RestController
@RequestMapping(path = "/v2")
public class RentalControllerV2 {
    protected String serviceUrl = "http://PRICING-SERVICE";

    private final RestTemplate restTemplate;

    public RentalControllerV2(@Qualifier("ribbon-template") RestTemplate restTemplate) {
        this.restTemplate = restTemplate;
    }

    @RequestMapping(path = "/rentals/{id}/charges", method = RequestMethod.GET)
    public ResponseEntity getPossibleCharges(@PathVariable("id") String id) {

        ZonedDateTime startTime = ZonedDateTime.now();
        ZonedDateTime endTime = startTime.plus(2, ChronoUnit.DAYS);
        HttpEntity<PriceRequest> request = new HttpEntity<>(
                new PriceRequest("vip", startTime, endTime)
        );
        PriceResponse response = restTemplate.postForObject(serviceUrl + "/v1/prices", request, PriceResponse.class);
        return new ResponseEntity<>(new RentalChargesResponse(response.getPrice()), HttpStatus.OK);
    }
}

To enable Ribbon we have to add this property in bootstrap.yaml or application.yaml

ribbon:
  http:
    client:
      enabled: true

In the controller above I am injecting RestTemplate as a bean named ribbon-template.
This is because I wanted to leave two RestTemplate beans in the application: one which we use in version 1 controller with native EurekaClient API and another in version 2 controller which is load-balanced RestTemplate.

This is how my beans configuration looks like in main class:

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

@Bean("ribbon-template")
@LoadBalanced
public RestTemplate restTemplateWithRibbon() {
    return new RestTemplate();
}

And that's it. Start the application and invoke endpoint:

curl localhost:8080/v2/rentals/1/charges

You will see in logs how Spring is resolving Rental Service URL from service name:

2018-06-29 01:11:58.027  INFO 18934 --- [nio-8080-exec-1] c.netflix.config.ChainedDynamicProperty  : Flipping property: PRICING-SERVICE.ribbon.ActiveConnectionsLimit to use NEXT property: niws.loadbalancer.availabilityFilteringRule.activeConnectionsLimit = 2147483647
2018-06-29 01:11:58.048  INFO 18934 --- [nio-8080-exec-1] c.n.u.concurrent.ShutdownEnabledTimer    : Shutdown hook installed for: NFLoadBalancer-PingTimer-PRICING-SERVICE
2018-06-29 01:11:58.067  INFO 18934 --- [nio-8080-exec-1] c.netflix.loadbalancer.BaseLoadBalancer  : Client: PRICING-SERVICE instantiated a LoadBalancer: DynamicServerListLoadBalancer:{NFLoadBalancer:name=PRICING-SERVICE,current list of Servers=[],Load balancer stats=Zone stats: {},Server stats: []}ServerList:null
2018-06-29 01:11:58.072  INFO 18934 --- [nio-8080-exec-1] c.n.l.DynamicServerListLoadBalancer      : Using serverListUpdater PollingServerListUpdater
2018-06-29 01:11:58.089  INFO 18934 --- [nio-8080-exec-1] c.netflix.config.ChainedDynamicProperty  : Flipping property: PRICING-SERVICE.ribbon.ActiveConnectionsLimit to use NEXT property: niws.loadbalancer.availabilityFilteringRule.activeConnectionsLimit = 2147483647
2018-06-29 01:11:58.090  INFO 18934 --- [nio-8080-exec-1] c.n.l.DynamicServerListLoadBalancer      : DynamicServerListLoadBalancer for client PRICING-SERVICE initialized: DynamicServerListLoadBalancer:{NFLoadBalancer:name=PRICING-SERVICE,current list of Servers=[192.168.43.107:46579],Load balancer stats=Zone stats: {defaultzone=[Zone:defaultzone;    Instance count:1;   Active connections count: 0;    Circuit breaker tripped count: 0;   Active connections per server: 0.0;]
},Server stats: [[Server:192.168.43.107:46579;  Zone:defaultZone;   Total Requests:0;   Successive connection failure:0;    Total blackout seconds:0;   Last connection made:Thu Jan 01 01:00:00 CET 1970;  First connection made: Thu Jan 01 01:00:00 CET 1970;    Active Connections:0;   total failure count in last (1000) msecs:0; average resp time:0.0;  90 percentile resp time:0.0;    95 percentile resp time:0.0;    min resp time:0.0;  max resp time:0.0;  stddev resp time:0.0]
]}ServerList:org.springframework.cloud.netflix.ribbon.eureka.DomainExtractingServerList@fcc5a3d
2018-06-29 01:11:58.131  INFO 18934 --- [nio-8080-exec-1] com.netflix.http4.ConnectionPoolCleaner  : Initializing ConnectionPoolCleaner for NFHttpClient:PRICING-SERVICE
2018-06-29 01:11:59.075  INFO 18934 --- [erListUpdater-0] c.netflix.config.ChainedDynamicProperty  : Flipping property: PRICING-SERVICE.ribbon.ActiveConnectionsLimit to use NEXT property: niws.loadbalancer.availabilityFilteringRule.activeConnectionsLimit = 2147483647

As usual, source code for this example is on Github spring-cloud-5 branch.

Image of Datadog

The Essential Toolkit for Front-end Developers

Take a user-centric approach to front-end monitoring that evolves alongside increasingly complex frameworks and single-page applications.

Get The Kit

Top comments (0)

Sentry image

See why 4M developers consider Sentry, “not bad.”

Fixing code doesn’t have to be the worst part of your day. Learn how Sentry can help.

Learn more

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay