This guide walks you through the process of applying circuit breakers to potentially failing method calls by using the Netflix Hystrix fault tolerance library.

What You Will Build

You will build a microservice application that uses the circuit breaker pattern to gracefully degrade functionality when a method call fails. Use of the Circuit Breaker pattern can let a microservice continue operating when a related service fails, preventing the failure from cascading and giving the failing service time to recover.

What You Need

How to complete this guide

Like most Spring Getting Started guides, you can start from scratch and complete each step or you can bypass basic setup steps that are already familiar to you. Either way, you end up with working code.

To start from scratch, move on to Starting with Spring Initializr.

To skip the basics, do the following:

When you finish, you can check your results against the code in gs-circuit-breaker/complete.

Starting with Spring Initializr

For all Spring applications, you should start with the Spring Initializr. The Initializr offers a fast way to pull in all the dependencies you need for an application and does a lot of the set up for you.

This guide needs two applications. The first application (a simple bookstore site) needs only the Web dependency.

The following listing shows the pom.xml file (for the configuration service) that is created when you choose Maven:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.3.2.RELEASE</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.example</groupId>
	<artifactId>circuit-breaker-bookstore</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>circuit-breaker-bookstore</name>
	<description>Demo project for Spring Boot</description>

	<properties>
		<java.version>1.8</java.version>
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
			<exclusions>
				<exclusion>
					<groupId>org.junit.vintage</groupId>
					<artifactId>junit-vintage-engine</artifactId>
				</exclusion>
			</exclusions>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>

</project>

The following listing shows the build.gradle file (for the configuration service) that is created when you choose Gradle:

plugins {
	id 'org.springframework.boot' version '2.3.2.RELEASE'
	id 'io.spring.dependency-management' version '1.0.9.RELEASE'
	id 'java'
}

group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '1.8'

repositories {
	mavenCentral()
}

dependencies {
	implementation 'org.springframework.boot:spring-boot-starter-web'
	testImplementation('org.springframework.boot:spring-boot-starter-test') {
		exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
	}
}

test {
	useJUnitPlatform()
}

The second application (the reading application, which will use a Hystrix circuit breaker) needs the Web and Hystrix dependencies.

The following listing shows the pom.xml file (for the configuration client) that is created when you choose Maven:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.3.2.RELEASE</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.example</groupId>
	<artifactId>circuit-breaker-reading</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>circuit-breaker-reading</name>
	<description>Demo project for Spring Boot</description>

	<properties>
		<java.version>1.8</java.version>
		<spring-cloud.version>Hoxton.M3</spring-cloud.version>
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
			<exclusions>
				<exclusion>
					<groupId>org.junit.vintage</groupId>
					<artifactId>junit-vintage-engine</artifactId>
				</exclusion>
			</exclusions>
		</dependency>
	</dependencies>

	<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>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>

	<repositories>
		<repository>
			<id>spring-milestones</id>
			<name>Spring Milestones</name>
			<url>https://repo.spring.io/milestone</url>
		</repository>
	</repositories>

</project>

The following listing shows the build.gradle file (for the configuration client) that is created when you choose Gradle:

plugins {
	id 'org.springframework.boot' version '2.3.2.RELEASE'
	id 'io.spring.dependency-management' version '1.0.9.RELEASE'
	id 'java'
}

group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '1.8'

repositories {
	mavenCentral()
}

ext {
	set('springCloudVersion', "Hoxton.SR1")
}

dependencies {
	implementation 'org.springframework.boot:spring-boot-starter-web'
	implementation 'org.springframework.cloud:spring-cloud-starter-netflix-hystrix'
	testImplementation('org.springframework.boot:spring-boot-starter-test') {
		exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
	}
}

dependencyManagement {
	imports {
		mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}"
	}
}

test {
	useJUnitPlatform()
}
For convenience, we have provided build files (a pom.xml file and a build.gradle file) at the top of the complete and initial projects (one directory above the bookstore and reading directories) that you can use to build both the bookstore project and the reading project at once. We also added the Maven and Gradle wrappers there.

Set up a Server Microservice Application

The Bookstore service will have a single endpoint. It will be accessible at /recommended and will (for simplicity) return a recommended reading list as a String.

You need to make your main class in BookstoreApplication.java. It should look like the following listing (from bookstore/src/main/java/com/example/circuitbreakerbookstore/CircuitBreakerBookstoreApplication.java):

package com.example.circuitbreakerbookstore;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.RequestMapping;

@RestController
@SpringBootApplication
public class CircuitBreakerBookstoreApplication {

