Hystrix Integration with Existing Spring Application – Hystrix与现有的Spring应用程序的集成

最后修改: 2016年 8月 28日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

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

上一篇文章中,我们探讨了Hystrix的基本知识,以及它如何帮助建立一个容错和弹性的应用程序。

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.

有很多现有的Spring应用程序对外部系统进行调用,这些应用程序将从Hystrix中受益。不幸的是,为了集成Hystrix,可能无法重写这些应用程序,但是在Spring AOP的帮助下,可以采用非侵入式的方式集成Hystrix。

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

在这篇文章中,我们将看看如何将Hystrix与现有的Spring应用程序集成。

2. Hystrix into a Spring Application

2.将Hystrix纳入一个Spring应用程序

2.1. Existing Application

2.1.现有的应用程序

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:

让我们看一下应用程序现有的客户端调用程序,该程序调用了我们在上一篇文章中创建的RemoteServiceTestSimulator

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

正如我们在上面的代码片段中看到的,invokeRemoteServiceWithOutHystrix方法负责对RemoteServiceTestSimulator远程服务进行调用。当然,现实世界的应用不会这么简单。

2.2. Create an Around Advice

2.2.创建一个周边建议

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

为了演示如何整合Hystrix,我们将使用这个客户端作为一个例子。

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

为此,我们将定义一个Around建议,它将在invokeRemoteService被执行时启动

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

上述建议被设计成一个Around建议,在被注解为@HystrixCircuitBreaker的点cut上执行。

Now let’s see the definition of the HystrixCircuitBreaker annotation:

现在让我们看看HystrixCircuitBreaker注释的定义

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

2.3. The Hystrix Logic

2.3.Hystrix逻辑

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:

现在让我们看一下RemoteServiceCommand。在示例代码中,它被实现为一个静态内部类,以便封装Hystrix的调用逻辑。

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.

Aspect组件的整个实现可以在这里看到。

2.4. Annotate With @HystrixCircuitBreaker

2.4.用@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来注释我们的客户端方法,如下图所示,Hystrix将在每次调用注释的方法时被激发。

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

下面的集成测试将展示Hystrix路由和非Hystrix路由之间的区别。

2.5. Test the Integration

2.5.测试集成

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

为了演示,我们定义了两条方法执行路线,一条有Hystrix,另一条没有。

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.

当测试执行时,你可以看到,没有Hystrix的方法调用将等待整个远程服务的执行时间,而Hystrix路由将短路并在定义的超时后抛出HystrixRuntimeException,在我们的例子中是10秒。

3. Conclusion

3.总结

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.

我们可以为每一个我们想用不同配置进行的远程服务调用创建一个方面。在下一篇文章中,我们将看看如何从项目的开始整合Hystrix。

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

本文的所有代码都可以在GitHub资源库中找到。