1. Overview

In the last article we looked at the basics of Hystrix and how it can help with building a fault tolerant and resilient application.

There are lots of existing Spring applications that make calls to external systems that would benefit from Hystrix. Unfortunately, it may not be possible to rewrite these applications in order to integrate Hystrix, however a non-invasive way of integrating Hystrix is possible with the help of Spring AOP.

In this article we will look at how to integrate Hystrix with an existing Spring application.

2. Hystrix into a Spring Application

2.1. Existing Application

Let's take a look at the application's existing client caller which makes call to the RemoteServiceTestSimulator that we created in the previous article:

@Component("springClient")
public class SpringExistingClient {

    @Value("${remoteservice.timeout}")
    private int remoteServiceDelay;

    public String invokeRemoteServiceWithOutHystrix() throws InterruptedException {
        return new RemoteServiceTestSimulator(remoteServiceDelay).execute();
    }
}

As we can see in the above code snippet, the invokeRemoteServiceWithOutHystrix method is responsible for making calls to the RemoteServiceTestSimulator remote service. Of course, a real world applications will not be this simple.

2.2. Create an Around Advice

To demonstrate how to integrate Hystrix we are going to use this client as an example.

To do this, we will define an Around advice that will kick in when invokeRemoteService gets executed:

@Around("@annotation(com.baeldung.hystrix.HystrixCircuitBreaker)")
public Object circuitBreakerAround(ProceedingJoinPoint aJoinPoint) {
    return new RemoteServiceCommand(config, aJoinPoint).execute();
}

The above advice is designed as an Around advice to be executed at a pointcut annotated with @HystrixCircuitBreaker.

Now let's see the definition of the HystrixCircuitBreaker annotation*:*

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface HystrixCircuitBreaker {}

2.3. The Hystrix Logic

Now let's take a look at the RemoteServiceCommand. It is implemented as a static inner class in the sample code, so as to encapsulate the Hystrix invocation logic:

private static class RemoteServiceCommand extends HystrixCommand<String> {

    private ProceedingJoinPoint joinPoint;

    RemoteServiceCommand(Setter config, ProceedingJoinPoint joinPoint) {
        super(config);
        this.joinPoint = joinPoint;
    }

    @Override
    protected String run() throws Exception {
        try {
            return (String) joinPoint.proceed();
        } catch (Throwable th) {
            throw new Exception(th);
        }
    }
}

The whole implementation of Aspect component can be seen here.

2.4. Annotate With @HystrixCircuitBreaker

Once the aspect has been defined, we can annotate our client method with @HystrixCircuitBreaker as shown below and Hystrix will be provoked for every call to methods annotated:

@HystrixCircuitBreaker
public String invokeRemoteServiceWithHystrix() throws InterruptedException{
    return new RemoteServiceTestSimulator(remoteServiceDelay).execute();
}

The below integration test will demonstrate the difference between the Hystrix route and non Hystrix route.

2.5. Test the Integration

For the purpose of demonstration, we have defined two method execution routes one with Hystrix and other without.

public class SpringAndHystrixIntegrationTest {

    @Autowired
    private HystrixController hystrixController;

    @Test(expected = HystrixRuntimeException.class)
    public void givenTimeOutOf15000_whenClientCalledWithHystrix_thenExpectHystrixRuntimeException()
      throws InterruptedException {
        hystrixController.withHystrix();
    }

    @Test
    public void givenTimeOutOf15000_whenClientCalledWithOutHystrix_thenExpectSuccess()
      throws InterruptedException {
        assertThat(hystrixController.withOutHystrix(), equalTo("Success"));
    }
}

When the test executes, you can see that the method call without Hystrix will wait for the whole execution time of the remote service whereas the Hystrix route will short circuit and throw the HystrixRuntimeException after the defined timeout which in our case is 10 seconds.

3. Conclusion

We can create one aspect for each remote service call that we want to make with different configurations. In the next article we'll look at integrating Hystrix from the beginning of a project.

All code in this article can be found in the GitHub repository.