1. 概述
在上一篇文章中,我们探讨了Hystrix的基本概念以及它如何帮助构建健壮的容错应用。许多现有的Spring应用调用外部系统时,都可以从Hystrix中受益。不幸的是,可能无法重写这些应用以集成Hystrix,但借助于Spring AOP,我们可以以非侵入的方式将Hystrix融入其中。
本篇文章将介绍如何将Hystrix与现有Spring应用集成。
2. 将Hystrix融入Spring应用
2.1. 当前应用
让我们先看看应用中现有的客户端调用者,它调用了我们在上一篇文章中创建的RemoteServiceTestSimulator
:
@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. 创建环绕通知
为了演示如何集成Hystrix,我们将使用这个客户端作为示例。为此,我们将定义一个环绕通知,当invokeRemoteService
执行时触发:
@Around("@annotation(com.baeldung.hystrix.HystrixCircuitBreaker)")
public Object circuitBreakerAround(ProceedingJoinPoint aJoinPoint) {
return new RemoteServiceCommand(config, aJoinPoint).execute();
}
上述通知设计为一个带有@HystrixCircuitBreaker
注解的切点上的环绕通知。
现在来看看HystrixCircuitBreaker
注解的定义:*
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface HystrixCircuitBreaker {}
2.3. Hystrix逻辑
接下来,我们看看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);
}
}
}
整个Aspect
组件的实现可以在这里看到。
2.4. 使用@HystrixCircuitBreaker
注解
一旦定义了Aspect
,我们可以在客户端方法上添加@HystrixCircuitBreaker
注解,如下所示,Hystrix会在每个带有此注解的方法调用时被触发:
@HystrixCircuitBreaker
public String invokeRemoteServiceWithHystrix() throws InterruptedException{
return new RemoteServiceTestSimulator(remoteServiceDelay).execute();
}
下面的集成测试将展示Hystrix路由和非Hystrix路由之间的差异。
2.5. 测试集成
为了演示,我们定义了两种方法执行路线,一种带有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"));
}
}
当测试执行时,你可以看到没有Hystrix的调用会等待远程服务的整个执行时间,而Hystrix路由会在定义的超时(在我们的例子中是10秒)后短路并抛出HystrixRuntimeException
。
3. 总结
我们可以为每个想要调用的不同远程服务创建一个单独的Aspect
,每个Aspect
都有不同的配置。在下一篇文章中,我们将从项目开始时就集成Hystrix。本文的所有代码可以在GitHub仓库中找到。