Uzorci integracije s Apache Camel

1. Pregled

Ovaj će članak pokriti neke bitne obrasce integracije poduzeća (EIP-ove) koje podržava Apache Camel. Obrasci integracije pomažu pružanjem rješenja za standardizirane načine integracije sustava.

Ako trebate prvo proučiti osnove Apache Camel, svakako posjetite ovaj članak da biste razjasnili osnove.

2. O EIP-ovima

Obrasci integracije poduzeća uzorci su dizajna kojima je cilj pružiti rješenja za integracijske izazove. Camel pruža implementacije mnogih od ovih obrazaca. Da biste vidjeli cijeli popis podržanih uzoraka, posjetite ovu vezu.

U ovom ćemo članku opisati obrasce integracije usmjerenih na sadržaj, prevoditelja poruka, multicast, splitter i Dead Letter Channel.

2. Usmjerivač na temelju sadržaja

Usmjerivač na temelju sadržaja usmjerivač je poruke koji usmjerava poruku do odredišta na temelju zaglavlja poruke, dijela korisnog tereta ili u osnovi bilo čega iz razmjene poruka što smatramo sadržajem.

Počinje sa izbor() DSL izjava nakon koje slijedi jedan ili više kada() DSL izjave. Svaki kada() sadrži predikatni izraz koji će, ako bude zadovoljen, rezultirati izvršavanjem sadržanih koraka obrade.

Ilustrirajmo ovaj EIP definiranjem rute koja troši datoteke iz jedne mape i premješta ih u dvije različite mape, ovisno o nastavku datoteke. Naša ruta je navedena u XML datoteci Spring koristeći prilagođenu XML sintaksu za Camel:

Definicija rute sadržana je u ContentBasedFileRouter klase u kojoj se datoteke usmjeravaju iz izvorne mape u dvije različite odredišne ​​mape, ovisno o njihovoj ekstenziji.

Kao alternativu, ovdje bismo mogli koristiti Spring Java config pristup, za razliku od Spring XML datoteke. Da bismo to učinili, moramo dodati dodatnu ovisnost našem projektu:

 org.apache.deva deva-proljeće-javaconfig 2.18.1 

Najnoviju verziju artefakta možete pronaći ovdje.

Nakon toga moramo produžiti Konfiguracija deve klase i nadjačati rute () metoda koja će se pozivati ContentBasedFileRouter:

@Configuration javna klasa ContentBasedFileRouterConfig proširuje CamelConfiguration {@Bean ContentBasedFileRouter getContentBasedFileRouter () {return new ContentBasedFileRouter (); } @Override javni popis ruta () {return Arrays.asList (getContentBasedFileRouter ()); }}

Proširenje se procjenjuje pomoću jezika jednostavnog izraza putem jednostavan() DSL izjava koja je namijenjena za procjenu izraza i predikata:

javna klasa ContentBasedFileRouter proširuje RouteBuilder {private static final String SOURCE_FOLDER = "src / test / source-folder"; privatni statički završni niz DESTINATION_FOLDER_TXT = "src / test / destination-folder-txt"; privatni statički završni niz DESTINATION_FOLDER_OTHER = "src / test / destination-folder-other"; @Override public void configure () baca izuzetak {from ("file: //" + SOURCE_FOLDER + "? Delete = true"). Choice () .when (simple ("$ {file: ext} == 'txt'" )) .to ("datoteka: //" + DESTINATION_FOLDER_TXT) .u suprotnom () .to ("datoteka: //" + DESTINATION_FOLDER_OTHER); }}

Ovdje se dodatno koristimo inače() DSL izraz kako bi se usmjerile sve poruke koje ne zadovoljavaju predikate dane s kada() izjave.

3. Prevoditelj poruka

Budući da svaki sustav koristi vlastiti format podataka, često je potrebno prevesti poruku koja dolazi iz drugog sustava u format podataka koji podržava odredišni sustav.

Devine potpore MessageTranslator usmjerivač koji nam omogućuje da transformiramo poruke koristeći bilo koji prilagođeni procesor u logici usmjeravanja, koristeći određeni grah za izvođenje transformacije ili pomoću transformirati() DSL izjava.

