Серия Spring Cloud - Модель Ворот

Весенняя серия облаков - модель ворот

1. обзор

So far, в нашем облачном приложении мы использовали шаблон шлюза для поддержки двух основных функций.

Во-первых, мы изолировали наших клиентов от каждой услуги, устраняя необходимость в поддержке из разных стран. Далее мы реализовали поиск экземпляров сервисов с помощью Eureka.

В этой статье мы рассмотрим, как использовать шаблон шлюза дляretrieve data from multiple services with a single request. Для этого мы собираемся внедрить Feign в наш шлюз, чтобы помочь писать вызовы API нашим сервисам.

Чтобы узнать, как использовать клиент Feign, просмотритеthis article.

Spring Cloud теперь также предоставляет проектSpring Cloud Gateway, который реализует этот шаблон.

2. Настроить

Давайте откроемpom.xml нашего сервераgateway и добавим зависимость для Feign:


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

Для справки - последние версии можно найти наMaven Central (spring-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);
}

С помощью этого интерфейса мы инструктируем Spring создать клиент Feign, который будет обращаться к конечной точке «/books/\{bookId}». При вызове методgetBookById выполняет HTTP-вызов конечной точки и использует параметрbookId.

Чтобы это работало, нам нужно добавить DTOBook.java:

@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, метод, представленный здесь, выполнит вызов нашей рейтинговой службы и вернет список оценок для книги.

Однако эта конечная точка защищена. To be able to access this endpoint properly we need to pass the user’s session to the request.с

Мы делаем это с помощью аннотации@RequestHeader. Это заставит Feign записать значение этой переменной в заголовок запроса. В нашем случае мы пишем в заголовокCookie, потому что Spring Session будет искать наш сеанс в файле cookie.

В нашем случае мы пишем в заголовокCookie, потому что Spring Session будет искать наш сеанс в файле cookie.

Наконец, давайте добавим DTORating.java:

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

Теперь оба клиента готовы. Давайте воспользуемся ими!

4. Комбинированный запрос

Один из наиболее распространенных вариантов использования шаблона шлюза - иметь конечные точки, которые инкапсулируют обычно называемые службы. Это может повысить производительность за счет уменьшения количества клиентских запросов.

Для этого давайте создадим контроллер и назовем его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;
}

И, наконец, давайте создадим запрос 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,gateway,book и службуrating.

Когда все закончится, запустите новый тест, чтобы убедиться, что он работает.

6. Заключение

Мы видели, как интегрировать Feign в наш шлюз для создания специализированной конечной точки. Мы можем использовать эту информацию для создания любого API, который нам необходим для поддержки. Что наиболее важно, мы видим, что мы не пойманы в ловушку универсальным API, который предоставляет только отдельные ресурсы.

Используя шаблон шлюза, мы можем индивидуально настроить нашу службу шлюза в соответствии с потребностями каждого клиента. Это создает разъединение, предоставляя нашим службам свободу развиваться по мере необходимости, оставаясь гибкими и сосредоточенными на одной области приложения.

Как всегда, фрагменты кода можно найтиover on GitHub.