Apache Camel - Hướng dẫn nhanh

Hãy xem xét tình huống mà một cửa hàng tạp hóa trực tuyến lớn trong thị trấn của bạn, chẳng hạn như Bigbasket ở Ấn Độ mời bạn thiết kế một giải pháp CNTT cho họ. Giải pháp ổn định và có thể mở rộng sẽ giúp họ vượt qua các vấn đề bảo trì phần mềm mà họ đang gặp phải hiện nay. Cửa hàng trực tuyến này đã hoạt động kinh doanh trong thập kỷ qua. Cửa hàng chấp nhận các đơn đặt hàng trực tuyến cho các loại sản phẩm khác nhau từ khách hàng của họ và phân phối chúng cho các nhà cung cấp tương ứng. Ví dụ, giả sử bạn đặt một số xà phòng, dầu và sữa; ba mặt hàng này sẽ được phân phối cho ba nhà cung cấp tương ứng. Ba nhà cung cấp sau đó sẽ gửi nguồn cung cấp của họ đến một điểm phân phối chung, từ đó trung tâm giao hàng sẽ thực hiện toàn bộ đơn hàng. Bây giờ, chúng ta hãy xem xét vấn đề mà họ đang phải đối mặt ngày hôm nay.

Khi cửa hàng này bắt đầu kinh doanh, cửa hàng đang chấp nhận các đơn đặt hàng trong một tệp văn bản thuần túy được phân tách bằng dấu phẩy. Sau một thời gian, cửa hàng chuyển sang đặt hàng theo tin nhắn. Sau đó, một số nhà phát triển phần mềm đã đề xuất một vị trí đặt hàng dựa trên XML. Cuối cùng, cửa hàng thậm chí đã điều chỉnh giao diện dịch vụ web. Bây giờ, đây là vấn đề thực sự. Các đơn đặt hàng hiện có các định dạng khác nhau. Rõ ràng, mỗi khi công ty nâng cấp định dạng chấp nhận đơn hàng, họ không muốn phá vỡ giao diện đã triển khai trước đó để không gây ra sự nhầm lẫn trong tâm trí khách hàng.

Đồng thời, khi công việc kinh doanh tiếp tục phát triển, cửa hàng định kỳ bổ sung các nhà cung cấp mới vào các tiết mục của mình. Mỗi nhà cung cấp như vậy có giao thức riêng để chấp nhận đơn đặt hàng. Một lần nữa, chúng ta phải đối mặt với vấn đề tích hợp; kiến trúc ứng dụng của chúng tôi phải có khả năng mở rộng để đáp ứng các nhà cung cấp mới với cơ chế đặt hàng độc nhất của họ.

Toàn bộ tình huống được thể hiện trong hình sau:

Bây giờ, hãy để chúng tôi xem cách Apache Camel có thể giải cứu bạn để cung cấp kiến ​​trúc giải pháp thanh lịch, có thể bảo trì, có thể mở rộng cho kịch bản được mô tả.

Trước khi tiến hành giải pháp, chúng ta cần đưa ra một giả định nhỏ. Đối với tất cả các cuộc thảo luận trong hướng dẫn này, chúng tôi sẽ giả định rằng các đơn đặt hàng trực tuyến được đặt ở định dạng XML. Định dạng điển hình cho tệp đơn đặt hàng mà chúng tôi sẽ sử dụng trong suốt các cuộc thảo luận của chúng tôi được hiển thị ở đây -

<?xml version = "1.0" encoding = "UTF-8"?>
<OrderID Order = "001">
   <order product = "soaps">
      <items>
         <item>
            <Brand>Cinthol</Brand>
            <Type>Original</Type>
            <Quantity>4</Quantity>
            <Price>25</Price>
         </item>
         <item>
            <Brand>Cinthol</Brand>
            <Type>Lime</Type>
            <Quantity>6</Quantity>
            <Price>30</Price>
         </item>
      </items>
   </order>
   
   <order product = "Oil">
      <items>
         <item>
            <Brand>Saffola</Brand>
            <Type>Gold</Type>
            <Quantity>2</Quantity>
            <Price>649</Price>
         </item>
         <item>
            <Brand>Fortune</Brand>
            <Type>Sunlite</Type>
            <Quantity>1</Quantity>
            <Price>525</Price>
         </item>
      </items>
   </order>
   
   <order product = "Milk">
      <items>
         <item>
            <Product>Milk</Product>
            <Brand>Amul</Brand>
            <Type>Pure</Type>
            <Quantity>2</Quantity>
            <Price>60</Price>
         </item>
      </items>
   </order>
</OrderID>

Chúng tôi sẽ sử dụng mẫu XML ở trên để minh họa các ví dụ về Camel trong hướng dẫn này.

Camel là một hộp đen nhận tin nhắn từ một số điểm cuối và gửi nó đến một điểm cuối khác. Trong hộp đen, tin nhắn có thể được xử lý hoặc chuyển hướng đơn giản.

