Apache Camel mit Spring Boot

1. Übersicht

Im Kern ist Apache Camel eine Integrations-Engine, mit der - einfach ausgedrückt - die Interaktion zwischen einer Vielzahl von Technologien erleichtert werden kann.

Diese Brücken zwischen Diensten und Technologien werden als Routen bezeichnet. Routen werden in einer Engine (dem CamelContext ) implementiert und kommunizieren mit sogenannten "Exchange Messages".

2. Maven-Abhängigkeiten

Zu Beginn müssen wir Abhängigkeiten für Spring Boot, Camel, Rest API mit Swagger und JSON einschließen:

  org.apache.camel camel-servlet-starter ${camel.version}   org.apache.camel camel-jackson-starter ${camel.version}   org.apache.camel camel-swagger-java-starter ${camel.version}   org.apache.camel camel-spring-boot-starter ${camel.version}   org.springframework.boot spring-boot-starter-web ${spring-boot-starter.version}  

Die neuesten Versionen der Apache Camel-Abhängigkeiten finden Sie hier.

3. Die Hauptklasse

Lassen Sie uns zuerst eine Spring Boot- Anwendung erstellen :

@SpringBootApplication @ComponentScan(basePackages="com.baeldung.camel") public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } }

4. Kamelkonfigurationen für Spring Boot

Lassen Sie uns nun unsere Anwendung mit Spring konfigurieren, beginnend mit den Konfigurationsdateien (Eigenschaften).

Konfigurieren wir beispielsweise ein Protokoll für unsere Anwendung in einer application.properties- Datei in src / main / resources :

logging.config=classpath:logback.xml camel.springboot.name=MyCamel server.address=0.0.0.0 management.address=0.0.0.0 management.port=8081 endpoints.enabled = true endpoints.health.enabled = true

Dieses Beispiel zeigt eine application.properties- Datei, die auch den Pfad zu einer Logback-Konfiguration festlegt. Durch Festlegen der IP-Adresse auf "0.0.0.0" wird der Administrator- und Verwaltungszugriff auf den von Spring Boot bereitgestellten Webserver vollständig eingeschränkt . Außerdem aktivieren wir den erforderlichen Netzwerkzugriff auf unsere Anwendungsendpunkte sowie auf die Endpunkte der Integritätsprüfung.

Eine weitere Konfigurationsdatei ist die application.yml . Darin fügen wir einige Eigenschaften hinzu, mit denen wir Werte in unsere Anwendungsrouten einfügen können:

server: port: 8080 camel: springboot: name: ServicesRest management: port: 8081 endpoints: enabled: false health: enabled: true quickstart: generateOrderPeriod: 10s processOrderPeriod: 30s

5 . Einrichten des Kamelservlets

Eine Möglichkeit, Camel zu verwenden, besteht darin, es als Servlet zu registrieren, damit es die HTTP-Anforderungen abfangen und an unsere Anwendung umleiten kann.

Wie bereits erwähnt, können wir mit Camels Version 2.18 und niedriger unsere application.yml nutzen, indem wir einen Parameter für unsere endgültige URL erstellen. Später wird es in unseren Java-Code eingefügt:

baeldung: api: path: '/camel'

Zurück zu unserer Anwendungsklasse müssen wir das Camel-Servlet im Stammverzeichnis unseres Kontextpfads registrieren, das beim Starten der Anwendung aus dem Referenzpfad baeldung.api.path in der application.yml eingefügt wird :

@Value("${baeldung.api.path}") String contextPath; @Bean ServletRegistrationBean servletRegistrationBean() { ServletRegistrationBean servlet = new ServletRegistrationBean (new CamelHttpTransportServlet(), contextPath+"/*"); servlet.setName("CamelServlet"); return servlet; }

Ab Camels Version 2.19 wurde diese Konfiguration gelöscht, da das CamelServlet standardmäßig auf "/ camel" eingestellt ist .

6. Eine Route bauen

Beginnen wir mit der Erstellung einer Route, indem wir die RouteBuilder- Klasse von Camel aus erweitern und als @Component festlegen, damit die Komponentenscanroutine sie während der Webserverinitialisierung finden kann:

