Spring Cloudシリーズ - ゲートウェイパターン

Spring Cloudシリーズ–ゲートウェイパターン

1. 概要

So far、クラウドアプリケーションでは、ゲートウェイパターンを使用して2つの主要な機能をサポートしています。

まず、各サービスからクライアントを隔離し、クロスオリジンサポートの必要性を排除しました。 次に、Eurekaを使用してサービスのインスタンスの検索を実装しました。

この記事では、retrieve data from multiple services with a single requestへのゲートウェイパターンの使用方法を見ていきます。 これを行うために、Feignをゲートウェイに導入して、サービスへのAPI呼び出しの記述を支援します。

Feignクライアントの使用方法を確認するには、this articleを確認してください。

Spring Cloudは、このパターンを実装するSpring Cloud Gatewayプロジェクトも提供するようになりました。

2. セットアップ

gatewayサーバーのpom.xmlを開き、Feignの依存関係を追加しましょう。


    org.springframework.cloud
    spring-cloud-starter-feign

参考までに–Maven Centralspring-cloud-starter-feign)で最新バージョンを見つけることができます。

Feignクライアントの構築がサポートされたので、GatewayApplication.javaで有効にしましょう。

@EnableFeignClients
public class GatewayApplication { ... }

それでは、書籍と評価サービス用にFeignクライアントを設定しましょう。

3. 偽のクライアント

3.1. ブッククライアント

BooksClient.javaという新しいインターフェースを作成しましょう。

@FeignClient("book-service")
public interface BooksClient {

    @RequestMapping(value = "/books/{bookId}", method = RequestMethod.GET)
    Book getBookById(@PathVariable("bookId") Long bookId);
}

このインターフェースを使用して、「/books/\{bookId}」エンドポイントにアクセスするFeignクライアントを作成するようにSpringに指示しています。 呼び出されると、getBookByIdメソッドはエンドポイントへのHTTP呼び出しを行い、bookIdパラメータを利用します。

これを機能させるには、Book.javaDTOを追加する必要があります。

@JsonIgnoreProperties(ignoreUnknown = true)
public class Book {

    private Long id;
    private String author;
    private String title;
    private List ratings;

    // getters and setters
}

RatingsClientに移りましょう。

3.2. 評価クライアント

RatingsClientというインターフェイスを作成しましょう。

@FeignClient("rating-service")
public interface RatingsClient {

    @RequestMapping(value = "/ratings", method = RequestMethod.GET)
    List getRatingsByBookId(
      @RequestParam("bookId") Long bookId,
      @RequestHeader("Cookie") String session);

}

BookClientと同様に、ここで公開されているメソッドは、評価サービスにREST呼び出しを行い、本の評価のリストを返します。

ただし、このエンドポイントは保護されています。 To be able to access this endpoint properly we need to pass the user’s session to the request.

これは、@RequestHeaderアノテーションを使用して行います。 これにより、Feignはその変数の値をリクエストのヘッダーに書き込むように指示されます。 この例では、Spring SessionがCookieでセッションを検索するため、Cookieヘッダーに書き込んでいます。

この例では、Spring SessionがCookieでセッションを検索するため、Cookieヘッダーに書き込んでいます。

最後に、Rating.javaDTOを追加しましょう。

@JsonIgnoreProperties(ignoreUnknown = true)
public class Rating {
    private Long id;
    private Long bookId;
    private int stars;
}

これで、両方のクライアントが完成しました。 それらを使ってみましょう!

4. 複合リクエスト

Gatewayパターンの一般的な使用例の1つは、一般的に呼ばれるサービスをカプセル化するエンドポイントを持つことです。 これにより、クライアント要求の数が減り、パフォーマンスが向上します。

これを行うには、コントローラーを作成してCombinedController.javaと呼びます。

@RestController
@RequestMapping("/combined")
public class CombinedController { ... }

次に、新しく作成した偽のクライアントを接続しましょう。

private BooksClient booksClient;
private RatingsClient ratingsClient;

@Autowired
public CombinedController(
  BooksClient booksClient,
  RatingsClient ratingsClient) {

    this.booksClient = booksClient;
    this.ratingsClient = ratingsClient;
}

最後に、これら2つのエンドポイントを組み合わせて、評価が読み込まれた1冊の本を返すGETリクエストを作成しましょう。

@GetMapping
public Book getCombinedResponse(
  @RequestParam Long bookId,
  @CookieValue("SESSION") String session) {

    Book book = booksClient.getBookById(bookId);
    List ratings = ratingsClient.getRatingsByBookId(bookId, "SESSION="+session);
    book.setRatings(ratings);
    return book;
}

リクエストからセッション値を抽出する@CookieValueアノテーションを使用してセッション値を設定していることに注意してください。

そこにそれがある! ゲートウェイには、クライアントとシステム間のネットワークコールを減らす複合エンドポイントがあります!

5. テスト

新しいエンドポイントが機能していることを確認しましょう。

LiveTest.javaに移動し、結合されたエンドポイントのテストを追加しましょう。

@Test
public void accessCombinedEndpoint() {
    Response response = RestAssured.given()
      .auth()
      .form("user", "password", formConfig)
      .get(ROOT_URI + "/combined?bookId=1");

    assertEquals(HttpStatus.OK.value(), response.getStatusCode());
    assertNotNull(response.getBody());

    Book result = response.as(Book.class);

    assertEquals(new Long(1), result.getId());
    assertNotNull(result.getRatings());
    assertTrue(result.getRatings().size() > 0);
}

Redisを起動し、アプリケーションで各サービス(config, discovery, zipkin,gatewaybook、およびratingサービス)を実行します。

すべてが起動したら、新しいテストを実行して機能していることを確認します。

6. 結論

Feignをゲートウェイに統合して、特殊なエンドポイントを構築する方法を見てきました。 この情報を活用して、サポートが必要なAPIを構築できます。 最も重要なことは、個々のリソースのみを公開する万能型APIにとらわれていないことです。

ゲートウェイパターンを使用して、各クライアントのニーズに合わせてゲートウェイサービスを独自に設定できます。 これにより、デカップリングが作成され、サービスが必要に応じて自由に進化できるようになり、無駄のないままアプリケーションの1つの領域に集中できます。

いつものように、コードスニペットはover on GitHub.で見つけることができます