Integrationsmønstre med Apache Camel

1. Oversigt

Denne artikel vil dække nogle vigtige virksomhedsintegrationsmønstre (EIP'er) understøttet af Apache Camel. Integrationsmønstre hjælper med at levere løsninger til standardiserede måder at integrere systemer på.

Hvis du først har brug for at gennemgå det grundlæggende i Apache Camel, skal du helt sikkert besøge denne artikel for at gøre noget ved det grundlæggende.

2. Om EIP'er

Virksomhedsintegrationsmønstre er designmønstre, der sigter mod at levere løsninger til integrationsudfordringer. Camel giver implementeringer for mange af disse mønstre. For at se den fulde liste over understøttede mønstre, besøg dette link.

I denne artikel dækker vi Content Based Router, Message Translator, Multicast, Splitter og Dead Letter Channel integrationsmønstre.

2. Indholdsbaseret router

Content Based Router er en meddelelsesrouter, der dirigerer en besked til sin destination baseret på en beskedoverskrift, en del af nyttelasten eller stort set alt fra meddelelsesudveksling, som vi betragter som indhold.

Det starter med valg() DSL-sætning efterfulgt af en eller flere hvornår() DSL-udsagn. Hver hvornår() indeholder et predikatudtryk, som, hvis det er tilfredsstillende, vil resultere i udførelsen af ​​indeholdte behandlingstrin.

Lad os illustrere denne EIP ved at definere en rute, der bruger filer fra en mappe og flytter dem til to forskellige mapper afhængigt af filtypen. Vores rute henvises til foråret XML-fil ved hjælp af brugerdefineret XML-syntaks til Camel:

Rutedefinition er indeholdt i ContentBasedFileRouter klasse, hvor filer dirigeres fra kildemappen til to forskellige destinationsmapper afhængigt af deres udvidelse.

Alternativt kunne vi bruge Spring Java config-tilgang her i modsætning til at bruge Spring XML-fil. For at gøre det skal vi tilføje en yderligere afhængighed af vores projekt:

 org.apache.camel camel-spring-javaconfig 2.18.1 

Den seneste version af artefakten kan findes her.

Derefter skal vi udvide Kamelkonfiguration klasse og tilsidesætte ruter () metode, som vil referere ContentBasedFileRouter:

@Configuration offentlig klasse ContentBasedFileRouterConfig udvider CamelConfiguration {@Bean ContentBasedFileRouter getContentBasedFileRouter () {returner nyt ContentBasedFileRouter (); } @Override public List ruter () {return Arrays.asList (getContentBasedFileRouter ()); }}

Udvidelsen evalueres ved hjælp af Simple Expression Language via enkel() DSL-erklæring, der var beregnet til at blive brugt til evaluering af udtryk og forudsigelser:

offentlig klasse ContentBasedFileRouter udvider RouteBuilder {privat statisk endelig streng SOURCE_FOLDER = "src / test / source-folder"; privat statisk endelig streng DESTINATION_FOLDER_TXT = "src / test / destination-folder-txt"; privat statisk endelig streng DESTINATION_FOLDER_OTHER = "src / test / destinationsmappe-anden"; @ Override public void configure () kaster undtagelse {fra ("file: //" + SOURCE_FOLDER + "? Delete = true"). Valg (). Når (simple ("$ {file: ext} == 'txt'" )) .to ("fil: //" + DESTINATION_FOLDER_TXT). ellers () .to ("fil: //" + DESTINATION_FOLDER_OTHER); }}

Her bruger vi desuden Ellers() DSL-erklæring for at dirigere alle meddelelser, der ikke opfylder prædikater givet med hvornår() udsagn.

3. Beskedoversætter

Da hvert system bruger sit eget dataformat, er det ofte nødvendigt at oversætte meddelelsen fra et andet system til det dataformat, der understøttes af destinationssystemet.

Kamelstøtter MessageTranslator router, der giver os mulighed for at transformere meddelelser ved hjælp af enten en tilpasset processor i routinglogikken ved hjælp af en bestemt bønne til at udføre transformationen eller ved hjælp af transformer () DSL-erklæring.

Eksempel på brug af en brugerdefineret processor kan findes i den forrige artikel, hvor vi definerede en processor, der forudindstiller et tidsstempel til hver indkommende fils filnavn.

Lad os nu demonstrere, hvordan man bruger Message Translator ved hjælp af transformer () udmelding:

offentlig klasse MessageTranslatorFileRouter udvider RouteBuilder {privat statisk endelig streng SOURCE_FOLDER = "src / test / source-folder"; privat statisk endelig streng DESTINATION_FOLDER = "src / test / destinationsmappe"; @ Overstyr offentlig ugyldig konfiguration () kaster undtagelse {fra ("fil: //" + SOURCE_FOLDER + "? Delete = true") .transform (body (). Append (header (Exchange.FILE_NAME))) .to ("file : // "+ DESTINATION_FOLDER); }}

I dette eksempel tilføjer vi filnavnet til filindholdet via transformer () erklæring for hver fil fra kildemappen og flytning af transformerede filer til en destinationsmappe.

4. Multicast

Multicast tillader os at rute den samme besked til et sæt forskellige slutpunkter og behandle dem på en anden måde.

Dette er muligt ved hjælp af multicast () DSL-erklæring og derefter ved at angive slutpunkter og behandlingstrin inden for dem.

Behandling på forskellige slutpunkter udføres som standard ikke parallelt, men dette kan ændres ved hjælp af parallelProcessing () DSL-erklæring.

Camel bruger som standard det sidste svar som den udgående besked efter multicasts. Det er dog muligt at definere en anden sammenlægningsstrategi, der skal bruges til at samle svarene fra multicasts.

Lad os se, hvordan Multicast EIP ser ud på et eksempel. Vi multicast filer fra kildemappen til to forskellige ruter, hvor vi transformerer deres indhold og sender dem til forskellige destinationsmapper. Her bruger vi direkte: komponent, der giver os mulighed for at forbinde to ruter sammen:

offentlig klasse MulticastFileRouter udvider RouteBuilder {privat statisk endelig streng SOURCE_FOLDER = "src / test / source-folder"; privat statisk endelig streng DESTINATION_FOLDER_WORLD = "src / test / destination-folder-world"; privat statisk endelig streng DESTINATION_FOLDER_HELLO = "src / test / destinationsmappe-hej"; @Override public void configure () kaster undtagelse {fra ("file: //" + SOURCE_FOLDER + "? Delete = true") .multicast () .to ("direct: append", "direct: prepend"). End ( ); fra ("direct: append") .transform (body (). append ("World")) .to ("file: //" + DESTINATION_FOLDER_WORLD); fra ("direct: prepend") .transform (body (). prepend ("Hello")) .to ("file: //" + DESTINATION_FOLDER_HELLO); }}

5. Splitter

Splitteren tillader os at opdele den indgående besked i et antal stykker og behandle hver af dem individuelt. Dette er muligt ved hjælp af dele() DSL-erklæring.

I modsætning til Multicast ændrer Splitter den indgående besked, mens Multicast vil lade den være som den er.

For at demonstrere dette på et eksempel definerer vi en rute, hvor hver linje fra en fil opdeles og omdannes til en individuel fil, som derefter flyttes til en anden destinationsmappe. Hver nye fil oprettes med filnavn svarende til filindhold:

offentlig klasse SplitterFileRouter udvider RouteBuilder {privat statisk endelig streng SOURCE_FOLDER = "src / test / source-folder"; privat statisk endelig streng DESTINATION_FOLDER = "src / test / destinationsmappe"; @Override public void configure () kaster undtagelse {fra ("file: //" + SOURCE_FOLDER + "? Delete = true") .split (body (). ConvertToString (). Tokenize ("\ n")) .setHeader ( Exchange.FILE_NAME, body ()) .to ("file: //" + DESTINATION_FOLDER); }}

6. Dead Letter Channel

Det er almindeligt, og det skal forventes, at der undertiden kan opstå problemer, f.eks. Datablokeringer, som kan medføre, at en meddelelse ikke leveres som forventet. I visse tilfælde vil det dog hjælpe med at prøve igen med en vis forsinkelse, og en besked bliver behandlet.

Dead Letter Channel giver os mulighed for at kontrollere, hvad der sker med en besked, når den ikke leveres. Ved hjælp af Dead Letter Channel kan vi specificere, om den kastede undtagelse skal spredes til den, der ringer op, og hvor den mislykkede Exchange skal dirigeres.

Når en meddelelse ikke leveres, vil Dead Letter Channel (hvis brugt) flytte meddelelsen til deadpoint-slutpunktet.

Lad os demonstrere dette på et eksempel ved at kaste en undtagelse på ruten:

public class DeadLetterChannelFileRouter udvider RouteBuilder {privat statisk endelig streng SOURCE_FOLDER = "src / test / source-folder"; @Override public void configure () kaster Exception {errorHandler (deadLetterChannel ("log: dead? Level = ERROR") .maximumRedeliveries (3) .redeliveryDelay (1000) .retryAttemptedLogLevel (LoggingLevel.ERROR)); fra ("file: //" + SOURCE_FOLDER + "? delete = true") .proces (udveksling -> {smid nyt IllegalArgumentException ("Undtagelse kastet!");}); }}

Her definerede vi en errorHandler som logger mislykkede leverancer og definerer genleveringsstrategi. Ved at indstille prøv igenAttemptedLogLevel (), vil hvert genleveringsforsøg blive logget med det angivne logniveau.

For at dette skal være fuldt funktionelt, skal vi desuden konfigurere en logger.

Efter at have kørt denne test er følgende logerklæringer synlige i en konsol:

FEJL DeadLetterChannel: 156 - Mislykket levering til (MessageId: ID-ZAG0025-50922-1481340325657-0-1 på ExchangeId: ID-ZAG0025-50922-1481340325657-0-2). Ved leveringsforsøg: 0 fanget: java.lang.IllegalArgumentException: Undtagelse kastet! FEJL DeadLetterChannel: 156 - Mislykket levering til (MessageId: ID-ZAG0025-50922-1481340325657-0-1 på ExchangeId: ID-ZAG0025-50922-1481340325657-0-2). Ved leveringsforsøg: 1 fanget: java.lang.IllegalArgumentException: Undtagelse kastet! FEJL DeadLetterChannel: 156 - Mislykket levering til (MessageId: ID-ZAG0025-50922-1481340325657-0-1 på ExchangeId: ID-ZAG0025-50922-1481340325657-0-2). Ved leveringsforsøg: 2 fanget: java.lang.IllegalArgumentException: Undtagelse kastet! FEJL DeadLetterChannel: 156 - Mislykket levering til (MessageId: ID-ZAG0025-50922-1481340325657-0-1 på ExchangeId: ID-ZAG0025-50922-1481340325657-0-2). Ved leveringsforsøg: 3 fanget: java.lang.IllegalArgumentException: Undtagelse kastet! FEJL død: 156 - Exchange [ExchangePattern: InOnly, BodyType: org.apache.camel.component.file.GenericFile, Body: [Body er filbaseret: GenericFile [File.txt]]]

Som du kan bemærke, logges hvert forsøg på genlevering med Exchange, hvor levering ikke lykkedes.

7. Konklusion

I denne artikel præsenterede vi en introduktion til integrationsmønstre ved hjælp af Apache Camel og demonstrerede dem på få eksempler.

Vi demonstrerede, hvordan man bruger disse integrationsmønstre, og hvorfor de er gavnlige til at løse integrationsudfordringer.

Kode fra denne artikel kan findes på GitHub.


$config[zx-auto] not found$config[zx-overlay] not found