Rendering RESTful service with React

Looking at the popularity of React, I thought of learning it and creating a simple UI which will render data from RESTful service.

With this post, I will try to replicate the steps I followed while writing it along with references. Before starting, let me give you a brief introduction about React.

What is React?

React is a declarative, efficient, and flexible JavaScript library for building user interfaces. It uses virtual DOM which improve apps performance since JavaScript virtual DOM is faster than the regular DOM with a limitation that it only covers view layer of the app so you still need to choose other technologies to get a complete tooling set for development.

Now, lets’ start with creating react-app running on port 8080, following below steps:

Step 1: Go to start.spring.io and create a new project react-app adding the Thymeleaf starters, based on the following image:

Screen Shot 2017-05-06 at 2.53.30 pm.png
Step 2: Edit ReactAppApplication.java to add a method which returns a list of employee, as follows:

package com.arpit.react.app;

import java.util.ArrayList;
import java.util.List;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@SpringBootApplication
@RestController
public class ReactAppApplication {

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

	@GetMapping("/employee/get")
	public List<Employee> get() {
		List<Employee> employeeList = new ArrayList<>();
		employeeList.add(new Employee(1, "Arpit", "IT"));
		employeeList.add(new Employee(2, "Sanjeev", "IT"));
		return employeeList;
	}
}

@Controller
class IndexPageController {

	@GetMapping(value = "/")
	public String index() {
		return "index";
	}
}

final class Employee {

	private int id;
	private String name;
	private String department;

	public Employee() {

	}

	public Employee(final int id, final String name, final String department) {
		this.id = id;
		this.name = name;
		this.department = department;
	}

	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getDepartment() {
		return department;
	}

	public void setDepartment(String department) {
		this.department = department;
	}
}

IndexPageController define index() method flagged by @GetMapping(value = “/”) to support the / route. It returns index as the name of the template, which Spring Boot’s autoconfigured view resolver will map to src/main/resources/templates/index.html.

Step 3: Define an HTML template src/main/resources/templates/index.html with the following content:

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head lang="en">
<meta charset="UTF-8" />
<title>React with Spring REST</title>
</head>
<body>
	<div id="react"></div>
	<script src="package/script.js"></script>
</body>
</html>

Step 4: Move to react-app directory and run command: mvn spring-boot:run. Once running open http://localhost:8080/employee/get which will give you the list of employees we are going to render on UI built with React.

Step 5: Next we will add frontend-maven-plugin in pom.xml  to install Node and NPM locally for the react-app followed by running Webpack  build, as follows:

<plugin>
				<groupId>com.github.eirslett</groupId>
				<artifactId>frontend-maven-plugin</artifactId>
				<version>1.2</version>
				<configuration>
					<installDirectory>target</installDirectory>
				</configuration>
				<executions>
					<execution>
						<id>install node and npm</id>
						<goals>
							<goal>install-node-and-npm</goal>
						</goals>
						<configuration>
							<nodeVersion>v4.4.5</nodeVersion>
							<npmVersion>3.9.2</npmVersion>
						</configuration>
					</execution>
					<execution>
						<id>npm install</id>
						<goals>
							<goal>npm</goal>
						</goals>
						<configuration>
							<arguments>install</arguments>
						</configuration>
					</execution>
					<execution>
						<id>webpack build</id>
						<goals>
							<goal>webpack</goal>
						</goals>
					</execution>
				</executions>
</plugin>

Step 6: Execute npm init in the root directory to create package.json in which we specify all the dependencies required to build our react-app like React, React DOM, Webpack, Babel Loader, Babel Core, Babel Preset: ES2015, Babel Preset: React, as follows:

$ cd react-app
$ touch npm init

Copy the following content:

{
  "name": "react-app",
  "version": "1.0.0",
  "description": "Rendering RESTful service with React",
  "repository": {
    "type": "git",
    "url": "git@github.com:arpitaggarwal/react-app.git"
  },
  "keywords": [
    "rest",
    "spring",
    "react"
  ],
  "author": "Arpit Aggarwal",
  "dependencies": {
    "axios": "^0.16.1",
    "react": "^15.3.2",
    "react-dom": "^15.3.2",
    "webpack": "^1.12.2"
  },
  "scripts": {
    "watch": "webpack --watch -d"
  },
  "devDependencies": {
    "babel-core": "^6.18.2",
    "babel-loader": "^6.2.7",
    "babel-polyfill": "^6.16.0",
    "babel-preset-es2015": "^6.18.0",
    "babel-preset-react": "^6.16.0"
  }
}