Vậy tại sao phải có một khuôn khổ cho việc này? Trong các tình huống thực tế như đã thấy trong nghiên cứu điển hình giới thiệu, có thể có nhiều người gửi và nhiều người nhận, mỗi người tuân theo giao thức riêng của nó như ftp, http và jms. Hệ thống có thể yêu cầu nhiều quy tắc phức tạp chẳng hạn như tin nhắn từ người gửi A chỉ được gửi cho B & C. Trong các tình huống, bạn có thể phải dịch tin nhắn sang định dạng khác mà người nhận mong đợi. Bản dịch này có thể tuân theo các điều kiện nhất định dựa trên nội dung thư. Vì vậy, về cơ bản bạn có thể cần phải dịch giữa các giao thức, các thành phần kết dính với nhau, xác định các quy tắc định tuyến và cung cấp tính năng lọc dựa trên nội dung thư. Điều này được minh họa trong hình sau:

Để đáp ứng các yêu cầu trên và thiết kế một kiến ​​trúc phần mềm phù hợp cho nhiều trường hợp như vậy, các Mẫu Tích hợp Doanh nghiệp ( EIP ) đã được Gregor Hohpe và Bobby Woolf ghi lại vào năm 2003. Apache Camel cung cấp cách triển khai các mẫu này và mục đích của hướng dẫn này là để dạy bạn làm thế nào để sử dụng Camel trong các tình huống như mô tả trong phần giới thiệu.

Apache Camel là một khung công tác mã nguồn mở. Nó là một phần mềm trung gian hướng tin nhắn cung cấp công cụ dàn xếp và định tuyến dựa trên quy tắc. Bạn có thể xác định các quy tắc chẳng hạn như nếu đơn đặt hàng "sữa" chuyển hướng nó đến một nhà cung cấp sữa và nếu nó là một đơn đặt hàng "dầu" thì chuyển hướng nó đến một nhà cung cấp dầu, v.v. Sử dụng Camel, bạn sẽ có thể triển khai các quy tắc này và thực hiện định tuyến bằng mã Java quen thuộc. Có nghĩa là bạn có thể sử dụng Java IDE quen thuộc của mình để xác định các quy tắc này trong một môi trường an toàn kiểu. Chúng tôi không cần sử dụng các tệp cấu hình XML, các tệp này thường có xu hướng cồng kềnh. Camel mặc dù hỗ trợ cấu hình XML thông qua Spring framework, nếu bạn thích sử dụng XML để định cấu hình các quy tắc. Bạn thậm chí có thể sử dụng các tệp Cấu hình XML Blueprint và thậm chí là một Scala DSL, nếu bạn là một người yêu thích Scala. Điều đó cũng có nghĩa là bạn có thể sử dụng Java, Scala IDE yêu thích của mình hoặc thậm chí là một trình soạn thảo XML đơn giản để định cấu hình các quy tắc.

Đầu vào cho công cụ này có thể là tệp văn bản được phân tách bằng dấu phẩy, POJO (Đối tượng Java cũ thuần túy), XML là bất kỳ định dạng nào trong số một số định dạng khác được Camel hỗ trợ. Tương tự, đầu ra của công cụ có thể được chuyển hướng đến một tệp, đến hàng đợi tin nhắn hoặc thậm chí màn hình điều khiển của bạn để bạn xem các đơn đặt hàng được gửi đến các nhà cung cấp tương ứng. Chúng được gọi là các điểm cuối và Camel hỗ trợ mẫu EIP Điểm cuối Thông báo . Các điểm cuối của lạc đà sẽ được thảo luận sau trong chương Điểm cuối.

Camel thường được sử dụng với Apache ServiceMix , Apache ActiveMQ và Apache CXF để triển khai các kiến ​​trúc hướng dịch vụ.

Sau khi xem tổng quan về Apache Camel, bây giờ chúng ta hãy đi sâu vào các tính năng của nó để xem những gì nó cung cấp. Chúng ta đã biết Apache Camel là một khung công tác Java mã nguồn mở về cơ bản cung cấp việc triển khai các EIP khác nhau. Camel làm cho việc tích hợp dễ dàng hơn bằng cách cung cấp kết nối với nhiều loại phương tiện vận tải và API. Ví dụ: bạn có thể dễ dàng định tuyến JMS sang JSON, JSON sang JMS, HTTP sang JMS, FTP sang JMS, thậm chí HTTP sang HTTP và kết nối với Microservices. Bạn chỉ cần cung cấp các điểm cuối thích hợp ở cả hai đầu. Camel có thể mở rộng và do đó trong tương lai có thể thêm nhiều thiết bị đầu cuối dễ dàng vào khung công tác.

Để kết nối các EIP và truyền tải với nhau, bạn sử dụng các Ngôn ngữ dành riêng cho Miền (DSL) như Java, Scala và Groovy. Quy tắc định tuyến Java điển hình có thể giống như sau:

from ("file:/order").to("jms:orderQueue");

Quy tắc định tuyến này tải các tệp từ order thư mục, tạo một thông báo JMS với nội dung của tệp và gửi thông báo đó đến một hàng đợi được gọi là orderQueue.

