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リポジトリにあります。