1. 概要
前回の記事では、Hystrixの基本と、フォールトトレラントで復元力のあるアプリケーションの構築にどのように役立つかについて説明しました。
Hystrixの恩恵を受ける外部システムを呼び出す既存のSpringアプリケーションがたくさんあります。残念ながら、Hystrixを統合するためにこれらのアプリケーションを書き直すことはできない場合がありますが、統合の非侵襲的な方法です。 HystrixはSpringAOPの助けを借りて可能です。
この記事では、Hystrixを既存のSpringアプリケーションと統合する方法を見ていきます。
2. 春のアプリケーションへのHystrix
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アドバイスを定義します:
@Around("@annotation(com.baeldung.hystrix.HystrixCircuitBreaker)")
public Object circuitBreakerAround(ProceedingJoinPoint aJoinPoint) {
return new RemoteServiceCommand(config, aJoinPoint).execute();
}
上記のアドバイスは、@HystrixCircuitBreakerで注釈が付けられたポイントカットで実行されるAroundアドバイスとして設計されています。
次に、 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で注釈を付ける
アスペクトが定義されたら、以下に示すように @HystrixCircuitBreaker でクライアントメソッドにアノテーションを付けることができ、アノテーションが付けられたメソッドへのすべての呼び出しに対してHystrixがトリガーされます。
@HystrixCircuitBreaker
public String invokeRemoteServiceWithHystrix() throws InterruptedException{
return new RemoteServiceTestSimulator(remoteServiceDelay).execute();
}
以下の統合テストは、Hystrixルートと非Hystrixルートの違いを示しています。
2.5. 統合をテストする
デモンストレーションの目的で、2つのメソッド実行ルートを定義しました。1つはHystrixあり、もう1つは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ルートは短絡し、定義されたタイムアウト後にHystrixRuntimeExceptionをスローします。 10秒です。
3. 結論
さまざまな構成で行うリモートサービス呼び出しごとに1つのアスペクトを作成できます。 次の記事では、プロジェクトの最初からHystrixを統合する方法について説明します。
この記事のすべてのコードは、GitHubリポジトリにあります。