info@yenlo.com
deu
Menu
API Management 7 min

Integrieren von APIs mit Apache Camel: Implementierung des Scatter-and-Gather-Musters mit Java-DSL

Entdecken Sie, wie Sie die API-Integration mithilfe des Scatter-and-Gather-Musters optimieren können. In diesem Blog zeigen wir Ihnen, wie Sie es mit Apache Camel implementieren, um Antworten mehrerer APIs zu einer einzigen Ausgabe zu konsolidieren. Ein praktischer Leitfaden für technische Experten und Geschäftsleiter.

Ajanthan Eliyathamby Integration Expert
Ajanthan Eliyathamby
Integrationsexperte
High Level Integration Flow Diagram

Eines der wichtigsten Enterprise Integration Patterns in der API-Integration ist das Scatter-and-Gather-Muster. Es beinhaltet das Sammeln mehrerer Antworten von Backends und deren Konsolidierung in eine einzige Ausgabe, die oft über das Frontend zugänglich ist.

In diesem Artikel werden wir ein Szenario untersuchen, bei dem wir Angebote für den Stundensatz für das Streichen von Häusern von APIs verschiedener Anbieter sammeln, konsolidieren und in einer einheitlichen Ansicht im Frontend präsentieren. Wir werden dies mit Apache Camel auf Basis von Spring Boot tun.

Für ein besseres Verständnis des Scatter-and-Gather-Musters kannst du das Dokument hier nachlesen.

Initiale Projekteinrichtung

Initiale Projekteinrichtung a. Um das initiale Projekt zu generieren, können wir den Spring Boot Initializer verwenden. Lass uns die untenstehende Auswahl für die Projektgenerierung verwenden. Unter den Abhängigkeiten kannst du sehen, dass ich Apache Camel ausgewählt habe.

Spring Project Initializer

Sobald wir die Apache Camel-Abhängigkeit ausgewählt haben, wird die untenstehende Abhängigkeit in der pom.xml enthalten sein.

<dependency>
<groupId>org.apache.camel.springboot</groupId>
   <artifactId>camel-spring-boot-starter</artifactId>
    <version>4.4.1</version>
</dependency>

Für den Build in diesem Artikel verwenden wir Apache Maven 3.8.6 und Java Version: 18.0.2 auf einem Apple M1 Pro, mit Ziel auf Java Version 11.

Für weitere Einblicke in die Projektstruktur kannst du den vorherigen Artikel zu Apache Camel Teil-1 und Teil-2 nachlesen.

Diagramm des Integrationsflusses auf hoher Ebene

High Level Integration Flow Diagram

Wie im obigen Diagramm dargestellt, haben wir eine Frontend-API namens GET /quotes/painting. Diese API wird gleichzeitig die drei Anbieter-APIs aufrufen, die Antworten von jedem abrufen, sie zusammenführen und dann eine konsolidierte Antwort an den Client senden.

Implementierung

Verständnis der pom.xml

Nr.AbhängigkeitBeschreibung
1camel-spring-boot-starterHilft bei der Integration von Camel-Routen innerhalb der Spring Boot-Anwendungen
2camel-rest-starterUnterstützt Camel-Routen zur Konfiguration als RESTful Services
3lombokErleichtert die Entwicklung, z.B. durch slf4j-Logging. Bietet Getter und Setter durch einfache Verwendung von Anmerkungen
4camel-netty-httpCamel unterstützt REST-Komponenten wie Jetty, Servlet, Undertow und hier verwende ich Netty
5Properties -> java.versionDefiniert 11, sodass die Kompatibilität mit JDK 11 bestätigt wird und die Klassen-Dateien für die spezifische Hauptversion generiert werden
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
       <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-starter-parent</artifactId>
       <version>3.2.3</version>
       <relativePath/>
    </parent>
    <groupId>com.quotes</groupId>
    <artifactId>PaintingServiceQuotes</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>PaintingServiceQuotes</name>
    <description>Project for Painting Service Costs</description>
    <properties>
       <java.version>11</java.version>
    </properties>
    <dependencyManagement>
       <dependencies>
          <dependency>
             <groupId>org.apache.camel.springboot</groupId>
             <artifactId>camel-spring-boot-bom</artifactId>
             <version>4.4.1</version>
             <type>pom</type>
             <scope>import</scope>
          </dependency>
          <dependency>
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-dependencies</artifactId>
             <version>3.2.3</version>
             <type>pom</type>
             <scope>import</scope>
          </dependency>
       </dependencies>
    </dependencyManagement>
    <dependencies>
       <dependency>
          <groupId>org.apache.camel.springboot</groupId>
          <artifactId>camel-spring-boot-starter</artifactId>
       </dependency>
       <dependency>
          <groupId>org.apache.camel.springboot</groupId>
          <artifactId>camel-rest-starter</artifactId>
       </dependency>
       <dependency>
          <groupId>org.projectlombok</groupId>
          <artifactId>lombok</artifactId>
       </dependency>
       <dependency>
          <groupId>org.apache.camel</groupId>
          <artifactId>camel-netty-http</artifactId>
          <version>4.4.1</version>
       </dependency>
    </dependencies>
    <build>
       <plugins>
          <plugin>
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-maven-plugin</artifactId>
          </plugin>
       </plugins>
    </build>
</project>

Implementierung der Spring Boot Hauptanwendungsklasse

package com.quotes.painting;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class PaintingServiceQuotesApplication {

    public static void main(String[] args) {
       SpringApplication.run(PaintingServiceQuotesApplication.class, args);
    }

}

Backend API Route Builder

