LATEST VERSION: 1.5 - RELEASE NOTES
Spring Cloud Services v1.5

Writing Client Applications

Page last updated:

Refer to the sample applications in the “traveler” repository to follow along with the code in this topic.

To use Spring Cloud Netflix Hystrix circuit breakers in a Spring Boot app with a Circuit Breaker Dashboard instance, you must add the dependencies listed below.

Important: Ensure that the ordering of the Maven BOM dependencies listed below is preserved in your application’s build file. Dependency resolution is affected in both Maven and Gradle by the order in which dependencies are declared.

To work with Spring Cloud Services service instances, your client application must include the spring-cloud-services-dependencies and spring-cloud-dependencies BOMs. Unless you are using the spring-boot-starter-parent or Spring Boot Gradle plugin, you must also specify the spring-boot-dependencies BOM as a dependency. See below for compatible Spring Boot, Spring Cloud, and Spring Cloud Services client dependency versions to use with a given Spring Cloud Services tile release.

Spring Cloud Services Tile Spring Boot Spring Cloud Spring Cloud Services Client
1.0.x 1.2.x Angel.x 1.0.x
1.1.x 1.3.x–1.4.x Brixton.x 1.1.x
1.2.x 1.3.x–1.4.x Brixton.x 1.2.x
1.3.x 1.3.x–1.4.x Camden.x 1.4.x
1.4.x 1.5.x Dalston.x 1.5.x
1.5.x 1.5.x Edgware.x 1.6.x
1.5.x 2.0.x Finchley.x 2.0.x

The build file examples given below contain version placeholders for the versions of Spring Boot, Spring Cloud, and the Spring Cloud Services client dependencies. See below for how to replace them, depending on whether your client application uses Spring Boot 2 and Spring Cloud Finchley or Spring Boot 1.5 and Spring Cloud Edgware:

If using… …use [BOOT] …use [CLOUD] …use [SCS]
Boot 2, Cloud Finchley 2.0.3.RELEASE Finchley.RELEASE 2.0.1.RELEASE
Boot 1.5, Cloud Edgware 1.5.13.RELEASE Edgware.SR3 1.6.1.RELEASE

If using Maven, include in pom.xml:

  <parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>[BOOT]</version>
    <relativePath/> <!-- lookup parent from repository -->
  </parent>

  <dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>io.pivotal.spring.cloud</groupId>
            <artifactId>spring-cloud-services-dependencies</artifactId>
            <version>[SCS]</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>[CLOUD]</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
  </dependencyManagement>

If not using the spring-boot-starter-parent, include in the <dependencyManagement> block of pom.xml:

  <dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-dependencies</artifactId>
            <version>[BOOT]</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>

        <!-- ... -->

    </dependencies>
  </dependencyManagement>

If using Gradle, you will also need to use the Gradle dependency management plugin.

Include in build.gradle:

buildscript {
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath("io.spring.gradle:dependency-management-plugin:1.0.5.RELEASE")
        classpath("org.springframework.boot:spring-boot-gradle-plugin:[BOOT]")
    }
}

apply plugin: "java"
apply plugin: "org.springframework.boot"
apply plugin: "io.spring.dependency-management"

dependencyManagement {
    imports {
        mavenBom "org.springframework.cloud:spring-cloud-dependencies:[CLOUD]"
        mavenBom "io.pivotal.spring.cloud:spring-cloud-services-dependencies:[SCS]"
    }
}

repositories {
    maven {
        url "https://repo.spring.io/plugins-release"
    }
}

If not using the Spring Boot Gradle plugin, include in the dependencyManagement block of build.gradle:

dependencyManagement {
    imports {
        mavenBom "org.springframework.boot:spring-boot-dependencies:[BOOT]"
    }
}

Your app must also declare the Spring Cloud Services Circuit Breaker Dashboard starter as a dependency.

If using Maven, include in pom.xml:

  <dependencies>
    <dependency>
      <groupId>io.pivotal.spring.cloud</groupId>
      <artifactId>spring-cloud-services-starter-circuit-breaker</artifactId>
    </dependency>
  </dependencies>

If using Gradle, include in build.gradle:

dependencies {
    compile("io.pivotal.spring.cloud:spring-cloud-services-starter-circuit-breaker")
}

Use a Circuit Breaker

To work with a Circuit Breaker Dashboard instance, your application must include the @EnableCircuitBreaker annotation on a configuration class.

import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
//...

@SpringBootApplication
@EnableDiscoveryClient
@RestController
@EnableCircuitBreaker
public class AgencyApplication {
    //...

To apply a circuit breaker to a method, annotate the method with @HystrixCommand, giving the annotation the name of a fallbackMethod.

    @HystrixCommand(fallbackMethod = "getBackupGuide")
    public String getGuide() {
        return restTemplate.getForObject("http://company/available", String.class);
    }

The getGuide() method uses a RestTemplate to obtain a guide name from another application called Company, which is registered with a Service Registry instance. (See the Service Registry documentation, specifically the Writing Client Applications topic.) The method thus relies on the Company application to return a response, and if the Company application fails to do so, calls to getGuide() will fail. When the failures exceed the threshold, the breaker on getGuide() will open the circuit.

While the circuit is open, the breaker redirects calls to the annotated method, and they instead call the designated fallbackMethod. The fallback method must be in the same class and have the same method signature (i.e., have the same return type and accept the same parameters) as the annotated method. In the Agency application, the getGuide() method on the TravelAgent class falls back to getBackupGuide().

    String getBackupGuide() {
        return "None available! Your backup guide is: Cookie";
    }

If you wish, you may also annotate fallback methods themselves with @HystrixCommand to create a fallback chain.

Use a Circuit Breaker with a Feign Client

You cannot apply @HystrixCommand directly to a Feign client interface at this time. Instead, you can call Feign client methods from a service class that is autowired as a Spring bean (either through the @Service or @Component annotations or by being declared as a @Bean in a configuration class) and then annotate the service class methods with @HystrixCommand.

In the Feign version of the Agency application, the AgencyApplication class is annotated with @EnableFeignClients.

//...
import org.springframework.cloud.netflix.feign.EnableFeignClients;

@SpringBootApplication
@EnableDiscoveryClient
@RestController
@EnableCircuitBreaker
@EnableFeignClients
public class AgencyApplication {
    // ...

The application has a Feign client called CompanyClient.

package agency;

import org.springframework.stereotype.Component;
import org.springframework.cloud.netflix.feign.FeignClient;
import org.springframework.web.bind.annotation.RequestMapping;

import static org.springframework.web.bind.annotation.RequestMethod.GET;

@FeignClient("https://company")
interface CompanyClient {
  @RequestMapping(value="/available", method = GET)
  String availableGuide();
}

The TravelAgent class is annotated as a @Service class. The CompanyClient class is injected through autowiring, and the getGuide() method uses the CompanyClient to access the Company application. @HystrixCommand is applied to the service method:

package agency;

import org.springframework.stereotype.Service;
import org.springframework.beans.factory.annotation.Autowired;

import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;

@Service
public class TravelAgent {

    @Autowired
    CompanyClient company;

    @HystrixCommand(fallbackMethod = "getBackupGuide")
    public String getGuide() {
        return company.availableGuide();
    }

    String getBackupGuide() {
        return "None available! Your backup guide is: Cookie";
    }

}

If the Company application becomes unavailable or if the Agency application cannot access it, calls to getGuide() will fail. When successive failures build up to the threshold, Hystrix will open the circuit, and subsequent calls will be redirected to the getBackupGuide() method until the Company application is accessible again and the circuit is closed.

Create a pull request or raise an issue on the source for this page in GitHub