Dưới đây là một số tính năng quan trọng nhất của Camel mà bạn sẽ thấy hữu ích trong việc phát triển các ứng dụng của Camel -

  • Camel hỗ trợ các định dạng dữ liệu có thể cắm thêm và bộ chuyển đổi kiểu cho các chuyển đổi thông báo như vậy, vì vậy các định dạng và bộ chuyển đổi mới có thể được thêm vào trong tương lai. Hiện tại, nó hỗ trợ một số định dạng và trình chuyển đổi phổ biến; tên một số - CSV, EDI, JAXB, JSON, XmlBeans, XStream, Flatpack, Zip.

  • Camel hỗ trợ các ngôn ngữ có thể cắm được để viết các vị từ trong DSL. Một số ngôn ngữ được hỗ trợ bao gồm JavaScript, Groovy, Python, PHP, Ruby, SQL, XPath, XQuery.

  • Camel hỗ trợ mô hình POJO để bạn có thể cắm Javabeans ở nhiều điểm khác nhau.

  • Camel giúp dễ dàng kiểm tra các hệ thống phân tán và không đồng bộ lớn như vậy bằng cách sử dụng tin nhắn.

Bây giờ chúng ta hãy hiểu kiến ​​trúc của Camel và xem các tính năng khác nhau được triển khai như thế nào.

Kiến trúc Camel bao gồm ba thành phần - Công cụ tích hợp và Bộ định tuyến, Bộ xử lý và Thành phần. Điều này được minh họa trong hình sau:

Bản thân lõi Camel rất nhỏ và chứa 13 thành phần thiết yếu. Hơn 80 thành phần còn lại nằm ngoài lõi. Điều này giúp duy trì sự phụ thuộc thấp vào nơi nó được triển khai và thúc đẩy các tiện ích mở rộng trong tương lai. CácComponents mô-đun cung cấp một Endpointgiao diện với thế giới bên ngoài. Các điểm cuối được chỉ định bởi URI, chẳng hạn nhưfile:/orderjms:orderQueue mà bạn đã thấy trong chương trước.

Các Processorsmô-đun được sử dụng để thao tác và dàn xếp thông báo giữa các Điểm cuối. Các EIP mà tôi đã đề cập trước đó được thực hiện trong mô-đun này. Nó hiện hỗ trợ hơn 40 mẫu như được ghi trong sách EIP và các đơn vị xử lý hữu ích khác.

Các ProcessorsEndpoints được kết nối với nhau trong Integration Engine and Routermô-đun sử dụng DSL. Trong khi nối những thứ này, bạn có thể sử dụng bộ lọc để lọc thư dựa trên tiêu chí do người dùng xác định. Như đã đề cập trước đó, bạn có một số tùy chọn để viết các quy tắc này. Bạn có thể sử dụng Java, Scala, Groovy hoặc thậm chí cả XML cho việc này.

Bây giờ, chúng ta đến với thành phần quan trọng nhất của Camel, có thể được coi là cốt lõi - CamelContext.

CamelContext cung cấp quyền truy cập vào tất cả các dịch vụ khác trong Camel như thể hiện trong hình sau:

Hãy để chúng tôi xem xét các dịch vụ khác nhau. CácRegistrytheo mặc định, mô-đun là sổ đăng ký JNDI, chứa tên của các Javabeans khác nhau mà ứng dụng của bạn sử dụng. Nếu bạn sử dụng Camel với Spring, đây sẽ là SpringApplicationContext. Nếu bạn sử dụng Camel trong vùng chứa OSGI, đây sẽ làOSGI registry. CácType convertersnhư tên cho thấy chứa các bộ chuyển đổi kiểu được tải khác nhau, chuyển đổi đầu vào của bạn từ định dạng này sang định dạng khác. Bạn có thể sử dụng các bộ chuyển đổi loại tích hợp sẵn hoặc cung cấp cơ chế chuyển đổi của riêng bạn. CácComponentsmô-đun chứa các thành phần được ứng dụng của bạn sử dụng. Các thành phần được tải bằng cách tự động khám phá trênclasspathmà bạn chỉ định. Trong trường hợp vùng chứa OSGI, chúng được tải bất cứ khi nào một gói mới được kích hoạt. Chúng tôi đã thảo luận vềEndpointsRoutestrong các chương trước. CácData formats mô-đun chứa các định dạng dữ liệu đã tải và cuối cùng là Languages mô-đun đại diện cho các ngôn ngữ được tải.

Đoạn mã ở đây sẽ cung cấp cho bạn cái nhìn sơ lược về cách CamelContext được tạo trong một ứng dụng Camel -

CamelContext context = new DefaultCamelContext();
try {
   context.addRoutes(new RouteBuilder() {
      // Configure filters and routes
   }
}
);

Các DefaultCamelContext lớp cung cấp một triển khai cụ thể của CamelContext. TrongaddRoutes , chúng tôi tạo một phiên bản ẩn danh của RouteBuilder. Bạn có thể tạo nhiềuRouteBuildercác trường hợp để xác định nhiều hơn một định tuyến. Mỗi tuyến đường trong cùng một ngữ cảnh phải có một ID duy nhất. Các tuyến có thể được thêm động trong thời gian chạy. Tuyến đường có ID giống như tuyến đường đã xác định trước đó sẽ thay thế tuyến đường cũ hơn.

Những gì bên trong RouteBuilder ví dụ được mô tả tiếp theo.