Step 7: Next we will create webpack.config.js to configure webpack, as follows:

$ cd react-app
$ touch webpack.config.js

Copy the following content:

var path = require('path');

module.exports = {
    entry: './app/main.js',
    cache: true,
    debug: true,
    output: {
        path: __dirname,
        filename: './src/main/resources/static/package/script.js'
    },
    module: {
        loaders: [
            {
                test: path.join(__dirname, '.'),
                exclude: /(node_modules)/,
                loader: 'babel',
                query: {
                    cacheDirectory: true,
                    presets: ['es2015', 'react']
                }
            }
        ]
    }
};

entry option specified above is the entry point for the bundle.
cache option specified above Cache generated modules and chunks to improve performance for multiple incremental builds.
output option specified above tell Webpack how to write the compiled files to disk.

For more configuration options you can explore here.

Step 8: Next we will create entry point for the webpack which is react-app/app/main.js, as:

$ cd react-app
$ mkdir app
$ cd app
$ touch main.js

Copy the following content:

'use strict';
const React = require('react');
const ReactDOM = require('react-dom')

import ReactApp from './components/react-app.jsx'

ReactDOM.render(
		<ReactApp />,
	document.getElementById('react')
)

React is the main library from Facebook for building the app.
ReactDOM provides DOM-specific methods that can be used at the top level.
ReactApp is the top level container for all React components.

Let’s define ReactApp along with it’s child components, as:

$ cd react-app/app/
$ mkdir components
$ cd components
$ touch react-app.jsx employee-list.jsx employee.jsx 

react-spring/app/components/react-app.jsx

'use strict';
const React = require('react');
var axios = require('axios');

import EmployeeList from './employee-list.jsx'

export default class ReactApp extends React.Component {

	constructor(props) {
		super(props);
		this.state = {employees: []};
		this.Axios = axios.create({
		    baseURL: "/employee",
		    headers: {'content-type': 'application/json', 'creds':'user'}
		});
	}

	componentDidMount() {
		let _this = this;
		this.Axios.get('/get')
		  .then(function (response) {
		     console.log(response);
		    _this.setState({employees: response.data});
		  })
		  .catch(function (error) {
		    console.log(error);
		  });
	}

	render() {
		return (
				<div>
				  <EmployeeList employees={this.state.employees}/>
		        </div>
			)
	}
}

react-spring/app/components/employee-list.jsx

const React = require('react');
import Employee from './employee.jsx'

export default class EmployeeList extends React.Component{
    
    render() {
		var employees = this.props.employees.map((employee, i) =>
			<Employee key={i} employee={employee}/>
		);
		
		return (
			<table>
				<tbody>
					<tr>
						<th>ID</th>
						<th>Name</th>
						<th>Department</th>
					</tr>
					{employees}
				</tbody>
			</table>
		)
	}
}

react-spring/app/components/employee.jsx

const React = require('react');

export default class Employee extends React.Component{
	render() {
		return (
			<tr>
				<td>{this.props.employee.id}</td>
				<td>{this.props.employee.name}</td>
				<td>{this.props.employee.department}</td>
			</tr>
		)
	}
}

With all this in place, your directory structure should look like:

Screen Shot 2017-05-06 at 4.49.26 pm

Now re-run the application and visit http://localhost:8080.

Complete source code is hosted on github.

Writing and Consuming SOAP Webservice with Spring

In the era of RESTful Web Services, I got a chance to consume SOAP Web Service. To do the same I chosen Spring, reason being we are already using Spring as backend framework in our project and secondly it provides an intuitive way to interact service(s) with well-defined boundaries to promote reusability and portability through WebServiceTemplate.

Assuming you already know about SOAP Web Services, let’s start creating hello-world soap service running on port 9999 and client to consume the same, following below steps:

Step 1: Go to start.spring.io and create a new project soap-server adding the Web starters, based on the following image:

soap-server