  @RequestMapping(value = "/recommended")
  public String readingList(){
  return "Spring in Action (Manning), Cloud Native Java (O'Reilly), Learning Spring Boot (Packt)";
  }

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

The @RestController annotation indicates that BookstoreApplication is a REST controller class and ensures that any @RequestMapping methods in this class behave as though annotated with @ResponseBody. That is, the return values of @RequestMapping methods in this class are automatically and appropriately converted from their original types and are written directly to the response body.

You are going to run this application locally alongside an application with a consuming application. As a result, in src/main/resources/application.properties, you need to set server.port so that the Bookstore service cannot conflict with the consuming application when we get that running. The following listing (from bookstore/src/main/resources/application.properties) shows how to do so:

server.port=8090

Set up a Client Microservice Application

The reading application will be your consumer (modeling visitors) for the bookstore application. You can view your reading list there at /to-read, and that reading list is retrieved from the bookstore service application. The following example (from reading/src/main/java/com/example/circuitbreakerreading/CircuitBreakerReadingApplication.java) shows this class:

package com.example.circuitbreakerreading;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.web.client.RestTemplate;

@EnableCircuitBreaker
@RestController
@SpringBootApplication
public class CircuitBreakerReadingApplication {

  @Autowired
  private BookService bookService;

  @Bean
  public RestTemplate rest(RestTemplateBuilder builder) {
  return builder.build();
  }

  @RequestMapping("/to-read")
  public String toRead() {
  return bookService.readingList();
  }

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

To get the list from your bookstore, you can use Spring’s RestTemplate template class. RestTemplate makes an HTTP GET request to the bookstore service’s URL and returns the result as a String. (For more information on using Spring to consume a RESTful service, see the Consuming a RESTful Web Service guide.) To do so, you need to add the server.port property to reading/src/main/resources/application.properties, as the following listing shows:

server.port=8080

You now can access, in a browser, the /to-read endpoint of your reading application and see your reading list. However, since we rely on the bookstore application, if anything happens to it or if the reading application is unable to access Bookstore, you will have no list and your users will get a nasty HTTP 500 error message.

Apply the Circuit Breaker Pattern

Netflix’s Hystrix library provides an implementation of the circuit breaker pattern. When you apply a circuit breaker to a method, Hystrix watches for failing calls to that method, and, if failures build up to a threshold, Hystrix opens the circuit so that subsequent calls automatically fail. While the circuit is open, Hystrix redirects calls to the method, and they are passed to your specified fallback method.

Spring Cloud Netflix Hystrix looks for any method annotated with the @HystrixCommand annotation and wraps that method in a proxy connected to a circuit breaker so that Hystrix can monitor it. This currently works only in a class marked with @Component or @Service. Therefore, in the reading application, under src/main/java/com/example/circuitbreakerreading, you need to add a new class (called BookService).

The RestTemplate is injected into the constructor of the BookService when it is created. The following listing (from reading/src/main/java/com/example/circuitbreakerreading/BookService.java shows the BookService class):

package com.example.circuitbreakerreading;

import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import java.net.URI;

@Service
public class BookService {

  private final RestTemplate restTemplate;

  public BookService(RestTemplate rest) {
  this.restTemplate = rest;
  }

  @HystrixCommand(fallbackMethod = "reliable")
  public String readingList() {
  URI uri = URI.create("http://localhost:8090/recommended");

  return this.restTemplate.getForObject(uri, String.class);
  }

  public String reliable() {
  return "Cloud Native Java (O'Reilly)";
  }

}

You have applied @HystrixCommand to your original readingList() method. You also have a new method here: reliable(). The @HystrixCommand annotation has reliable as its fallbackMethod. If, for some reason, Hystrix opens the circuit on readingList(), you have an excellent (if short) placeholder reading list ready for your users.

In our main class, ReadingApplication, you need to create a RestTemplate bean, inject the BookService, and call it for your reading list. The following example (from reading/src/main/java/com/example/circuitbreakerreading/CircuitBreakerReadingApplication.java) shows how to do so:

package com.example.circuitbreakerreading;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.web.client.RestTemplate;

@EnableCircuitBreaker
@RestController
@SpringBootApplication
public class CircuitBreakerReadingApplication {

  @Autowired
  private BookService bookService;

  @Bean
  public RestTemplate rest(RestTemplateBuilder builder) {
  return builder.build();
  }

  @RequestMapping("/to-read")
  public String toRead() {
  return bookService.readingList();
  }

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

Now, to retrieve the list from the Bookstore service, you can call bookService.readingList(). You should also add one last annotation, @EnableCircuitBreaker. That annotation tells Spring Cloud that the reading application uses circuit breakers and to enable their monitoring, opening, and closing (behavior supplied, in our case, by Hystrix).

Try It

To test your circuit breaker, run both the bookstore service and the reading service and then open a browser to the reading service, at localhost:8080/to-read. You should see the complete recommended reading list, as the following listing shows:

Spring in Action (Manning), Cloud Native Java (O'Reilly), Learning Spring Boot (Packt)

Now stop the bookstore application. Your list source is gone, but thanks to Hystrix and Spring Cloud Netflix, you have a reliable abbreviated list to stand in the gap. You should see the following:

Cloud Native Java (O'Reilly)

Summary

Congratulations! You have just developed a Spring application that uses the circuit breaker pattern to protect against cascading failures and to provide fallback behavior for potentially failing calls.

See Also

The following guides may also be helpful:

Want to write a new guide or contribute to an existing one? Check out our contribution guidelines.

All guides are released with an ASLv2 license for the code, and an Attribution, NoDerivatives creative commons license for the writing.