现有Spring应用的Hystrix集成

1.概述

上一篇文章中,我们研究了Hystrix的基础知识,以及它如何帮助构建容错和弹性应用程序。

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

在本文中,我们将了解如何将Hystrix与现有的Spring应用程序集成。

2. Hystrix成Spring应用程序

2.1 应用现状

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

1
2
3
4
5
6
7
8
9
10
@Component("springClient")
public class SpringExistingClient {

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

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

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

2.2 创建一个 Aspect Advice

为了演示如何集成Hystrix,我们将以此客户端为例。

为此,我们将定义一个在执行invokeRemoteService时将启动的Around Advice

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

上述建议被设计为在使用@HystrixCircuitBreaker注释的切入点处执行的Around建议。

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

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

2.3 Hystrix逻辑

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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);
}
}
}

可以在此处看到Aspect组件的整个实现。

2.4 添加 @HystrixCircuitBreaker 注解

一旦定义了 Aspect,我们就可以使用@HystrixCircuitBreaker注释我们的客户端方法,如下所示,并且每次调用注释的方法都会激发Hystrix:

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

以下积分测试将证明Hystrix路线和非Hystrix路线之间的差异。

2.5 测试集成

出于演示的目的,我们已经定义了两个方法执行路由,一个是Hystrix,另一个是没有。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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"));
}
}

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

3.结论

我们可以为每个远程服务调用创建一个方面,我们希望使用不同的配置。在下一篇文章中,我们将介绍从项目开始时集成Hystrix。