Step 2: Edit SoapServerApplication.java to publish the hello-world service at Endpoint – http://localhost:9999/service/hello-world, as follows:


package com.arpit.soap.server.main;

import javax.xml.ws.Endpoint;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

import com.arpit.soap.server.service.impl.HelloWorldServiceImpl;

@SpringBootApplication
public class SoapServerApplication implements CommandLineRunner {

	@Value("${service.port}")
	private String servicePort;

	@Override
	public void run(String... args) throws Exception {
		Endpoint.publish("http://localhost:" + servicePort
				+ "/service/hello-world", new HelloWorldServiceImpl());
	}

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


Step 3: Edit application.properties to specify the application name, port and port number of hello-world service, as follows:

server.port=9000
spring.application.name=soap-server

## Soap Service Port
service.port=9999

Step 4: Create additional packages as com.arpit.soap.server.service and com.arpit.soap.server.service.impl to define the Web Service and it’s implementation, as follows:

HelloWorldService.java

package com.arpit.soap.server.service;

import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebService;

import com.arpit.soap.server.model.ApplicationCredentials;

@WebService
public interface HelloWorldService {

	@WebMethod(operationName = "helloWorld", action = "https://aggarwalarpit.wordpress.com/hello-world/helloWorld")
	String helloWorld(final String name,
			@WebParam(header = true) final ApplicationCredentials credential);

}

@WebService specified above marks a Java class as implementing a Web Service, or a Java interface as defining a Web Service interface.

@WebMethod specified above marks a Java method as a Web Service operation.

@WebParam specified above customize the mapping of an individual parameter to a Web Service message part and XML element.

HelloWorldServiceImpl.java

package com.arpit.soap.server.service.impl;

import javax.jws.WebService;

import com.arpit.soap.server.model.ApplicationCredentials;
import com.arpit.soap.server.service.HelloWorldService;

@WebService(endpointInterface = "com.arpit.soap.server.service.HelloWorldService")
public class HelloWorldServiceImpl implements HelloWorldService {

	@Override
	public String helloWorld(final String name,
			final ApplicationCredentials credential) {
		return "Hello World from " + name;
	}
}

Step 5: Move to soap-server directory and run command: mvn spring-boot:run. Once running, open http://localhost:9999/service/hello-world?wsdl to view the WSDL for the hello-world service.

Next, we will create soap-client which will consume our newly created hello-world service.

Step 6: Go to start.spring.io and create a new project soap-client adding the Web, Web Services starters, based on the following image:

soap-client.png

Step 7: Edit SoapClientApplication.java to create a request to hello-world web service, sending the same to soap-server along with header and get the response from it, as follows:


package com.arpit.soap.client.main;

import java.io.IOException;
import java.io.StringWriter;

import javax.xml.bind.JAXBElement;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamResult;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.ws.WebServiceMessage;
import org.springframework.ws.client.core.WebServiceMessageCallback;
import org.springframework.ws.client.core.WebServiceTemplate;
import org.springframework.ws.soap.SoapMessage;
import org.springframework.xml.transform.StringSource;

import com.arpit.soap.server.service.ApplicationCredentials;
import com.arpit.soap.server.service.HelloWorld;
import com.arpit.soap.server.service.HelloWorldResponse;
import com.arpit.soap.server.service.ObjectFactory;

@SpringBootApplication
@ComponentScan("com.arpit.soap.client.config")
public class SoapClientApplication implements CommandLineRunner {

	@Autowired
	@Qualifier("webServiceTemplate")
	private WebServiceTemplate webServiceTemplate;

	@Value("#{'${service.soap.action}'}")
	private String serviceSoapAction;

	@Value("#{'${service.user.id}'}")
	private String serviceUserId;

	@Value("#{'${service.user.password}'}")
	private String serviceUserPassword;

	public static void main(String[] args) {
		SpringApplication.run(SoapClientApplication.class, args);
		System.exit(0);
	}

	public void run(String... args) throws Exception {
		final HelloWorld helloWorld = createHelloWorldRequest();
		@SuppressWarnings("unchecked")
		final JAXBElement<HelloWorldResponse> jaxbElement = (JAXBElement<HelloWorldResponse>) sendAndRecieve(helloWorld);
		final HelloWorldResponse helloWorldResponse = jaxbElement.getValue();
		System.out.println(helloWorldResponse.getReturn());
	}

