Integreringsmønstre med Apache Camel

1. Oversikt

Denne artikkelen vil dekke noen viktige integrasjonsmønstre for bedrifter (EIP) støttet av Apache Camel. Integreringsmønstre hjelper ved å tilby løsninger for standardiserte måter å integrere systemer på.

Hvis du først trenger å gå gjennom det grunnleggende om Apache Camel, kan du definitivt besøke denne artikkelen for å gjøre noe med det grunnleggende.

2. Om EIP

Virksomhetsintegrasjonsmønstre er designmønstre som tar sikte på å gi løsninger for integrasjonsutfordringer. Camel gir implementeringer for mange av disse mønstrene. For å se hele listen over støttede mønstre, besøk denne lenken.

I denne artikkelen vil vi dekke innholdsbasert ruter, Message Translator, Multicast, Splitter og Dead Letter Channel integrasjonsmønstre.

2. Innholdsbasert ruter

Content Based Router er en meldingsruter som ruter en melding til destinasjonen basert på en meldingstittel, en del av nyttelasten eller i utgangspunktet alt fra meldingsutveksling som vi anser som innhold.

Det starter med valg() DSL-setning etterfulgt av en eller flere når() DSL-uttalelser. Hver når() inneholder et predikatuttrykk som, hvis tilfredsstilt, vil resultere i utførelse av inneholdte behandlingstrinn.

La oss illustrere denne EIP ved å definere en rute som bruker filer fra en mappe og flytter dem til to forskjellige mapper, avhengig av filtypen. Ruten vår er referert til i vår XML-fil ved bruk av tilpasset XML-syntaks for Camel:

Rutedefinisjon er inneholdt i ContentBasedFileRouter klasse der filer rutes fra kildemappen til to forskjellige målmapper, avhengig av utvidelsen.

Alternativt kan vi bruke Spring Java config-tilnærming her i motsetning til å bruke Spring XML-fil. For å gjøre det, må vi legge til en ekstra avhengighet til prosjektet vårt:

 org.apache.camel kamel-vår-javaconfig 2.18.1 

Den siste versjonen av gjenstanden finner du her.

Etter det må vi utvide Kamelkonfigurasjon klasse og overstyre ruter () metode som vil referere ContentBasedFileRouter:

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

Utvidelsen blir evaluert ved hjelp av Simple Expression Language via enkel() DSL-setning som var ment å brukes til å evaluere uttrykk og predikater:

offentlig klasse ContentBasedFileRouter utvider RouteBuilder {privat statisk sluttstreng SOURCE_FOLDER = "src / test / source-folder"; privat statisk sluttstreng DESTINATION_FOLDER_TXT = "src / test / destinasjonsmappe-txt"; privat statisk slutt String DESTINATION_FOLDER_OTHER = "src / test / destinasjonsmappe-annen"; @Override public void configure () kaster unntak {fra ("file: //" + SOURCE_FOLDER + "? Delete = true"). Valg () .when (enkel ("$ {file: ext} == 'txt'" )) .to ("file: //" + DESTINATION_FOLDER_TXT) .otherwise () .to ("file: //" + DESTINATION_FOLDER_OTHER); }}

Her bruker vi i tillegg ellers() DSL-uttalelse for å dirigere alle meldinger som ikke tilfredsstiller predikatene gitt med når() uttalelser.

3. Meldingsoversetter

Siden hvert system bruker sitt eget dataformat, er det ofte nødvendig å oversette meldingen som kommer fra et annet system til dataformatet som støttes av destinasjonssystemet.

Kamelstøtter MessageTranslator ruter som lar oss transformere meldinger ved hjelp av enten tilpasset prosessor i rutelogikken, ved hjelp av en bestemt bønne for å utføre transformasjonen eller ved å bruke forvandle() DSL-uttalelse.

Eksempel på bruk av en tilpasset prosessor finner du i forrige artikkel der vi definerte en prosessor som forhåndsstiller et tidsstempel til hver innkommende fils filnavn.

La oss nå demonstrere hvordan du bruker Message Translator ved hjelp av forvandle() uttalelse:

public class MessageTranslatorFileRouter utvider RouteBuilder {private static final String SOURCE_FOLDER = "src / test / source-folder"; privat statisk slutt String DESTINATION_FOLDER = "src / test / destinasjonsmappe"; @ Override public void configure () kaster Unntak {fra ("file: //" + SOURCE_FOLDER + "? Delete = true") .transform (body (). Append (header (Exchange.FILE_NAME))) .to ("file : // "+ DESTINATION_FOLDER); }}

I dette eksemplet legger vi filnavnet til filinnholdet via forvandle() uttalelse for hver fil fra kildemappen og flytte transformerte filer til en destinasjonsmappe.

4. Multicast

Multicast lar oss rute den samme meldingen til et sett med forskjellige endepunkter og behandle dem på en annen måte.

Dette er mulig ved å bruke multicast () DSL-setning og deretter ved å liste sluttpunktene og behandlingstrinnene i dem.

Som standard gjøres ikke behandling på forskjellige sluttpunkter parallelt, men dette kan endres ved å bruke parallelProsessering () DSL-uttalelse.

Kamel vil bruke det siste svaret som utgående melding etter multicastene som standard. Det er imidlertid mulig å definere en annen aggregeringsstrategi som skal brukes til å samle svarene fra multicasts.