Primjer korištenja prilagođenog procesora možete pronaći u prethodnom članku gdje smo definirali procesor koji dodaje vremensku oznaku imenu datoteke svake dolazne datoteke.

Pokažimo sada kako se koristi Prevoditelj poruka pomoću transformirati() izjava:

javna klasa MessageTranslatorFileRouter proširuje RouteBuilder {private static final String SOURCE_FOLDER = "src / test / source-folder"; privatni statički završni niz DESTINATION_FOLDER = "src / test / destination-folder"; @Override public void configure () baca izuzetak {from ("file: //" + SOURCE_FOLDER + "? Delete = true") .transform (body (). Append (header (Exchange.FILE_NAME))) .to ("datoteka : // "+ DESTINATION_FOLDER); }}

U ovom primjeru dodajemo naziv datoteke sadržaju datoteke putem transformirati() izjava za svaku datoteku iz izvorne mape i premještanje transformiranih datoteka u odredišnu mapu.

4. Multicast

Multicast nam omogućuje usmjerite istu poruku na skup različitih krajnjih točaka i obradite ih na drugačiji način.

To je moguće pomoću multicast () DSL izjava, a zatim popisivanjem krajnjih točaka i koraka obrade unutar njih.

Prema zadanim postavkama, obrada na različitim krajnjim točkama ne vrši se paralelno, ali to se može promijeniti pomoću paralelna obrada () DSL izjava.

Camel će prema zadanim postavkama koristiti zadnji odgovor kao odlaznu poruku nakon multicastinga. Međutim, moguće je definirati drugačiju strategiju agregiranja koja će se koristiti za sastavljanje odgovora iz multicast-a.

Pogledajmo kako na primjeru izgleda Multicast EIP. Datoteke ćemo preusmjeriti iz izvorne mape na dvije različite rute gdje ćemo transformirati njihov sadržaj i poslati ih u različite odredišne ​​mape. Ovdje koristimo direktno: komponenta koja nam omogućuje povezivanje dviju ruta:

javna klasa MulticastFileRouter proširuje RouteBuilder {private static final String SOURCE_FOLDER = "src / test / source-folder"; privatni statički završni niz DESTINATION_FOLDER_WORLD = "src / test / destination-folder-world"; privatni statički završni niz DESTINATION_FOLDER_HELLO = "src / test / destination-folder-hello"; @Override public void configure () baca izuzetak {from ("file: //" + SOURCE_FOLDER + "? Delete = true") .multicast () .to ("direct: append", "direct: prepend"). End ( ); from ("direct: append") .transform (body (). append ("World")) .to ("file: //" + DESTINATION_FOLDER_WORLD); from ("direct: prepend") .transform (body (). prepend ("Hello")) .to ("file: //" + DESTINATION_FOLDER_HELLO); }}

5. Razdjelnik

Razdjelnik nam omogućuje podijeliti dolaznu poruku u više dijelova i obraditi svaki od njih pojedinačno. To je moguće pomoću podjela() DSL izjava.

Za razliku od Multicast, Splitter će promijeniti dolaznu poruku, dok će Multicast ostaviti takvu kakva jest.

Da bismo to demonstrirali na primjeru, definirat ćemo rutu gdje se svaki redak datoteke dijeli i transformira u pojedinačnu datoteku koja se zatim premješta u drugu odredišnu mapu. Svaka nova datoteka bit će stvorena s nazivom datoteke jednakim sadržaju datoteke:

javna klasa SplitterFileRouter proširuje RouteBuilder {private static final String SOURCE_FOLDER = "src / test / source-folder"; privatni statički završni niz DESTINATION_FOLDER = "src / test / destination-folder"; @Override public void configure () baca izuzetak {from ("file: //" + SOURCE_FOLDER + "? Delete = true") .split (body (). ConvertToString (). Tokenize ("\ n")) .setHeader ( Exchange.FILE_NAME, body ()) .to ("datoteka: //" + DESTINATION_FOLDER); }}