	private Object sendAndRecieve(HelloWorld seatMapRequestType) {
		return webServiceTemplate.marshalSendAndReceive(seatMapRequestType,
				new WebServiceMessageCallback() {
					public void doWithMessage(WebServiceMessage message)
							throws IOException, TransformerException {
						SoapMessage soapMessage = (SoapMessage) message;
						soapMessage.setSoapAction(serviceSoapAction);
						org.springframework.ws.soap.SoapHeader soapheader = soapMessage
								.getSoapHeader();
						final StringWriter out = new StringWriter();
						webServiceTemplate.getMarshaller().marshal(
								getHeader(serviceUserId, serviceUserPassword),
								new StreamResult(out));
						Transformer transformer = TransformerFactory
								.newInstance().newTransformer();
						transformer.transform(new StringSource(out.toString()),
								soapheader.getResult());
					}
				});
	}

	private Object getHeader(final String userId, final String password) {
		final https.aggarwalarpit_wordpress.ObjectFactory headerObjectFactory = new https.aggarwalarpit_wordpress.ObjectFactory();
		final ApplicationCredentials applicationCredentials = new ApplicationCredentials();
		applicationCredentials.setUserId(userId);
		applicationCredentials.setPassword(password);
		final JAXBElement<ApplicationCredentials> header = headerObjectFactory
				.createApplicationCredentials(applicationCredentials);
		return header;
	}

	private HelloWorld createHelloWorldRequest() {
		final ObjectFactory objectFactory = new ObjectFactory();
		final HelloWorld helloWorld = objectFactory.createHelloWorld();
		helloWorld.setArg0("Arpit");
		return helloWorld;
	}

}

Step 8: Next, create additional package com.arpit.soap.client.config to configure WebServiceTemplate, as follows:

ApplicationConfig.java

package com.arpit.soap.client.config;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
import org.springframework.oxm.jaxb.Jaxb2Marshaller;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.ws.client.core.WebServiceTemplate;
import org.springframework.ws.soap.saaj.SaajSoapMessageFactory;
import org.springframework.ws.transport.http.HttpComponentsMessageSender;

@Configuration
@EnableWebMvc
public class ApplicationConfig extends WebMvcConfigurerAdapter {

	@Value("#{'${service.endpoint}'}")
	private String serviceEndpoint;

	@Value("#{'${marshaller.packages.to.scan}'}")
	private String marshallerPackagesToScan;

	@Value("#{'${unmarshaller.packages.to.scan}'}")
	private String unmarshallerPackagesToScan;

	@Bean
	public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
		return new PropertySourcesPlaceholderConfigurer();
	}

	@Bean
	public SaajSoapMessageFactory messageFactory() {
		SaajSoapMessageFactory messageFactory = new SaajSoapMessageFactory();
		messageFactory.afterPropertiesSet();
		return messageFactory;
	}

	@Bean
	public Jaxb2Marshaller marshaller() {
		Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
		marshaller.setPackagesToScan(marshallerPackagesToScan.split(","));
		return marshaller;
	}

	@Bean
	public Jaxb2Marshaller unmarshaller() {
		Jaxb2Marshaller unmarshaller = new Jaxb2Marshaller();
		unmarshaller.setPackagesToScan(unmarshallerPackagesToScan.split(","));
		return unmarshaller;
	}

	@Bean
	public WebServiceTemplate webServiceTemplate() {
		WebServiceTemplate webServiceTemplate = new WebServiceTemplate(
				messageFactory());
		webServiceTemplate.setMarshaller(marshaller());
		webServiceTemplate.setUnmarshaller(unmarshaller());
		webServiceTemplate.setMessageSender(messageSender());
		webServiceTemplate.setDefaultUri(serviceEndpoint);
		return webServiceTemplate;
	}

	@Bean
	public HttpComponentsMessageSender messageSender() {
		HttpComponentsMessageSender httpComponentsMessageSender = new HttpComponentsMessageSender();
		return httpComponentsMessageSender;
	}
}

Step 9: Edit application.properties to specify the application name, port and hello-world soap web service configurations, as follows:

server.port=9000
spring.application.name=soap-client

