Corak Integrasi Dengan Unta Apache

1. Gambaran keseluruhan

Artikel ini akan merangkumi beberapa corak integrasi perusahaan penting (EIP) yang disokong oleh Apache Camel. Corak integrasi membantu dengan menyediakan penyelesaian untuk kaedah penyatuan sistem yang standard.

Sekiranya anda perlu terlebih dahulu membaca asas-asas Apache Camel, sila lawati artikel ini untuk mengetahui asas-asasnya.

2. Mengenai EIP

Corak integrasi perusahaan adalah corak reka bentuk yang bertujuan untuk memberikan penyelesaian untuk cabaran integrasi. Unta menyediakan pelaksanaan untuk banyak corak ini. Untuk melihat senarai penuh corak yang disokong, lawati pautan ini.

Dalam artikel ini, kita akan membahas corak integrasi Content Router, Message Translator, Multicast, Splitter dan Dead Letter Channel.

2. Penghala Berasaskan Kandungan

Content Based Router adalah penghala mesej yang merutekan pesan ke tujuannya berdasarkan tajuk mesej, sebahagian dari muatan atau pada dasarnya apa saja dari pertukaran mesej yang kami anggap sebagai kandungan.

Ia dimulakan dengan pilihan () penyataan DSL diikuti oleh satu atau lebih apabila () penyataan DSL. Setiap ketika () mengandung ungkapan predikat yang, jika puas, akan menghasilkan pelaksanaan langkah pemrosesan terkandung.

Mari kita gambarkan EIP ini dengan menentukan laluan yang menggunakan fail dari satu folder dan memindahkannya ke dalam dua folder yang berbeza bergantung pada peluasan fail. Laluan kami dirujuk dalam fail Spring XML menggunakan sintaks XML khusus untuk Camel:

Definisi laluan terdapat dalam kelas ContentBasedFileRouter di mana fail disalurkan dari folder sumber ke dalam dua folder tujuan yang berbeza bergantung pada peluasannya.

Sebagai alternatif, kita dapat menggunakan pendekatan konfigurasi Spring Java di sini daripada menggunakan file Spring XML. Untuk melakukan itu, kita perlu menambahkan kebergantungan tambahan pada projek kita:

 org.apache.camel camel-spring-javaconfig 2.18.1 

Versi artifak terkini boleh didapati di sini.

Selepas itu, kita perlu memperluaskan kelas CamelConfiguration dan kaedah override () yang akan merujuk ContentBasedFileRouter :

@Configuration public class ContentBasedFileRouterConfig extends CamelConfiguration { @Bean ContentBasedFileRouter getContentBasedFileRouter() { return new ContentBasedFileRouter(); } @Override public List routes() { return Arrays.asList(getContentBasedFileRouter()); } }

Sambungan tersebut dinilai menggunakan Bahasa Ekspresi Mudah melalui pernyataan DSL sederhana () yang dimaksudkan untuk digunakan untuk menilai Ekspresi dan Predikat:

public class ContentBasedFileRouter extends RouteBuilder { private static final String SOURCE_FOLDER = "src/test/source-folder"; private static final String DESTINATION_FOLDER_TXT = "src/test/destination-folder-txt"; private static final String DESTINATION_FOLDER_OTHER = "src/test/destination-folder-other"; @Override public void configure() throws Exception { from("file://" + SOURCE_FOLDER + "?delete=true").choice() .when(simple("${file:ext} == 'txt'")) .to("file://" + DESTINATION_FOLDER_TXT).otherwise() .to("file://" + DESTINATION_FOLDER_OTHER); } }

Di sini kami juga menggunakan pernyataan DSL sebaliknya () untuk mengarahkan semua mesej yang tidak memenuhi predikat yang diberikan dengan pernyataan bila () .

3. Penterjemah Mesej

Oleh kerana setiap sistem menggunakan format datanya sendiri, seringkali diperlukan untuk menerjemahkan pesan yang berasal dari sistem lain ke dalam format data yang disokong oleh sistem tujuan.

Camel menyokong penghala MessageTranslator yang membolehkan kita mengubah mesej menggunakan pemproses tersuai dalam logik penghalaan, menggunakan kacang tertentu untuk melakukan transformasi atau dengan menggunakan pernyataan DSL transform () .

Contoh dengan menggunakan pemproses khusus boleh didapati di artikel sebelumnya di mana kami menentukan pemproses yang menyediakan cap waktu untuk setiap nama fail fail yang masuk.

Sekarang mari kita tunjukkan cara menggunakan Penterjemah Mesej menggunakan pernyataan transform () :

public class MessageTranslatorFileRouter extends RouteBuilder { private static final String SOURCE_FOLDER = "src/test/source-folder"; private static final String DESTINATION_FOLDER = "src/test/destination-folder"; @Override public void configure() throws Exception { from("file://" + SOURCE_FOLDER + "?delete=true") .transform(body().append(header(Exchange.FILE_NAME))) .to("file://" + DESTINATION_FOLDER); } }

Dalam contoh ini, kami menambahkan nama file ke file isi melalui pernyataan transform () untuk setiap fail dari folder sumber dan memindahkan fail yang diubah ke folder tujuan.

4. Multicast

Multicast membolehkan kita mengarahkan mesej yang sama ke sekumpulan titik akhir yang berbeza dan memprosesnya dengan cara yang berbeza .

Ini dimungkinkan dengan menggunakan penyataan DSL multicast () dan kemudian dengan menyenaraikan titik akhir dan langkah memproses di dalamnya.

Secara lalai, pemprosesan pada titik akhir yang berbeza tidak dilakukan secara selari, tetapi ini boleh diubah dengan menggunakan pernyataan DSL parallelProcessing () .