La oss se hvordan Multicast EIP ser ut på et eksempel. Vi vil multicast-filer fra kildemappen til to forskjellige ruter der vi transformerer innholdet og sender dem til forskjellige destinasjonsmapper. Her bruker vi direkte: komponent som lar oss koble to ruter sammen:

offentlig klasse MulticastFileRouter utvider RouteBuilder {privat statisk sluttstreng SOURCE_FOLDER = "src / test / source-folder"; privat statisk sluttstreng DESTINATION_FOLDER_WORLD = "src / test / destinasjonsmappe-verden"; privat statisk sluttstreng DESTINATION_FOLDER_HELLO = "src / test / destinasjonsmappe-hei"; @Override public void configure () kaster unntak {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 tillater oss å dele innkommende melding i et antall stykker og behandle hver av dem individuelt. Dette er mulig ved å bruke dele() DSL-uttalelse.

I motsetning til Multicast, vil Splitter endre den innkommende meldingen, mens Multicast vil la den være som den er.

For å demonstrere dette på et eksempel, definerer vi en rute der hver linje fra en fil blir delt og transformert til en individuell fil som deretter flyttes til en annen målmappe. Hver nye fil blir opprettet med filnavn som tilsvarer filinnholdet:

offentlig klasse SplitterFileRouter utvider RouteBuilder {privat statisk sluttstreng SOURCE_FOLDER = "src / test / source-folder"; privat statisk slutt String DESTINATION_FOLDER = "src / test / destinasjonsmappe"; @Override public void configure () kaster unntak {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 vanlig, og det må forventes at det noen ganger kan oppstå problemer, for eksempel datablokkeringer, som kan føre til at en melding ikke blir levert som forventet. I visse tilfeller vil det imidlertid hjelpe å prøve igjen med en viss forsinkelse, og en melding blir behandlet.

Dead Letter Channel lar oss kontrollere hva som skjer med en melding når den ikke leveres. Ved hjelp av Dead Letter Channel kan vi spesifisere om vi skal formidle det kastede unntaket til den som ringer og hvor den mislykkede sentralen skal dirigeres.

Når en melding ikke leveres, vil Dead Letter Channel (hvis brukt) flytte meldingen til dødpunktet.

La oss demonstrere dette på et eksempel ved å kaste et unntak på ruten:

offentlig klasse DeadLetterChannelFileRouter utvider RouteBuilder {privat statisk endelig streng SOURCE_FOLDER = "src / test / source-folder"; @Override public void configure () kaster Unntak {errorHandler (deadLetterChannel ("log: dead? Level = ERROR") .maximumRedeliveries (3) .redeliveryDelay (1000) .retryAttemptedLogLevel (LoggingLevel.ERROR)); fra ("file: //" + SOURCE_FOLDER + "? delete = true"). prosess (utveksling -> {kast ny IllegalArgumentException ("Unntatt kastet!");}); }}

Her definerte vi en errorHandler som logger mislykkede leveranser og definerer strategien for omlevering. Ved å sette prøv på nyttAttemptedLogLevel (), blir hvert forsøk på omlevering logget med angitt loggnivå.

For at dette skal være fullt funksjonelt, må vi i tillegg konfigurere en logger.

Etter å ha kjørt denne testen, er følgende logguttalelser synlige i en konsoll:

FEIL DeadLetterChannel: 156 - Mislykket levering for (MessageId: ID-ZAG0025-50922-1481340325657-0-1 på ExchangeId: ID-ZAG0025-50922-1481340325657-0-2). Ved leveringsforsøk: 0 fanget: java.lang.IllegalArgumentException: Unntak kastet! FEIL DeadLetterChannel: 156 - Mislykket levering for (MessageId: ID-ZAG0025-50922-1481340325657-0-1 på ExchangeId: ID-ZAG0025-50922-1481340325657-0-2). Ved forsøk på levering: 1 fanget: java.lang.IllegalArgumentException: Unntak kastet! FEIL DeadLetterChannel: 156 - Mislykket levering for (MessageId: ID-ZAG0025-50922-1481340325657-0-1 på ExchangeId: ID-ZAG0025-50922-1481340325657-0-2). Ved leveringsforsøk: 2 fanget: java.lang.IllegalArgumentException: Unntak kastet! FEIL DeadLetterChannel: 156 - Mislykket levering for (MessageId: ID-ZAG0025-50922-1481340325657-0-1 på ExchangeId: ID-ZAG0025-50922-1481340325657-0-2). Ved leveringsforsøk: 3 fanget: java.lang.IllegalArgumentException: Unntak kastet! FEIL død: 156 - Exchange [ExchangePattern: InOnly, BodyType: org.apache.camel.component.file.GenericFile, Body: [Body is file based: GenericFile [File.txt]]]

Som du kan legge merke til, logges hvert forsendelsesforsøk og viser Exchange som levering ikke var vellykket for.

7. Konklusjon

I denne artikkelen presenterte vi en introduksjon til integrasjonsmønstre ved hjelp av Apache Camel og demonstrerte dem på noen få eksempler.

Vi demonstrerte hvordan du bruker disse integrasjonsmønstrene og hvorfor de er gunstige for å løse integrasjonsutfordringer.

Kode fra denne artikkelen finner du på GitHub.


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