## Soap Service Configuration

service.endpoint=http://localhost:9999/service/hello-world
service.soap.action=https://aggarwalarpit.wordpress.com/hello-world/helloWorld
service.user.id=arpit
service.user.password=arpit
marshaller.packages.to.scan=com.arpit.soap.server.service
unmarshaller.packages.to.scan=com.arpit.soap.server.service

service.endpoint specified above is the URL provided to the service user to invoke the services exposed by the service provider.

service.soap.action specifies which process or program that need to be called when a request is sent by the service requester and also defines the relative path of the process/program.

marshaller.packages.to.scan specifies the packages to scan at time of marshalling before sending the request to the server.

unmarshaller.packages.to.scan specifies the packages to scan at time of unmarshalling after receiving the request from the server.

Now, we will generate Java Objects from WSDL using wsimport and copy it to the soap-client project executing below command on the terminal:

wsimport -keep -verbose http://localhost:9999/service/hello-world?wsdl

Step 10: Move to soap-client directory and run command: mvn spring-boot:run. Once command finishes we will see “Hello World from Arpit” as response from hello-world soap service on console.

While running if you are getting error as – Unable to marshal type “com.arpit.soap.server.service.HelloWorld” as an element because it is missing an @XmlRootElement annotation then add @XmlRootElement(name = “helloWorld”, namespace = “http://service.server.soap.arpit.com/ “) to the com.arpit.soap.server.service.HelloWorld, where namespace should be matched from xmlns:ser defined in soap envelope, as below:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ser="http://service.server.soap.arpit.com/">
   <soapenv:Header>
      <ser:arg1>
         <userId>arpit</userId>
         <password>arpit</password>
      </ser:arg1>
   </soapenv:Header>
   <soapenv:Body>
      <ser:helloWorld>
         <!--Optional:-->
         <arg0>Arpit</arg0>
      </ser:helloWorld>
   </soapenv:Body>
</soapenv:Envelope>

The complete source code is hosted on github.

Microservices fault and latency tolerance using Netflix Hystrix

Recently in one of my project I got a requirement to execute a fallback call for a failing webservice call. To implement the same I was looking for some implementation of circuit breaker pattern and finally came across Netflix Hystrix library which I found is the best suited library as per our application.

In this post I tried to showcase a thin example of our problem and how Hystrix solved the same using a single microservice and a client to access it along with Hystrix Dashboard. Before diving into coding, let’s understand in brief what Hystrix is and how it works internally.

What is Hystrix?

Hystrix is a library that helps us control the interactions between the distributed services by adding latency tolerance and fault tolerance logic. It does this by isolating points of access between the services, stopping cascading failures across them, and providing fallback options, all of which improve our system’s overall resiliency.

It implements the circuit breaker pattern which work on circuit-breaker transitions from CLOSED to OPEN when a circuit meets a specified threshold and error percentage exceeds the threshold error percentage. While it is open, it short-circuits all requests made against that circuit-breaker. After some amount of time, the next single request is let through (this is the HALF-OPEN state). If the request fails, the circuit-breaker returns to the OPEN state for the duration of the sleep window. If the request succeeds, the circuit-breaker transitions to CLOSED and all requests made against that circuit-breaker are passed through to the service. More you can explore here.

Now, let’s start creating employee-service microservice running on port 8090 and client to access the same along with Hystrix Dashboard following below steps:

Step 1: Go to start.spring.io and create a new project employee-service adding the Web starters, based on the following image:

screen-1

Step 2: Edit EmployeeServiceApplication.java to add a method which returns a list of employee, as follows:

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

@SpringBootApplication
@RestController
public class EmployeeServiceApplication {

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

 @RequestMapping(value = "/list")
 public String list() {
	return "Arpit, Sanjeev, Abhishek";
 }
}

Step 3: Edit application.properties to specify the application name and port number of a service, as follows:

server.port=8090
spring.application.name=employee-service

Step 4: Move to employee-service directory and run command: mvn spring-boot:run. Once running, open http://localhost:8090/list.

Next, we will create hystrix-client which will access our newly created employee-service and if it is down will return the response from fallback method.

Step 5: Go to start.spring.io and create a new project hystrix-client adding the Web, Hystrix and Actuator starters, based on the following image:

screen-2

 

Step 6: Edit HystrixClientApplication.java to add a method which calls employee-service to get a response and if service is down or unavailable because of any reason return a response from fallback method, as follows:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.netflix.hystrix.EnableHystrix;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;

import com.test.service.IEmployeeService;

@EnableHystrix
@EnableCircuitBreaker
@SpringBootApplication
@RestController
@ComponentScan(basePackages = { "com.test.service" })
public class HystrixClientApplication {

@Autowired
private IEmployeeService employeeService;

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

@RequestMapping("/list")
public String list() {
	return employeeService.list();
}

  static class ApplicationConfig extends WebMvcConfigurerAdapter {

	@Bean
	public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
		return new PropertySourcesPlaceholderConfigurer();
	}
  }
}