6. Kanal mrtvog slova

Uobičajeno je i treba očekivati ​​da se ponekad mogu dogoditi problemi, na primjer, blokade baze podataka, što može dovesti do toga da poruka ne bude isporučena kako se očekuje. Međutim, u određenim slučajevima pomoći će ponovni pokušaj s određenim kašnjenjem i poruka će se obraditi.

Dead Letter Channel omogućuje nam da kontroliramo što se događa s porukom kad ne uspije biti isporučena. Koristeći Dead Letter Channel možemo odrediti hoćemo li distribuirani izuzetak širiti pozivatelju i kamo usmjeriti neuspjelu Exchange.

Kada poruka ne bude isporučena, kanal mrtvog slova (ako se koristi) premjestit će je na krajnju točku mrtvog slova.

Pokažimo to na primjeru izbacivanjem iznimke na ruti:

javna klasa DeadLetterChannelFileRouter proširuje RouteBuilder {private static final String SOURCE_FOLDER = "src / test / source-folder"; @Override public void configure () baca iznimku {errorHandler (deadLetterChannel ("log: dead? Level = ERROR") .maximumRedeliveries (3) .redeliveryDelay (1000) .retryAttemptedLogLevel (LoggingLevel.ERROR)); from ("file: //" + SOURCE_FOLDER + "? delete = true") .process (exchange -> {throw new IllegalArgumentException ("Izuzetak bačen!")}}; }}

Ovdje smo definirali errorHandler koja bilježi neuspjele isporuke i definira strategiju ponovne isporuke. Postavljanjem retryAttemptedLogLevel (), svaki pokušaj ponovne isporuke zabilježit će se s određenom razinom dnevnika.

Da bi ovo bilo u potpunosti funkcionalno, dodatno moramo konfigurirati zapisnik.

Nakon pokretanja ovog testa, u konzoli su vidljivi sljedeći navodi dnevnika:

POGREŠKA DeadLetterChannel: 156 - Neuspjela isporuka za (MessageId: ID-ZAG0025-50922-1481340325657-0-1 na ExchangeId: ID-ZAG0025-50922-1481340325657-0-2). Pri pokušaju isporuke: 0 uhvaćeno: java.lang.IllegalArgumentException: Iznimka izbačena! POGREŠKA DeadLetterChannel: 156 - Neuspjela isporuka za (MessageId: ID-ZAG0025-50922-1481340325657-0-1 na ExchangeId: ID-ZAG0025-50922-1481340325657-0-2). Pri pokušaju isporuke: 1 uhvaćen: java.lang.IllegalArgumentException: Iznimka izbačena! POGREŠKA DeadLetterChannel: 156 - Neuspjela isporuka za (MessageId: ID-ZAG0025-50922-1481340325657-0-1 na ExchangeId: ID-ZAG0025-50922-1481340325657-0-2). Pri pokušaju isporuke: 2 uhvaćena: java.lang.IllegalArgumentException: Iznimka bačena! POGREŠKA DeadLetterChannel: 156 - Neuspjela isporuka za (MessageId: ID-ZAG0025-50922-1481340325657-0-1 na ExchangeId: ID-ZAG0025-50922-1481340325657-0-2). Pri pokušaju isporuke: 3 uhvaćena: java.lang.IllegalArgumentException: Iznimka izbačena! POGREŠKA mrtva: 156 - Razmjena [ExchangePattern: InOnly, BodyType: org.apache.camel.component.file.GenericFile, Body: [Tijelo se temelji na datoteci: GenericFile [File.txt]]]

Kao što možete primijetiti, svaki pokušaj ponovne isporuke bilježi se tako da prikazuje Exchange za koji isporuka nije bila uspješna.

7. Zaključak

U ovom smo članku predstavili uvod u obrasce integracije pomoću Apache Camel i demonstrirali ih na nekoliko primjera.

Pokazali smo kako se koriste ti obrasci integracije i zašto su oni korisni za rješavanje integracijskih izazova.

Kôd iz ovog članka možete pronaći na GitHubu.


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