Spring Cloud-Serie - Das Gateway-Muster

Spring Cloud Series - Das Gateway-Muster

1. Überblick

So far haben wir in unserer Cloud-Anwendung das Gateway-Muster verwendet, um zwei Hauptfunktionen zu unterstützen.

Erstens haben wir unsere Kunden von jedem Service isoliert, sodass keine herkunftsübergreifende Unterstützung erforderlich ist. Als Nächstes haben wir die Suche nach Instanzen von Diensten mithilfe von Eureka implementiert.

In diesem Artikel werden wir uns ansehen, wie das Gateway-Muster fürretrieve data from multiple services with a single request verwendet wird. Zu diesem Zweck werden wir Feign in unser Gateway einführen, um die API-Aufrufe für unsere Dienste zu schreiben.

Informationen zur Verwendung des Feign-Clients finden Sie unterthis article.

Spring Cloud stellt jetzt auch dasSpring Cloud Gateway-Projekt bereit, das dieses Muster implementiert.

2. Konfiguration

Öffnen wir diepom.xml unseresgateway-Servers und fügen die Abhängigkeit für Feign hinzu:


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

Als Referenz - wir können die neuesten Versionen aufMaven Central (spring-cloud-starter-feign) finden.

Nachdem wir nun die Unterstützung für die Erstellung eines Feign-Clients haben, aktivieren wir ihn inGatewayApplication.java:

@EnableFeignClients
public class GatewayApplication { ... }

Richten wir nun Feign-Kunden für die Buch- und Bewertungsdienste ein.

3. Kunden vortäuschen

3.1. Client buchen

Erstellen wir eine neue Schnittstelle mit dem NamenBooksClient.java:

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

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

Mit dieser Schnittstelle weisen wir Spring an, einen Feign-Client zu erstellen, der auf den Endpunkt "/books/\{bookId}" zugreift. Beim Aufruf führt die MethodegetBookById einen HTTP-Aufruf an den Endpunkt durch und verwendet den ParameterbookId.

Damit dies funktioniert, müssen wir einBook.java DTO hinzufügen:

@JsonIgnoreProperties(ignoreUnknown = true)
public class Book {

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

    // getters and setters
}

Fahren wir mitRatingsClientfort.

3.2. Bewertungen Client

Erstellen wir eine Schnittstelle mit dem NamenRatingsClient:

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

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

}

Wie beiBookClient ruft die hier dargestellte Methode unseren Bewertungsservice erneut auf und gibt die Liste der Bewertungen für ein Buch zurück.

Dieser Endpunkt ist jedoch gesichert. To be able to access this endpoint properly we need to pass the user’s session to the request.

Wir tun dies mit der Annotation@RequestHeader. Dadurch wird Feign angewiesen, den Wert dieser Variablen in den Header der Anforderung zu schreiben. In unserem Fall schreiben wir in den Header vonCookie, da Spring Session nach unserer Sitzung in einem Cookie sucht.

In unserem Fall schreiben wir in den Header vonCookie, da Spring Session nach unserer Sitzung in einem Cookie sucht.

Zum Schluss fügen wir das DTO vonRating.javahinzu:

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

Jetzt sind beide Clients fertig. Setzen wir sie ein!

4. Kombinierte Anfrage

Ein häufiger Anwendungsfall für das Gateway-Muster sind Endpunkte, die häufig aufgerufene Dienste kapseln. Dies kann die Leistung steigern, indem die Anzahl der Clientanforderungen verringert wird.

Dazu erstellen wir einen Controller und nennen ihnCombinedController.java:

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

Lassen Sie uns als Nächstes unsere neu erstellten vorgetäuschten Kunden einbinden:

private BooksClient booksClient;
private RatingsClient ratingsClient;

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

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

Lassen Sie uns abschließend eine GET-Anforderung erstellen, die diese beiden Endpunkte kombiniert und ein einzelnes Buch mit geladenen Bewertungen zurückgibt:

@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;
}

Beachten Sie, dass wir den Sitzungswert mithilfe der Annotation@CookieValuefestlegen, die ihn aus der Anforderung extrahiert.

Da ist es! Wir haben einen kombinierten Endpunkt in unserem Gateway, der Netzwerkanrufe zwischen dem Client und dem System reduziert!

5. Testen

Stellen wir sicher, dass unser neuer Endpunkt funktioniert.

Navigieren Sie zuLiveTest.java und fügen Sie einen Test für unseren kombinierten Endpunkt hinzu:

@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);
}

Starten Sie Redis und führen Sie dann jeden Dienst in unserer Anwendung aus:config, discovery, zipkin,gateway,book und den Dienstrating.

Sobald alles fertig ist, führen Sie den neuen Test durch, um zu bestätigen, dass er funktioniert.

6. Fazit

Wir haben gesehen, wie Feign in unser Gateway integriert werden kann, um einen speziellen Endpunkt zu erstellen. Wir können diese Informationen nutzen, um alle APIs zu erstellen, die wir unterstützen müssen. Am wichtigsten ist, dass wir nicht von einer universellen API erfasst werden, die nur einzelne Ressourcen verfügbar macht.

Mithilfe des Gateway-Musters können wir unseren Gateway-Service individuell auf die Bedürfnisse jedes Kunden einstellen. Dies schafft eine Entkopplung, die unseren Diensten die Freiheit gibt, sich nach Bedarf zu entwickeln, schlank zu bleiben und sich auf einen Bereich der Anwendung zu konzentrieren.

Wie immer können Codefragmenteover on GitHub. gefunden werden