Рубрики
Без рубрики

Серия Spring Cloud – Шаблон Шлюза

Узнайте о преимуществах использования службы шлюза в архитектуре микросервисов.

Автор оригинала: Tim Schimandle.

1. Обзор

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

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

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

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

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

2. Настройка

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


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

Для справки – мы можем найти последние версии на Maven Central ( spring-cloud-starter-feign ).

Теперь, когда у нас есть поддержка для создания Feignclient, давайте включим его в GatewayApplication.java :

@EnableFeignClients
public class GatewayApplication { ... }

Теперь давайте создадим фиктивных клиентов для книжных и рейтинговых служб.

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 создать притворный клиент, который получит доступ к конечной точке ” /books/{BookID }”. При вызове метод getBookById выполнит HTTP-вызов конечной точки и использует параметр BookID .

Чтобы это сработало, нам нужно добавить Book.java КОМУ:

@JsonIgnoreProperties(ignoreUnknown = true)
public class Book {
 
    private Long id;
    private String author;
    private String title;
    private List ratings;
    
    // getters and setters
}

Давайте перейдем к клиенту Ratings|/.

3.2. Рейтинги Клиента

Давайте создадим интерфейс под названием Клиент рейтингов :

@FeignClient("rating-service")
public interface RatingsClient {
 
    @RequestMapping(value = "/ratings", method = RequestMethod.GET)
    List getRatingsByBookId(
      @RequestParam("bookId") Long bookId, 
      @RequestHeader("Cookie") String session);
    
}

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

Однако эта конечная точка защищена. Чтобы правильно получить доступ к этой конечной точке, нам нужно передать сеанс пользователя в запрос.

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

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

Наконец, давайте добавим Rating.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, | шлюз , книга и рейтинг служба.

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

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

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

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

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