Các tuyến đường

Bộ định tuyến xác định quy tắc để di chuyển thông báo from đến một tovị trí. Bạn dùngRouteBuilderđể xác định một tuyến đường trong Java DSL. Bạn tạo một tuyến đường bằng cách mở rộngRouteBuilderlớp học. Lộ trình bắt đầu bằngfromđiểm cuối và kết thúc tại một hoặc nhiều điểm cuối. Ở giữa hai, bạn thực hiện logic xử lý. Bạn có thể định cấu hình bất kỳ số lượng tuyến đường nào trong mộtconfigure phương pháp.

Đây là một ví dụ điển hình về cách tạo tuyến đường -

context.addRoutes(new RouteBuilder() {
   @Override
   public void configure() throws Exception {
      from("direct:DistributeOrderDSL")
      .to("stream:out");
   }
}

Chúng tôi ghi đè phương thức cấu hình của RouteBuilderlớp và thực hiện cơ chế định tuyến và lọc của chúng tôi trong đó. Trong trường hợp hiện tại, chúng tôi chuyển hướng đầu vào nhận được từ Điểm cuốiDistributeOrderDSL vào bảng điều khiển, được chỉ định bởi Điểm cuối stream:out.

Lựa chọn ngôn ngữ

Bạn có thể tạo các tuyến đường bằng các ngôn ngữ khác nhau. Dưới đây là một số ví dụ về cách xác định cùng một tuyến đường bằng ba ngôn ngữ khác nhau -

Java DSL

from ("file:/order").to("jms:orderQueue");

DSL mùa xuân

<route>
   <from uri = "file:/order"/>
   <to uri = "jms:orderQueue"/>
</route>

Scala DSL

from "file:/order" -> "jms:orderQueue"

Bộ lọc

Bạn sử dụng bộ lọc để chọn một phần của nội dung đầu vào. Để thiết lập bộ lọc, bạn sử dụng bất kỳ triển khai Vị ngữ tùy ý nào . Đầu vào được lọc sau đó sẽ được gửi đến Điểm cuối đích mong muốn của bạn. Trong ví dụ này, chúng tôi lọc ra tất cả các đơn đặt hàng xà phòng để chúng có thể được gửi chung đến một nhà cung cấp xà phòng.

from("direct:DistributeOrderDSL")
   .split(xpath("//order[@product = 'soaps']/items"))
      .to("stream:out");

Trong ví dụ, chúng tôi đã sử dụng xpathvị ngữ để lọc. Nếu bạn thích sử dụng lớp Java để lọc, hãy sử dụng mã sau:

from("direct:DistributeOrderDSL")
   .filter()
      .method(new Order(),"filter")
         .to("stream:out");

Các Order là lớp Java tùy chỉnh của bạn với cơ chế lọc của riêng bạn.

Bạn có thể kết hợp nhiều vị từ trong một định tuyến như sau:

from("direct:DistributeOrderDSL")
   .choice()
      .when(header("order").isEqualTo("oil"))
         .to("direct:oil")
      .when(header("order").isEqualTo("milk"))
         .to("direct:milk")
      .otherwise()
         .to("direct:d");

Vì vậy, bây giờ tất cả các đơn đặt hàng "dầu" sẽ được chuyển cho nhà cung cấp dầu, đơn hàng "sữa" sẽ đến nhà cung cấp sữa và phần còn lại vào một nhóm chung.

Bộ xử lý tùy chỉnh

Bạn cũng có thể sử dụng xử lý tùy chỉnh. Ví dụ dưới đây tạo một bộ xử lý tùy chỉnh được gọi làmyCustomProcessor và sử dụng nó trong trình xây dựng tuyến đường.

Processor myCustomProcessor = new Processor() {
   public void process(Exchange exchange) {
      // implement your custom processing
   }
};
RouteBuilder builder = new RouteBuilder() {
   public void configure() {
      from("direct:DistributeOrderDSL")
      .process(myProcessor);
   }
};

Bạn có thể sử dụng bộ xử lý tùy chỉnh cùng với sự lựa chọn và lọc để kiểm soát tốt hơn việc dàn xếp và định tuyến của mình -

from("direct:DistributeOrderDSL")
   .filter(header("order").isEqualTo("milk"))
      .process(myProcessor);

Sử dụng XML

Các tuyến có thể được xác định bằng XML lớn hơn, nếu bạn thích nó. Đoạn mã XML sau đây cho biết cách tạo một tuyến đường cùng với một số lọc qua Spring XML:

<camelContext xmlns = "http://camel.apache.org/schema/spring">
   <route>
      <from uri = "direct:DistributeOrderXML"/>
      <log message = "Split by Distribute Order"/>
      <split>
         <xpath>//order[@product = 'Oil']/items</xpath>
         <to uri = "file:src/main/resources/order/"/>
         <to uri = "stream:out"/>
      </split>
   </route>
</camelContext>

Sau khi xem các tuyến đường được xây dựng như thế nào, bây giờ chúng ta sẽ thấy các kỹ thuật tạo Điểm cuối khác nhau.

Chúng tôi đã tìm hiểu về cách các điểm cuối trông như thế nào trong mã tích hợp của chúng tôi. Các biểu thức mà chúng tôi đã sử dụng cho đến nay, chẳng hạn nhưfile:/order, jms:orderQueue, direct:distributeOrderDSLlà các điểm cuối. Như bạn thấy, chúng tuân theo các định dạng đặc tả URI. Trong khi đánh giá URI này,CamelContext tạo ra Endpointví dụ; bạn không cần phải lo lắng về việc khởi tạoEndpoint triển khai trong DSL của bạn.

Lấy các ví dụ trước đó của chúng tôi, bạn chỉ định các điểm cuối trong Java DSL như ở đây -

from ("file:/order").to("jms:orderQueue");

Và vào mùa Xuân như đây -

<route>
   <from uri = "file:/order"/>
   <to uri = "jms:orderQueue"/>
</route>

Trong cả hai trường hợp, điểm cuối là một chuỗi không đổi. Trong một số trường hợp nhất định, bạn có thể muốn xây dựng chuỗi này trong thời gian chạy. Bạn có thể làm như vậy bằng cách sử dụng JavaStringcác phương pháp định dạng. Camel cung cấp một cách tiếp cận khác đơn giản hơn để tạo các chuỗi URI này trong thời gian chạy. Với mục đích này, Camel cung cấpfromFtoFcác phương thức chấp nhận các đối số với các tham số do người dùng chỉ định. Câu lệnh sau minh họa việc sử dụngtoF phương pháp -

from("direct:distributeOrderDSL”).toF("file://%s?fileName=%s", path, name);

Do các phương pháp này, nhu cầu sử dụng Java tích hợp String các phương thức định dạng bị xóa.

Camel sử dụng ngôn ngữ Đơn giản theo mặc định để tính toán biểu thức điểm cuối. CácSimple ngôn ngữ được thiết kế chủ yếu để đánh giá ExpressionsPredicatesmà không cần bận tâm nhiều về sự phức tạp của XPath. Để đánh giá các vị từ, bạn có thể kết hợp một ngôn ngữ khác, chẳng hạn nhưxpath với mặc định Simplengôn ngữ. Điều này được thực hiện bằng cách sử dụng dấu cộng để phân tách ngôn ngữ khác. Đoạn mã ở đây cho biết cách nốixpath chuỗi vào biểu thức được viết bằng Simple.

from("direct:start")
.toD("jms:${orderQueue}+language:xpath:/order/@id");

Trong Spring, bạn có thể đạt được điều tương tự như ở đây -

<route>
   <from uri = "direct:start"/>
   <toD uri = "jms:${orderQueue}+language:xpath:/order/@id"/>
</route>

Bạn có thể ghép bao nhiêu ngôn ngữ tùy thích, mỗi ngôn ngữ được phân tách bằng dấu cộng với ngôn ngữ trước đó. Danh sách các ngôn ngữ được hỗ trợ có thể được tìm thấy tại đây .

Camel cung cấp một số thành phần được xây dựng sẵn.

Trong chương này, chúng tôi sẽ thảo luận một số thành phần quan trọng từ camel-core mô-đun.

hạt đậu

Các Beanthành phần liên kết đậu với trao đổi tin nhắn Camel. URI để tạo một Điểm cuối được chỉ định làbean:beanID, Ở đâu beanID là tên của hạt đậu như được chỉ định trong Registry.

JndiContext jndiContext = new JndiContext();
jndiContext.bind("MilkOrder", new MilkOrderProcessor());
CamelContext camelContext = new DefaultCamelContext(jndiContext);

camelContext.addRoutes(new RouteBuilder() {
   public void configure() {
      from("direct:bigBasket")
         .to("bean:MilkOrder?method=placeOrder");
   }
});

Lưu ý cách điểm cuối được chỉ định bằng cách sử dụng bean:giao thức. Bạn có thể tùy ý chỉ định phương thức bean sẽ được gọi; trong trường hợp này, phương thức được gọi làplaceOrdersẽ được gọi trong khi đánh giá biểu thức Điểm cuối. CácMilkOrder là một tên JNDI cho MilkOrderProcessorJavabean như đã đăng ký trong hai dòng đầu tiên của đoạn mã. Định nghĩa củaMilkOrderProcessor bản thân nó được bỏ qua ở đây cho ngắn gọn.

Thẳng thắn

Bạn hẳn đã nhận thấy việc sử dụng Directtrong các ví dụ trước của chúng tôi. Để gửi đơn đặt hàng đến một nhà cung cấp dầu, chúng tôi đã sử dụngdirect:oiltrong đặc tả Điểm cuối. Việc sử dụngDirectthành phần cho phép bạn gọi đồng bộ một điểm cuối. Hai đoạn mã sau đây từ các ví dụ trước của chúng tôi minh họa việc sử dụngDirect -

.when(header("order").isEqualTo("oil"))
   .to("direct:oil")

Và,

from("direct:DistributeOrderDSL")
   .process(myProcessor);

Tập tin

Các Filethành phần cung cấp quyền truy cập vào hệ thống tệp trên máy của bạn. Sử dụng thành phần này, bạn sẽ có thể lưu tin nhắn từ các thành phần khác vào đĩa cục bộ. Ngoài ra, nó cho phép các thành phần Camel khác xử lý các tệp cục bộ. Bạn có thể sử dụng một trong haifile:directoryName[?options] hoặc là file://directoryName[?options]dưới dạng định dạng URI trong khi sử dụng thành phần Tệp. Trước đó bạn đã thấy việc sử dụng thành phần này -

from ("file:/order").to("jms:orderQueue");

Lưu ý rằng Filethành phần mặc định lấy tên thư mục. Do đó, nội dung của thư mục đặt hàng sẽ được lấy làm nội dung đầu vào. Để chỉ định một tệp cụ thể trongorder thư mục, bạn sẽ sử dụng câu lệnh sau:

from ("file:/order?fileName = order.xml").to("jms:orderQueue");

Nhật ký

Các Logthành phần cho phép bạn đăng nhập các thông báo vào cơ chế ghi nhật ký cơ bản. Camel sử dụng Simple Logging Facade cho Java (SLF4J) như một phần trừu tượng cho các khung ghi nhật ký khác nhau. Bạn có thể sử dụngjava.util.logging, logback, log4jđể ghi nhật ký. Đoạn mã này minh họa việc sử dụngLog thành phần -

from("direct:DistributeOrderDSL")
   .to("bean:MilkOrder?method = placeOrder")
   .to("log:com.example.com?level = INFO&showBody = true");

SEDA

Các SEDA thành phần cho phép bạn gọi bất đồng bộ một điểm cuối khác trong cùng một CamelContext. Nếu bạn muốn gọi trên các phiên bản CamelContext, bạn cần sử dụngVMthành phần. Việc sử dụng SEDA được minh họa ở đây -

from("direct:DistributeOrderDSL")
// send it to the seda queue that is async
   .to("seda:nextOrder")

Trong lộ trình này, chúng tôi chỉ định tuyến các đơn đặt hàng đến nextOrderhàng đợi không đồng bộ. Khách hàng đã đăng ký hàng đợi này sẽ nhận các tin nhắn từ hàng đợi này.

Hẹn giờ

Các Timerthành phần được sử dụng để gửi tin nhắn đều đặn và do đó có thể rất hữu ích trong khi thử nghiệm các ứng dụng Camel. Đoạn mã ở đây sẽ kích hoạt một thông báo thử nghiệm tới bảng điều khiển cứ sau hai giây -

from("timer://testTimer?period = 2000")
   .setBody()
   .simple("This is a test message ${header.timer}")
      .to("stream:out");

Hầu hết các dự án tích hợp sử dụng tin nhắn vì nó giúp tạo ra kiến ​​trúc ứng dụng được kết hợp lỏng lẻo. Nhắn tin có thể đồng bộ hoặc không đồng bộ. JMS hỗ trợ cả haipoint-to-pointpublish-subscribecác mô hình. Bạn sử dụng mộtQueue cho điểm đến điểm và Topiccho mô hình đăng ký xuất bản. Trên nền tảng Java, JMS - Java Messaging Service cung cấp giao diện cho máy chủ nhắn tin. Apache activeMQ là một trong những nhà cung cấp JMS mã nguồn mở. Camel không giao hàng với nhà cung cấp JMS; tuy nhiên, nó có thể được cấu hình để sử dụng activeMQ. Để sử dụng thành phần này, bạn cần bao gồm các lọ sau trong dự án của mình - activemq, camel-spring và camel-jms.

Đoạn mã sau đây cho thấy cách định cấu hình Camel cho activeMQ.

<bean id = "jms" class = "org.apache.camel.component.jms.JmsComponent">
   <property name = "connectionFactory">
      <bean class="org.apache.activemq.ActiveMQConnectionFactory">
         <property name = "orderQueue" value = "tcp://localhost:61000" />
      </bean>
   </property>
</bean>

Tại đây, ứng dụng Camel sẽ bắt đầu lắng nghe một hàng đợi có tên orderQueue. Bản thân hàng đợi được thiết lập trong máy chủ nhắn tin activeMQ chạy trên máy chủ cục bộ và liệt kê tới cổng 61000. Sau khi hoàn tất, ứng dụng của bạn có thể gửi hoặc nhận tin nhắn đến hàng đợi này từ bất kỳ điểm cuối nào được xác định trong ứng dụng của bạn.

Cuối cùng, đã đến lúc đặt mọi thứ lại với nhau trong một dự án để hiểu sâu hơn về cách các ứng dụng Camel được tạo ra.

Chúng tôi sẽ sử dụng Maven để xây dựng một dự án Camel. Mặc dù, chúng tôi ưu tiên sử dụng IntelliJ IDE để phát triển. Bạn có thể sử dụng bất kỳ IDE nào mà bạn chọn cho dự án này.

Tạo dự án mới

Tạo một cái mới Maven dự án và chỉ định những điều sau:

GroupId: Basket
ArtifactId: Basket

Chọn vị trí mặc định cho dự án của bạn hoặc nếu bạn muốn chỉ định thư mục mà bạn chọn.

Thêm phụ thuộc

Bạn cần thêm một số phụ thuộc để sử dụng Camel. Các phụ thuộc được thêm vàopom.xml. Vì vậy, hãy mở pom.xml và thêm hai phần phụ thuộc sau:

<dependencies>
   <dependency>
      <groupId>org.apache.camel</groupId>
      <artifactId>camel-core</artifactId>
      <version>2.20.0</version>
   </dependency>
   <dependency>
      <groupId>org.apache.camel</groupId>
      <artifactId>camel-stream</artifactId>
      <version>2.20.0</version>
   </dependency>
</dependencies>

Note- Chúng tôi cần các phụ thuộc tối thiểu cho ứng dụng của mình. Khi bạn sử dụng nhiều thành phần Camel hơn từ các thư viện của nó, bạn sẽ cần thêm các phần phụ thuộc tương ứng vào tệp pom.xml này.

Tạo Java DSL

Tiếp theo, bạn sẽ viết mã lọc và định tuyến của mình trong một Java DSL. Tạo một lớp Java mới được gọi làDistributeOrderDSL. Thêm mã sau vào nó -

public class DistributeOrderDSL {
   public static void main(String[] args) throws Exception {
      CamelContext context = new DefaultCamelContext();
      try {
         context.addRoutes(new RouteBuilder() {
            @Override
            public void configure() throws Exception {
               from("direct:DistributeOrderDSL")
                  .split(xpath("//order[@product='soaps']/items")).to("stream:out");
               
               // .to("file:src/main/resources/order/");
            }
         });
         context.start();
         ProducerTemplate orderProducerTemplate = context.createProducerTemplate();
         InputStream orderInputStream = new FileInputStream(ClassLoader.getSystemClassLoader()
            .getResource("order.xml").getFile());
         orderProducerTemplate.sendBody("direct:DistributeOrderDSL", orderInputStream);
      } finally {
         context.stop();
      }
   }
}

bên trong main phương pháp, trước tiên chúng tôi tạo CamelContext bằng cách khởi tạo một triển khai mặc định được cung cấp trong DefaultCamelContext lớp học.

CamelContext context = new DefaultCamelContext();

Tiếp theo, chúng tôi thêm một tuyến đường bằng cách tạo một RouteBuilder ví dụ -

context.addRoutes(new RouteBuilder() {

Chúng tôi ghi đè configure phương pháp để thêm một tuyến đường từ một URI trực tiếp DistributeOrderDSLvào bảng điều khiển hệ thống. Chúng tôi cung cấp một số bộ lọc bằng cách sử dụng truy vấn xpath.

public void configure() throws Exception {
   from("direct:DistributeOrderDSL")
      .split(xpath("//order[@product = 'soaps']/items")).to("stream:out");
   // .to("file:src/main/resources/order/");
}

Sau khi thêm tuyến đường, chúng tôi bắt đầu ngữ cảnh -

context.start();

Tiếp theo, chúng tôi thêm mã để tạo URI trực tiếp của chúng tôi - DistributeOrderDSL.

ProducerTemplate orderProducerTemplate = context.createProducerTemplate();
InputStream orderInputStream = new FileInputStream(ClassLoader.getSystemClassLoader()
   .getResource("order.xml").getFile());

Cuối cùng, chúng tôi bắt đầu xử lý -

orderProducerTemplate.sendBody("direct:DistributeOrderDSL", orderInputStream);

Bây giờ, khi mã Java DSL của bạn đã hoàn thành, điều duy nhất còn lại trước khi kiểm tra ứng dụng là thêm order.xmltập tin vào dự án của bạn. Bạn có thể sử dụng XML mẫu được hiển thị trong chương Giới thiệu cho mục đích này.

Kết quả kiểm tra

Khi bạn chạy ứng dụng, bạn sẽ thấy kết quả sau:

<items>
   <item>
      <Brand>Cinthol</Brand>
      <Type>Original</Type>
      <Quantity>4</Quantity>
      <Price>25</Price>
   </item>
   <item>
      <Brand>Cinthol</Brand>
      <Type>Lime</Type>
      <Quantity>6</Quantity>
      <Price>30</Price>
   </item>
</items>

Lưu ý rằng chỉ có đơn đặt hàng cho Xà phòng được liệt kê ở đây. Nếu bạn muốn lưu trữ nó vào một tệp cục bộ, chỉ cần nhận xétstream.out dòng và bỏ ghi chú dòng sau trong configure phương pháp -

// .to("file:src/main/resources/order/");

Trong phần tiếp theo, chúng ta sẽ học cách sử dụng Camel với Spring.

Bây giờ chúng ta sẽ tạo lại ứng dụng từ chương trước bằng Spring. Điều này sẽ cho chúng ta một ý tưởng về cách tạo định tuyến Camel trong XML chứ không phải DSL.

Tạo dự án mới

Tạo một cái mới Maven dự án và chỉ định những điều sau:

GroupId: BasketWithSpring
ArtifactId: BasketWithSpring

Chọn vị trí mặc định cho dự án của bạn hoặc nếu bạn muốn chỉ định thư mục mà bạn chọn.

Thêm phụ thuộc

Ngoài các phụ thuộc cốt lõi mà bạn đã sử dụng trong ứng dụng trước đó, bạn cần thêm một vài phụ thuộc nữa để sử dụng Spring. Các phụ thuộc được thêm vào trong pom.xml. Bây giờ, mở pom.xml và thêm các phụ thuộc sau:

<dependencies>
   ...
   <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>5.1.3.RELEASE</version>
   </dependency>
   
   <dependency>
      <groupId>org.apache.activemq</groupId>
      <artifactId>activemq-pool</artifactId>
      <version>5.15.2</version>
   </dependency>
   
   <dependency>
      <groupId>org.apache.activemq</groupId>
      <artifactId>activemq-pool</artifactId>
      <version>5.15.1</version>
   </dependency>
   
   <dependency>
      <groupId>org.apache.camel</groupId>
      <artifactId>camel-spring</artifactId>
      <version>2.15.1</version>
   </dependency>
</dependencies>

Tạo Java DSL cho mùa xuân

Bây giờ chúng ta hãy tạo một lớp Java mới có tên là DistributeOrderXML. Thêm mã sau vào nó -

public class DistributeOrderXML {
   public static void main(String[] args) throws Exception {
      ApplicationContext appContext = new ClassPathXmlApplicationContext(
         "SpringRouteContext.xml");
      CamelContext camelContext = SpringCamelContext.springCamelContext(appContext, false);
      try {
         camelContext.start();
         ProducerTemplate orderProducerTemplate = camelContext.createProducerTemplate();
         InputStream orderInputStream = new FileInputStream(ClassLoader.getSystemClassLoader()
            .getResource("order.xml").getFile());
         
         orderProducerTemplate.sendBody("direct:DistributeOrderXML", orderInputStream);
      } finally {
         camelContext.stop();
      }
   }
}

bên trong main , trước tiên chúng ta tạo một phiên bản của ApplicationContext, là giao diện trung tâm trong ứng dụng Spring. Trong hàm tạo của nó, chúng tôi chỉ định tên của tệp XML có chứa thông tin định tuyến và lọc của chúng tôi.

ApplicationContext appContext = new ClassPathXmlApplicationContext(
   "SpringRouteContext.xml");

Tiếp theo, chúng tôi tạo CamelContext chỉ định ở trên được tạo ApplicationContext trong tham số của nó.

CamelContext camelContext = SpringCamelContext.springCamelContext(appContext, false);

Tại thời điểm này, định tuyến và lọc của chúng tôi đã được thiết lập. Do đó, chúng tôi bắt đầuCamelContext sử dụng nó startphương pháp. Như trong trường hợp trước, chúng tôi xác định Điểm cuối để tải tệp order.xml và bắt đầu xử lý. Bây giờ, chúng ta hãy hiểu cách định tuyến trong XML.

Tạo bối cảnh ứng dụng

Thêm tệp XML mới vào dự án và gọi nó SpringRouteContext.xml. Cắt-n-dán các nội dung sau vào tệp này.

<?xml version = "1.0" encoding = "UTF-8"?>
<beans xmlns = "http://www.springframework.org/schema/beans"
   xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation = "
      http://www.springframework.org/schema/beans
      http://www.springframework.org/schema/beans/spring-beans.xsd
      http://camel.apache.org/schema/spring
      http://camel.apache.org/schema/spring/camel-spring.xsd ">
   <camelContext xmlns = "http://camel.apache.org/schema/spring">
      <route>
         <from uri = "direct:DistributeOrderXML"/>
         <log message = "Split by Distribute Order"/>
         <split>
            <xpath>//order[@product = 'Oil']/items</xpath>
            <to uri = "file:src/main/resources/order/"/>
            <to uri = "stream:out"/>
         </split>
      </route>
   </camelContext>
</beans>

Ở đây, chúng tôi xác định truy vấn xpath như sau, lưu ý rằng bây giờ chúng tôi chọn tất cả các đơn đặt hàng cho “dầu”.

<xpath>//order[@product = 'Oil']/items</xpath>

Các điểm cuối đầu ra là nhiều. Điểm cuối đầu tiên chỉ địnhorder và thư mục thứ hai chỉ định bảng điều khiển.

<to uri = "file:src/main/resources/order/"/>
<to uri = "stream:out"/>

Chạy ứng dụng.

Kết quả kiểm tra

Khi bạn chạy ứng dụng, bạn sẽ thấy kết quả sau trên màn hình.

<items>
   <item>
      <Brand>Cinthol</Brand>
      <Type>Original</Type>
      <Quantity>4</Quantity>
      <Price>25</Price>
   </item>
   <item>
      <Brand>Cinthol</Brand>
      <Type>Lime</Type>
      <Quantity>6</Quantity>
      <Price>30</Price>
   </item>
</items>

Kiểm tra orderthư mục trong đường dẫn do bạn chỉ định. Bạn sẽ tìm thấy một tệp mới được tạo có chứa mã XML ở trên.

Phần kết luận

Camel cung cấp một khuôn khổ sẵn sàng sử dụng để triển khai các EIP để dễ dàng thực hiện các dự án tích hợp của bạn. Nó hỗ trợ mã hóa bằng các ngôn ngữ dành riêng cho miền và sử dụng cả XML.