@Component class RestApi extends RouteBuilder { @Override public void configure() { CamelContext context = new DefaultCamelContext(); restConfiguration()... rest("/api/")... from("direct:remoteService")... } }

In dieser Klasse überschreiben wir die configure () -Methode aus der RouteBuilder- Klasse von Camel .

Camel benötigt immer eine CamelContext- Instanz - die Kernkomponente, in der eingehende und ausgehende Nachrichten gespeichert werden.

In diesem einfachen Beispiel reicht DefaultCamelContext aus, da nur Nachrichten und Routen darin gebunden werden , wie beim REST-Service, den wir erstellen werden.

6.1. Die restConfiguration () Strecke

Als Nächstes erstellen wir eine REST-Deklaration für die Endpunkte, die wir in der restConfiguration () -Methode erstellen möchten :

restConfiguration() .contextPath(contextPath) .port(serverPort) .enableCORS(true) .apiContextPath("/api-doc") .apiProperty("api.title", "Test REST API") .apiProperty("api.version", "v1") .apiContextRouteId("doc-api") .component("servlet") .bindingMode(RestBindingMode.json)

Hier registrieren wir den Kontextpfad mit unserem injizierten Attribut aus der YAML-Datei. Die gleiche Logik wurde auf den Port unserer Anwendung angewendet. CORS ist aktiviert und ermöglicht die standortübergreifende Nutzung dieses Webdienstes. Der Bindungsmodus erlaubt und konvertiert Argumente in unsere API.

Als Nächstes fügen wir der zuvor festgelegten URI, dem Titel und der Version die Swagger-Dokumentation hinzu. Während wir Methoden / Endpunkte für unseren REST-Webdienst erstellen, wird die Swagger-Dokumentation automatisch aktualisiert.

Dieser Swagger-Kontext ist selbst eine Kamelroute, und während des Startvorgangs werden im Serverprotokoll einige technische Informationen dazu angezeigt. Unsere Beispieldokumentation wird standardmäßig unter // localhost: 8080 / camel / api-doc bereitgestellt.

6.2. Der Rest () Route

Implementieren wir nun den Methodenaufruf rest () aus der oben aufgeführten Methode configure () :

rest("/api/") .id("api-route") .consumes("application/json") .post("/bean") .bindingMode(RestBindingMode.json_xml) .type(MyBean.class) .to("direct:remoteService");

Diese Methode ist für diejenigen, die mit APIs vertraut sind, ziemlich einfach. Die ID ist die Identifikation der Route im CamelContext . Die nächste Zeile definiert den MIME-Typ. Der Bindungsmodus wird hier definiert, um zu zeigen, dass wir einen Modus für die restConfiguration () festlegen können .

Die post () -Methode fügt der API eine Operation hinzu und generiert einen POST / Bean- Endpunkt, während MyBean (eine reguläre Java-Bean mit einer Integer-ID und einem String-Namen ) die erwarteten Parameter definiert.

Ebenso sind HTTP-Aktionen wie GET, PUT und DELETE in Form von get () , put () , delete () verfügbar .

Schließlich erstellt die to () -Methode eine Brücke zu einer anderen Route. Hier weist es Camel an, in seinem Kontext / seiner Engine nach einer anderen Route zu suchen, die wir erstellen werden. Diese wird durch den Wert / die ID „ direct:… “ benannt und erkannt , der mit der in der from () -Methode definierten Route übereinstimmt .

6.3. Die from () Route mit transform ()

Bei der Arbeit mit Camel empfängt eine Route Parameter und konvertiert, transformiert und verarbeitet diese Parameter. Danach sendet es diese Parameter an eine andere Route, die das Ergebnis an die gewünschte Ausgabe weiterleitet (eine Datei, eine Datenbank, einen SMTP-Server oder eine REST-API-Antwort).

In diesem Artikel erstellen wir nur eine andere Route innerhalb der Methode configure () , die wir überschreiben. Dies ist die Zielroute für unsere letzte Route nach () :