Step 7: Create interface IEmployeeService and it’s implementation class EmployeeServiceImpl under com.test.service package and edit them as follows:

IEmployeeService.java

package com.test.service;

public interface IEmployeeService {
  String list();
}

EmployeeServiceImpl.java

package com.test.service.impl;

import java.net.URI;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
import com.test.service.IEmployeeService;

@Service
public class EmployeeServiceImpl implements IEmployeeService {

 @Value("#{'${employee.service.url}'}")
 private String employeeServiceUrl;

 @HystrixCommand(commandProperties = {
			@HystrixProperty(name = "execution.isolation.strategy", value = "THREAD"),
			@HystrixProperty(name = "execution.timeout.enabled", value = "true"),
			@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "500"),
			@HystrixProperty(name = "execution.isolation.thread.interruptOnTimeout", value = "true"),
			@HystrixProperty(name = "fallback.enabled", value = "true"),
			@HystrixProperty(name = "circuitBreaker.enabled", value = "true"),
			@HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "10"),
			@HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds", value = "1000"),
			@HystrixProperty(name = "circuitBreaker.errorThresholdPercentage", value = "10"),
			@HystrixProperty(name = "circuitBreaker.forceOpen", value = "false"),
			@HystrixProperty(name = "circuitBreaker.forceClosed", value = "false") }, fallbackMethod = "fallback", commandKey = "list", groupKey = "EmployeeServiceImpl", threadPoolKey = "thread-pool-employee-service", threadPoolProperties = { @HystrixProperty(name = "coreSize", value = "5") }, ignoreExceptions = { IllegalAccessException.class })
 public String list() {
	RestTemplate restTemplate = new RestTemplate();
	URI uri = URI.create(employeeServiceUrl + "/list");
	return restTemplate.getForObject(uri, String.class);
 }
 
 public String fallback() {
	return "Fallback call, seems employee service is down";
 }
}

@HystrixCommand specified above is used to wrap code that will execute potentially risky functionality with fault and latency tolerance, statistics and performance metrics capture, circuit breaker and bulkhead functionality.

@HystrixProperty specified above is used to control HystrixCommand behavior. All available options are listed here.

Step 8: Edit application.properties to specify the application port on which hystrix-client should be running and url on which employee-service is available, as follows:

server.port=8080
employee.service.url=http://localhost:8090

Step 9: Move to hystrix-client directory and run command: mvn spring-boot:run. Once running, open http://localhost:8080/list.

Is Hystrix working?

Shut down the employee-service application. Fallback message should be seen : Fallback call, seems employee service is down.

Next, we will create Hystrix Dashboard which will provide us the graphical view of success and failure requests, circuit status, host, cluster and thread pool status of an application.

Step 10: Go to start.spring.io and create a new project hystrix-dashboard adding the Hystrix Dashboard starters. Once created edit HystrixDashboardApplication.java, as follows:

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.hystrix.dashboard.EnableHystrixDashboard;

@SpringBootApplication
@EnableHystrixDashboard
public class HystrixDashboardApplication {

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

Step 11: Edit application.properties to specify the application port on which hystrix-dashboard should be running, as follows:

server.port=8383

Step 12: Move to hystrix-dashboard directory and run command: mvn spring-boot:run. Once running, open http://localhost:8383/hystrix and enter http://localhost:8080/hystrix.stream in stream textbox and click Monitor Stream. Once dashboard is loaded we will see image similar to below:

screen-3

The complete source code is hosted on github.