Unta akan menggunakan balasan terakhir sebagai mesej keluar setelah berbilang siaran secara lalai. Walau bagaimanapun, adalah mungkin untuk menentukan strategi pengagregatan yang berbeda yang akan digunakan untuk mengumpulkan balasan dari pelbagai stesen.

Mari kita lihat bagaimana rupa Multicast EIP pada contoh. Kami akan menghantar fail multicast dari folder sumber ke dua laluan yang berbeza di mana kami akan mengubah kandungannya dan menghantarnya ke folder tujuan yang berbeza. Di sini kita menggunakan komponen langsung: yang membolehkan kita menghubungkan dua laluan bersama:

public class MulticastFileRouter extends RouteBuilder { private static final String SOURCE_FOLDER = "src/test/source-folder"; private static final String DESTINATION_FOLDER_WORLD = "src/test/destination-folder-world"; private static final String DESTINATION_FOLDER_HELLO = "src/test/destination-folder-hello"; @Override public void configure() throws Exception { 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. Pemisah

Pembahagi membolehkan kita membahagikan mesej masuk menjadi beberapa bahagian dan memprosesnya secara berasingan. Ini boleh dilakukan dengan menggunakan penyataan DSL split () .

Berbanding dengan Multicast, Splitter akan mengubah mesej masuk, sementara Multicast akan meninggalkannya seperti adanya.

Untuk menunjukkan ini sebagai contoh, kami akan menentukan laluan di mana setiap baris dari fail dipecah dan diubah menjadi fail individu yang kemudian dipindahkan ke folder tujuan yang berbeza. Setiap fail baru akan dibuat dengan nama fail yang sama dengan kandungan fail:

public class SplitterFileRouter extends RouteBuilder { private static final String SOURCE_FOLDER = "src/test/source-folder"; private static final String DESTINATION_FOLDER = "src/test/destination-folder"; @Override public void configure() throws Exception { from("file://" + SOURCE_FOLDER + "?delete=true") .split(body().convertToString().tokenize("\n")) .setHeader(Exchange.FILE_NAME, body()) .to("file://" + DESTINATION_FOLDER); } }

6. Saluran Surat Mati

Ini adalah perkara biasa dan diharapkan masalah kadang-kadang dapat terjadi, misalnya, kebuntuan pangkalan data, yang dapat menyebabkan pesan tidak dapat disampaikan seperti yang diharapkan. Walau bagaimanapun, dalam kes tertentu, mencuba lagi dengan kelewatan tertentu akan membantu dan mesej akan diproses.

Dead Letter Channel allows us to control what happens with a message once it fails to be delivered. Using Dead Letter Channel we can specify whether to propagate the thrown Exception to the caller and where to route the failed Exchange.

When a message fails to be delivered, Dead Letter Channel (if used) will move the message to the dead letter endpoint.

Let's demonstrate this on an example by throwing an exception on the route:

public class DeadLetterChannelFileRouter extends RouteBuilder { private static final String SOURCE_FOLDER = "src/test/source-folder"; @Override public void configure() throws Exception { errorHandler(deadLetterChannel("log:dead?level=ERROR") .maximumRedeliveries(3).redeliveryDelay(1000) .retryAttemptedLogLevel(LoggingLevel.ERROR)); from("file://" + SOURCE_FOLDER + "?delete=true") .process(exchange -> { throw new IllegalArgumentException("Exception thrown!"); }); } }

Here we defined an errorHandler which logs failed deliveries and defines redelivery strategy. By setting retryAttemptedLogLevel(), each redelivery attempt will be logged with specified log level.

In order for this to be fully functional, we additionally need to configure a logger.

Setelah menjalankan ujian ini, penyataan log berikut dapat dilihat di konsol:

ERROR DeadLetterChannel:156 - Failed delivery for (MessageId: ID-ZAG0025-50922-1481340325657-0-1 on ExchangeId: ID-ZAG0025-50922-1481340325657-0-2). On delivery attempt: 0 caught: java.lang.IllegalArgumentException: Exception thrown! ERROR DeadLetterChannel:156 - Failed delivery for (MessageId: ID-ZAG0025-50922-1481340325657-0-1 on ExchangeId: ID-ZAG0025-50922-1481340325657-0-2). On delivery attempt: 1 caught: java.lang.IllegalArgumentException: Exception thrown! ERROR DeadLetterChannel:156 - Failed delivery for (MessageId: ID-ZAG0025-50922-1481340325657-0-1 on ExchangeId: ID-ZAG0025-50922-1481340325657-0-2). On delivery attempt: 2 caught: java.lang.IllegalArgumentException: Exception thrown! ERROR DeadLetterChannel:156 - Failed delivery for (MessageId: ID-ZAG0025-50922-1481340325657-0-1 on ExchangeId: ID-ZAG0025-50922-1481340325657-0-2). On delivery attempt: 3 caught: java.lang.IllegalArgumentException: Exception thrown! ERROR dead:156 - Exchange[ExchangePattern: InOnly, BodyType: org.apache.camel.component.file.GenericFile, Body: [Body is file based: GenericFile[File.txt]]]

Seperti yang anda perhatikan, setiap percubaan penghantaran semula dicatat menampilkan Exchange yang penghantarannya tidak berjaya.

7. Kesimpulannya

Dalam artikel ini, kami menunjukkan pengenalan mengenai pola integrasi menggunakan Apache Camel dan menunjukkannya pada beberapa contoh.

Kami menunjukkan cara menggunakan corak integrasi ini dan mengapa ia bermanfaat untuk menyelesaikan cabaran integrasi.

Kod dari artikel ini boleh didapati di GitHub.