from("direct:remoteService") .routeId("direct-route") .tracing() .log(">>> ${body.id}") .log(">>> ${body.name}") .transform().simple("Hello ${in.body.name}") .setHeader(Exchange.HTTP_RESPONSE_CODE, constant(200));

Die from () -Methode folgt denselben Prinzipien und hat viele der gleichen Methoden wie die rest () -Methode, außer dass sie aus den Camel-Kontextnachrichten verwendet wird. Dies ist der Grund für den Parameter „ direct-route “, der eine Verknüpfung zu der oben genannten Methode rest (). To () herstellt .

Viele andere Konvertierungen sind verfügbar , einschließlich der Extraktion als Java-Grundelemente (oder Objekte) und des Sendens an eine Persistenzschicht. Beachten Sie, dass die Routen immer aus eingehenden Nachrichten lesen, sodass verkettete Routen ausgehende Nachrichten ignorieren.

Unser Beispiel ist fertig und wir können es versuchen:

  • Führen Sie den Eingabeaufforderungsbefehl aus: mvn spring-boot: run
  • Führen Sie eine POST-Anforderung an // localhost: 8080 / camel / api / bean mit den Header-Parametern aus: Inhaltstyp: application / json und eine Nutzlast {"id": 1, "name": "World"}
  • Wir sollten einen Rückkehrcode von 201 und die Antwort erhalten: Hallo, Welt

6.4. Die EINFACHE Skriptsprache

Im Beispiel wird die Protokollierung mit der Methode tracing () ausgegeben. Beachten Sie, dass wir die Platzhalter $ {} verwendet haben . Diese sind Teil einer Skriptsprache, die zu Camel gehört und SIMPLE heißt. Es wird auf Nachrichten angewendet, die über die Route ausgetauscht werden, wie z. B. den Text der eingehenden Nachricht.

In unserem Beispiel verwenden wir SIMPLE, um die Bean-Attribute, die sich im Camel-Nachrichtentext befinden, in das Protokoll auszugeben.

Wir können es auch verwenden, um einfache Transformationen durchzuführen, wie mit der transform () -Methode gezeigt wurde.

6.5. Die from () Route mit process ()

Lassen Sie uns etwas aussagekräftigeres tun, z. B. eine Serviceschicht aufrufen, um verarbeitete Daten zurückzugeben. SIMPLE ist nicht für die Verarbeitung schwerer Datenmengen gedacht. Ersetzen Sie daher transform () durch eine process () -Methode:

from("direct:remoteService") .routeId("direct-route") .tracing() .log(">>> ${body.id}") .log(">>> ${body.name}") .process(new Processor() { @Override public void process(Exchange exchange) throws Exception { MyBean bodyIn = (MyBean) exchange.getIn().getBody(); ExampleServices.example(bodyIn); exchange.getIn().setBody(bodyIn); } }) .setHeader(Exchange.HTTP_RESPONSE_CODE, constant(200));

Auf diese Weise können wir die Daten in eine Bean extrahieren, die zuvor in der type () -Methode definiert wurde, und sie in unserer ExampleServices- Ebene verarbeiten.

Since we set the bindingMode() to JSON previously, the response already is in a proper JSON format, generated based on our POJO. This implies that for an ExampleServices class:

public class ExampleServices { public static void example(MyBean bodyIn) { bodyIn.setName( "Hello, " + bodyIn.getName() ); bodyIn.setId(bodyIn.getId() * 10); } }

The same HTTP request now returns with a response code 201 and body: {“id”: 10,”name”: “Hello, World”}.

7. Conclusion

With a few lines of code, we managed to create a relatively complete application. All dependencies are built, managed and run automatically with a single command. Moreover, we can create APIs that tie together all sorts of technologies.

This approach is also very container friendly, resulting in a very lean server environment that can be easily replicated on demand. The extra configuration possibilities can easily be incorporated into a container template configuration file.

Dieses REST-Beispiel finden Sie auf GitHub.

Neben den APIs filter () , process () , transform () und marshall () stehen in Camel viele weitere Integrationsmuster und Datenmanipulationen zur Verfügung:

  • Kamel-Integrationsmuster
  • Kamel Benutzerhandbuch
  • Kamel EINFACHE Sprache