Wir implementieren den Backend API Route Builder, um die anbieter-spezifischen APIs zu haben. Wie du sehen kannst, haben wir 3 Anbieter-APIs definiert, und sie werden application/json-Antworten zurücksenden.

package com.quotes.painting.builders.api.back;

import lombok.extern.slf4j.Slf4j;
import org.apache.camel.builder.RouteBuilder;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

@Slf4j
@Component
public class BackApiBuilder extends RouteBuilder {

    @Value("${custom.netty.http.port}")
    private int nettyHttpPort;

    @Override
    public void configure() throws Exception {

        log.info("BackApiBuilder Route Builder Initiated.");

        restConfiguration()
                .component("netty-http")
                .port(nettyHttpPort);

        // 1. API of the Vendor One
        rest("/quotes")
            .get("/vendor-one")
            .produces("application/json")
            .to("direct:vendorOne");

        from("direct:vendorOne")
            .log("Received GET request for vendorOne.")
                .setBody(constant("{\"vendor\": \"vendorOne\", \"serviceType\": \"Painting\", \"Hourly\": \"25$\"}"));

        // 2. API of the Vendor Two
        rest("/quotes")
            .get("/vendor-two")
            .produces("application/json")
            .to("direct:vendorTwo");

        from("direct:vendorTwo")
            .log("Received GET request for vendorTwo.")
                .setBody(constant("{\"vendor\": \"vendorTwo\", \"serviceType\": \"Painting\", \"Hourly\": \"35$\"}"));

        // 3. API of the Vendor Three
        rest("/quotes")
            .get("/vendor-three")
            .produces("application/json")
            .to("direct:vendorThree");

        from("direct:vendorThree")
            .log("Received GET request for vendorThree.")
            .setBody(constant("{\"vendor\": \"vendorThree\", \"serviceType\": \"Painting\", \"Hourly\": \"15$\"}"));

    }
}

Front API Route Builder

Die folgende Klasse enthält die Hauptimplementierung der Scatter-and-Gather-Musterlogik. In diesem Beispiel habe ich die Multicast-Camel-Komponente verwendet. Standardmäßig arbeitet Multicast auf einem einzelnen Thread, aber parallele Verarbeitung kann ebenfalls aktiviert werden. Außerdem wurde die „AggregationStrategy“ verwendet, um die Antwort-Payloads zu kombinieren und als konsolidierte JSON-Antwort zurückzusenden.

package com.quotes.painting.builders.api.front;

import com.quotes.painting.aggregaters.JsonAggregator;
import lombok.extern.slf4j.Slf4j;
import org.apache.camel.builder.RouteBuilder;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

@Slf4j
@Component
public class FrontApiBuilder extends RouteBuilder {

    @Value("${custom.netty.http.port}")
    private int nettyHttpPort;

    @Override
    public void configure() throws Exception {

        log.info("FrontApiBuilder Route Builder Initiated.");

        restConfiguration()
                .component("netty-http")
                .port(nettyHttpPort);

        rest("/quotes")
            .get("/painting")
            .produces("application/json")
            .to("direct:paintingQuotes");

        from("direct:paintingQuotes")
            .log("PaintingQuotes Request Initiated.")
            .multicast()
                .parallelProcessing()
                .aggregationStrategy(new JsonAggregator())
                .to("netty-http:http://localhost:8090/quotes/vendor-one")
                .to("netty-http:http://localhost:8090/quotes/vendor-two")
                .to("netty-http:http://localhost:8090/quotes/vendor-three")
            .end()
            .log("Process Completed: ${body}");
    }
}

Implementierung der Aggregation Strategy

Diese Klasse hilft, die Antworten der Backend-APIs zu aggregieren.

package com.quotes.painting.aggregaters;

import org.apache.camel.AggregationStrategy;
import org.apache.camel.Exchange;
import org.springframework.stereotype.Component;

@Component
public class JsonAggregator implements AggregationStrategy {

    @Override
    public Exchange aggregate(Exchange oldExchange, Exchange newExchange) {
        if (oldExchange == null) {
            return newExchange;
        }
        String oldBody = oldExchange.getIn().getBody(String.class);
        String newBody = newExchange.getIn().getBody(String.class);
        String body = null;
        if (!oldBody.startsWith("[")) {
            body = "[ " + oldBody + ", " + newBody + " ]";
        } else{
            body = oldBody.replace("]", "") + ", " + newBody + " ]";
        }
        oldExchange.getIn().setBody(body);
        return oldExchange;
    }
}

Resources/application.yml-Konfiguration

camel:
  springboot:
    name: PaintingServiceQuotes

logging:
  level:
    org:
      apache:
        camel: INFO

custom:
    netty:
        http:
            port: 8090

Build und Test

Führe das typische Maven-Build-Kommando im Hauptverzeichnis des Projekts aus:

mvn clean install

Führe dann das folgende Kommando aus, um die Spring Boot-Anwendung zu starten:

java -jar target/PaintingServiceQuotes-0.0.1-SNAPSHOT.jar

Verwende einen Client oder Curl-Befehl, um die Frontend-API aufzurufen, die mit der aggregierten Antwort antworten wird.

API Execution View of Client

Damit endet die Diskussion darüber, wie wir das Scatter-and-Gather Enterprise Integration Pattern mit Apache Camel implementieren können. Hoffentlich hat diese Schritt-für-Schritt-Anleitung eine detaillierte Erklärung gegeben, wie wir dies mit Camel erreichen können.

Ich hoffe, dich in einem weiteren Blog wiederzusehen. Bleib dran für weitere Einblicke und Updates.

deu
Schließen
Was ist auf unserer Speisekarte