Apache Camel - คู่มือฉบับย่อ

ลองพิจารณาสถานการณ์ที่ร้านขายของชำออนไลน์ขนาดใหญ่ในเมืองของคุณเช่น Bigbasket ในอินเดียเชิญให้คุณออกแบบโซลูชันด้านไอทีสำหรับพวกเขา โซลูชันที่เสถียรและปรับขนาดได้จะช่วยให้พวกเขาเอาชนะปัญหาการบำรุงรักษาซอฟต์แวร์ที่เผชิญอยู่ในปัจจุบัน ร้านค้าออนไลน์แห่งนี้ดำเนินธุรกิจมาตลอดทศวรรษที่ผ่านมา ร้านค้ายอมรับคำสั่งซื้อทางออนไลน์สำหรับผลิตภัณฑ์ประเภทต่างๆจากลูกค้าและกระจายสินค้าไปยังซัพพลายเออร์ที่เกี่ยวข้อง ตัวอย่างเช่นสมมติว่าคุณสั่งสบู่น้ำมันและนม ทั้งสามรายการนี้จะถูกแจกจ่ายให้กับซัพพลายเออร์ทั้งสามราย จากนั้นซัพพลายเออร์ทั้งสามจะส่งเสบียงของตนไปยังจุดแจกจ่ายทั่วไปจากจุดที่ศูนย์จัดส่งจะดำเนินการตามคำสั่งซื้อทั้งหมด ตอนนี้ให้เราดูปัญหาที่พวกเขากำลังเผชิญอยู่ในปัจจุบัน

เมื่อร้านค้านี้เริ่มต้นธุรกิจได้รับคำสั่งซื้อในไฟล์ข้อความธรรมดาที่คั่นด้วยเครื่องหมายจุลภาค ในช่วงระยะเวลาหนึ่งร้านค้าได้เปลี่ยนไปใช้การจัดวางคำสั่งซื้อที่ขับเคลื่อนด้วยข้อความ ต่อมานักพัฒนาซอฟต์แวร์บางรายแนะนำการจัดวางคำสั่งตาม XML ในที่สุดร้านค้าก็ปรับเปลี่ยนอินเทอร์เฟซบริการบนเว็บ ตอนนี้ปัญหาที่แท้จริงมาถึงแล้ว ขณะนี้คำสั่งซื้อมาในรูปแบบที่แตกต่างกัน เห็นได้ชัดว่าทุกครั้งที่ บริษัท อัปเกรดรูปแบบการยอมรับคำสั่งซื้อ บริษัท ไม่ต้องการทำลายอินเทอร์เฟซที่ใช้งานก่อนหน้านี้เพื่อไม่ให้เกิดความสับสนในใจของลูกค้า

ในขณะเดียวกันในขณะที่ธุรกิจเติบโตขึ้นเรื่อย ๆ ร้านค้าก็เพิ่มซัพพลายเออร์รายใหม่เข้ามาเป็นระยะ ๆ ซัพพลายเออร์แต่ละรายมีโปรโตคอลของตนเองในการรับคำสั่งซื้อ อีกครั้งที่เราเผชิญกับปัญหาการบูรณาการ สถาปัตยกรรมแอปพลิเคชันของเราต้องปรับขนาดได้เพื่อรองรับซัพพลายเออร์รายใหม่ด้วยกลไกการจัดวางคำสั่งซื้อที่เป็นเอกลักษณ์

สถานการณ์ทั้งหมดแสดงในรูปต่อไปนี้ -

ตอนนี้ให้เราดูว่า Apache Camel สามารถช่วยเหลือคุณได้อย่างไรเพื่อมอบสถาปัตยกรรมโซลูชันที่สง่างามดูแลรักษาได้และปรับขนาดได้สำหรับสถานการณ์ที่อธิบายไว้

ก่อนที่เราจะดำเนินการแก้ปัญหาเราจำเป็นต้องตั้งสมมติฐานเล็กน้อย สำหรับการอภิปรายทั้งหมดในบทช่วยสอนนี้เราจะถือว่าคำสั่งซื้อออนไลน์อยู่ในรูปแบบ XML รูปแบบทั่วไปสำหรับไฟล์คำสั่งซื้อที่เราจะใช้ตลอดการสนทนาของเราแสดงไว้ที่นี่ -

<?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>

เราจะใช้เทมเพลต XML ด้านบนเพื่อแสดงตัวอย่างอูฐในบทช่วยสอนนี้

Camel เป็นกล่องดำที่รับข้อความจากปลายทางบางส่วนและส่งไปยังอีกเครื่องหนึ่ง ภายในกล่องดำข้อความอาจถูกประมวลผลหรือเพียงแค่เปลี่ยนเส้นทาง

แล้วทำไมต้องมีกรอบสำหรับสิ่งนี้? ในสถานการณ์จริงตามที่เห็นในกรณีศึกษาเบื้องต้นอาจมีผู้ส่งหลายรายและผู้รับหลายรายแต่ละรายปฏิบัติตามโปรโตคอลของตนเองเช่น ftp, http และ jms ระบบอาจต้องใช้กฎที่ซับซ้อนมากมายเช่นข้อความจากผู้ส่ง A ควรส่งไปยัง B & C เท่านั้นในสถานการณ์คุณอาจต้องแปลข้อความเป็นรูปแบบอื่นที่ผู้รับคาดหวัง การแปลนี้อาจอยู่ภายใต้เงื่อนไขบางประการตามเนื้อหาของข้อความ โดยพื้นฐานแล้วคุณอาจต้องแปลระหว่างโปรโตคอลส่วนประกอบกาวเข้าด้วยกันกำหนดกฎการกำหนดเส้นทางและจัดเตรียมการกรองตามเนื้อหาของข้อความ แสดงในรูปต่อไปนี้ -

เพื่อให้เป็นไปตามข้อกำหนดข้างต้นและออกแบบสถาปัตยกรรมซอฟต์แวร์ที่เหมาะสมสำหรับสถานการณ์เช่นนี้ Enterprise Integration Patterns ( EIP ) ได้รับการบันทึกโดย Gregor Hohpe และ Bobby Woolf ในปี 2003 Apache Camel จัดเตรียมรูปแบบเหล่านี้ให้ใช้งานและจุดประสงค์ของบทช่วยสอนนี้คือการสอน วิธีใช้ Camel ในสถานการณ์เช่นเดียวกับที่อธิบายไว้ในบทนำ

Apache Camel เป็นเฟรมเวิร์กโอเพ่นซอร์ส เป็นมิดเดิลแวร์ที่เน้นข้อความที่ให้เครื่องมือกำหนดเส้นทางและสื่อกลางตามกฎ คุณสามารถกำหนดกฎต่างๆเช่นหากเป็นคำสั่งซื้อ "นม" จะเปลี่ยนเส้นทางไปยังผู้ขายนมและหากเป็นคำสั่งซื้อ "น้ำมัน" จะเปลี่ยนเส้นทางไปยังผู้ขายน้ำมันเป็นต้น เมื่อใช้ Camel คุณจะสามารถใช้กฎเหล่านี้และกำหนดเส้นทางในโค้ด Java ที่คุ้นเคย หมายความว่าคุณสามารถใช้ Java IDE ที่คุณคุ้นเคยเพื่อกำหนดกฎเหล่านี้ในสภาพแวดล้อม type-safe เราไม่จำเป็นต้องใช้ไฟล์คอนฟิกูเรชัน XML ซึ่งโดยทั่วไปแล้วจะมีขนาดใหญ่ แม้ว่า Camel จะรองรับการกำหนดค่า XML ผ่าน Spring framework หากคุณต้องการใช้ XML ในการกำหนดค่ากฎ คุณสามารถใช้ไฟล์ Blueprint XML Configuration และแม้แต่ Scala DSL ได้หากคุณเป็นคนรัก Scala นอกจากนี้ยังหมายความว่าคุณสามารถใช้ Java, Scala IDE ที่คุณชื่นชอบหรือแม้แต่โปรแกรมแก้ไข XML แบบธรรมดาเพื่อกำหนดค่ากฎ

อินพุตของเอ็นจิ้นนี้อาจเป็นไฟล์ข้อความที่คั่นด้วยจุลภาค POJO (Plain Old Java Object) XML เป็นรูปแบบอื่น ๆ ที่ Camel รองรับ ในทำนองเดียวกันเอาต์พุตของเครื่องยนต์สามารถเปลี่ยนเส้นทางไปยังไฟล์ไปยังคิวข้อความหรือแม้แต่หน้าจอมอนิเตอร์ของคุณเพื่อให้คุณดูคำสั่งซื้อที่ส่งไปยังผู้ขายที่เกี่ยวข้อง สิ่งเหล่านี้เรียกว่า endpoints และ Camel รองรับรูปแบบMessage Endpoint EIP จุดสิ้นสุดของอูฐจะกล่าวถึงในตอนท้ายของบทจุดสิ้นสุด

โดยทั่วไปแล้ว Camel จะใช้กับApache ServiceMix , Apache ActiveMQและApache CXFเพื่อใช้สถาปัตยกรรมที่มุ่งเน้นการบริการ

เมื่อได้เห็นภาพรวมของ Apache Camel แล้วตอนนี้เรามาเจาะลึกถึงคุณสมบัติต่างๆเพื่อดูว่ามีอะไรบ้าง เรารู้อยู่แล้วว่า Apache Camel เป็นเฟรมเวิร์ก Java โอเพ่นซอร์สที่ให้การใช้งาน EIP ต่างๆเป็นหลัก Camel ช่วยให้การรวมระบบง่ายขึ้นโดยให้การเชื่อมต่อกับการขนส่งและ API ที่หลากหลาย ตัวอย่างเช่นคุณสามารถกำหนดเส้นทาง JMS เป็น JSON, JSON ไปยัง JMS, HTTP ไปยัง JMS, FTP ไปยัง JMS แม้กระทั่ง HTTP เป็น HTTP และการเชื่อมต่อกับ Microservices คุณต้องระบุจุดสิ้นสุดที่เหมาะสมที่ปลายทั้งสองด้าน อูฐสามารถขยายได้ดังนั้นในอนาคตสามารถเพิ่มจุดสิ้นสุดลงในเฟรมเวิร์กได้อย่างง่ายดาย

ในการต่อสาย EIP และการขนส่งเข้าด้วยกันคุณใช้ภาษาเฉพาะโดเมน (DSL) เช่น Java, Scala และ Groovy กฎการกำหนดเส้นทาง Java ทั่วไปอาจมีลักษณะดังนี้ -

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

กฎการกำหนดเส้นทางนี้โหลดไฟล์จากไฟล์ order ไดเร็กทอรีสร้างข้อความ JMS พร้อมเนื้อหาของไฟล์และส่งข้อความนั้นไปยังคิวที่เรียกว่า orderQueue.

นี่คือคุณสมบัติที่สำคัญที่สุดของ Camel ที่คุณจะพบว่ามีประโยชน์ในการพัฒนาแอพพลิเคชั่น Camel -

  • Camel รองรับรูปแบบข้อมูลที่เสียบได้และตัวแปลงประเภทสำหรับการแปลงข้อความดังกล่าวดังนั้นจึงสามารถเพิ่มรูปแบบและตัวแปลงใหม่ได้ในอนาคต ปัจจุบันรองรับรูปแบบและตัวแปลงยอดนิยมหลายรูปแบบ เพื่อตั้งชื่อไม่กี่ - CSV, EDI, JAXB, JSON, XmlBeans, XStream, Flatpack, Zip

  • Camel รองรับภาษาที่เสียบได้เพื่อเขียนเพรดิเคตใน DSL ภาษาที่รองรับบางภาษา ได้แก่ JavaScript, Groovy, Python, PHP, Ruby, SQL, XPath, XQuery

  • Camel รองรับรุ่น POJO เพื่อให้เสียบ Javabeans ตามจุดต่างๆ

  • Camel ช่วยลดการทดสอบระบบกระจายและอะซิงโครนัสขนาดใหญ่ดังกล่าวโดยใช้การส่งข้อความ

ตอนนี้ให้เราเข้าใจสถาปัตยกรรมของ Camel และดูว่าคุณสมบัติต่างๆถูกนำไปใช้อย่างไร

สถาปัตยกรรม Camel ประกอบด้วยส่วนประกอบสามส่วน ได้แก่ Integration Engine และ Router, Processors และ Components แสดงในรูปต่อไปนี้ -

แกนอูฐมีขนาดเล็กมากและมีส่วนประกอบที่จำเป็น 13 อย่าง ส่วนประกอบ 80+ ที่เหลืออยู่นอกแกนกลาง สิ่งนี้ช่วยในการรักษาการพึ่งพาในระดับต่ำว่าจะใช้งานที่ไหนและส่งเสริมส่วนขยายในอนาคต Components โมดูลมีไฟล์ Endpointเชื่อมต่อกับโลกภายนอก ปลายทางถูกระบุโดย URI เช่นfile:/order และ jms:orderQueue ที่คุณได้เห็นในบทสุดท้าย

Processorsโมดูลใช้สำหรับจัดการและสื่อกลางข้อความระหว่างปลายทาง EIP ที่ฉันกล่าวถึงก่อนหน้านี้ถูกนำไปใช้ในโมดูลนี้ ปัจจุบันรองรับรูปแบบมากกว่า 40 รูปแบบตามที่ระบุไว้ในEIP bookและหน่วยประมวลผลที่มีประโยชน์อื่น ๆ

Processors และ Endpoints ต่อสายเข้าด้วยกัน Integration Engine and Routerโมดูลที่ใช้ DSL ในขณะเดินสายเหล่านี้คุณสามารถใช้ตัวกรองเพื่อกรองข้อความตามเกณฑ์ที่ผู้ใช้กำหนด ดังที่ได้กล่าวไว้ก่อนหน้านี้คุณมีหลายทางเลือกในการเขียนกฎเหล่านี้ คุณอาจใช้ Java, Scala, Groovy หรือแม้แต่ XML สำหรับสิ่งนี้

ตอนนี้เรามาถึงองค์ประกอบที่สำคัญที่สุดของ Camel ซึ่งอาจถือได้ว่าเป็นแกนกลางนั่นคือ CamelContext.

CamelContext ให้การเข้าถึงบริการอื่น ๆ ทั้งหมดใน Camel ดังแสดงในรูปต่อไปนี้ -

ให้เราดูบริการต่างๆ Registryโมดูลโดยค่าเริ่มต้นคือรีจิสตรี JNDI ซึ่งเก็บชื่อ Javabeans ต่างๆที่แอปพลิเคชันของคุณใช้ ถ้าคุณใช้ Camel กับ Spring นี่จะเป็น SpringApplicationContext. หากคุณใช้ Camel ในคอนเทนเนอร์ OSGI สิ่งนี้จะเป็นOSGI registry. Type convertersตามชื่อที่แนะนำมีตัวแปลงประเภทต่างๆที่โหลดซึ่งจะแปลงอินพุตของคุณจากรูปแบบหนึ่งไปเป็นอีกรูปแบบหนึ่ง คุณสามารถใช้ตัวแปลงประเภทที่มีอยู่แล้วภายในหรือระบุกลไกการแปลงของคุณเอง Componentsโมดูลประกอบด้วยส่วนประกอบที่แอปพลิเคชันของคุณใช้ ส่วนประกอบถูกโหลดโดยการค้นหาอัตโนมัติในไฟล์classpathที่คุณระบุ ในกรณีของคอนเทนเนอร์ OSGI สิ่งเหล่านี้จะถูกโหลดทุกครั้งที่เปิดใช้งานบันเดิลใหม่ เราได้หารือเกี่ยวกับไฟล์Endpoints และ Routesในบทก่อนหน้า Data formats โมดูลมีรูปแบบข้อมูลที่โหลดและสุดท้ายคือ Languages โมดูลแสดงถึงภาษาที่โหลด

ข้อมูลโค้ดที่นี่จะทำให้คุณเห็นว่าไฟล์ CamelContext ถูกสร้างขึ้นในแอปพลิเคชัน Camel -

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

DefaultCamelContext คลาสให้การนำไปใช้อย่างเป็นรูปธรรม CamelContext. ในaddRoutes เราสร้างอินสแตนซ์ที่ไม่ระบุตัวตนของ RouteBuilder. คุณสามารถสร้างหลาย ๆRouteBuilderอินสแตนซ์เพื่อกำหนดการกำหนดเส้นทางมากกว่าหนึ่งรายการ แต่ละเส้นทางในบริบทเดียวกันต้องมี ID ที่ไม่ซ้ำกัน สามารถเพิ่มเส้นทางได้แบบไดนามิกที่รันไทม์ เส้นทางที่มี ID เหมือนกับที่กำหนดไว้ก่อนหน้านี้จะแทนที่เส้นทางเก่า

สิ่งที่อยู่ภายในไฟล์ RouteBuilder อินสแตนซ์จะอธิบายต่อไป

เส้นทาง

เราเตอร์กำหนดกฎสำหรับการย้ายข้อความ from ถึงก toสถานที่. คุณใช้RouteBuilderเพื่อกำหนดเส้นทางใน Java DSL คุณสร้างเส้นทางโดยการขยายในตัวRouteBuilderชั้นเรียน เส้นทางเริ่มต้นด้วยfromจุดสิ้นสุดและสิ้นสุดที่จุดสิ้นสุดหนึ่งจุดหรือมากกว่า ในระหว่างทั้งสองคุณใช้ตรรกะการประมวลผล คุณสามารถกำหนดเส้นทางจำนวนเท่าใดก็ได้ภายในหนึ่งเดียวconfigure วิธี.

นี่คือตัวอย่างทั่วไปของการสร้างเส้นทาง -

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

เราลบล้างวิธีกำหนดค่าของ RouteBuilderคลาสและใช้กลไกการกำหนดเส้นทางและการกรองของเราในนั้น ในกรณีปัจจุบันเราเปลี่ยนเส้นทางอินพุตที่ได้รับจากปลายทางDistributeOrderDSL ไปยังคอนโซลซึ่งระบุโดย Endpoint stream:out.

ตัวเลือกภาษา

คุณสามารถสร้างเส้นทางในภาษาต่างๆ นี่คือตัวอย่างบางส่วนของการกำหนดเส้นทางเดียวกันในสามภาษาที่แตกต่างกัน -

Java DSL

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

สปริง DSL

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

Scala DSL

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

ฟิลเตอร์

คุณใช้ตัวกรองเพื่อเลือกส่วนหนึ่งของเนื้อหาอินพุต การตั้งค่าตัวกรองที่คุณใช้ใด ๆ โดยพลการสรุปการดำเนินงาน จากนั้นข้อมูลที่กรองแล้วจะถูกส่งไปยังปลายทางปลายทางที่คุณต้องการ ในตัวอย่างนี้เรากรองคำสั่งซื้อทั้งหมดสำหรับสบู่เพื่อให้สามารถส่งรวมกันไปยังซัพพลายเออร์สบู่ได้

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

ในตัวอย่างเราได้ใช้ xpathเพรดิเคตสำหรับการกรอง หากคุณต้องการใช้คลาส Java ในการกรองให้ใช้รหัสต่อไปนี้ -

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

Order เป็นคลาส Java ที่คุณกำหนดเองพร้อมกลไกการกรองของคุณเอง

คุณสามารถรวมเพรดิเคตหลายตัวในการกำหนดเส้นทางเดียวได้ที่นี่ -

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

ตอนนี้คำสั่งซื้อ "น้ำมัน" ทั้งหมดจะไปที่ผู้ขายน้ำมันคำสั่งซื้อ "นม" จะไปที่ผู้ขายนมและส่วนที่เหลือจะส่งไปที่สระทั่วไป

โปรเซสเซอร์ที่กำหนดเอง

คุณยังสามารถใช้การประมวลผลแบบกำหนดเอง ตัวอย่างด้านล่างสร้างโปรเซสเซอร์แบบกำหนดเองที่เรียกว่าmyCustomProcessor และใช้ในเครื่องมือสร้างเส้นทาง

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);
   }
};

คุณสามารถใช้โปรเซสเซอร์ที่กำหนดเองพร้อมกับตัวเลือกและการกรองเพื่อให้สามารถควบคุมสื่อกลางและการกำหนดเส้นทางของคุณได้ดีขึ้น -

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

ใช้ XML

เส้นทางอาจถูกกำหนดใน XML ที่มีขนาดใหญ่ขึ้นหากคุณต้องการ ตัวอย่าง XML ต่อไปนี้แสดงวิธีสร้างเส้นทางพร้อมกับการกรองผ่าน 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>

เมื่อได้เห็นวิธีสร้างเส้นทางแล้วตอนนี้เราจะเห็นเทคนิคต่างๆในการสร้างจุดสิ้นสุด

เราได้เรียนรู้ว่าจุดสิ้นสุดมีลักษณะอย่างไรในรหัสการผสานรวมของเรา นิพจน์ที่เราใช้จนถึงตอนนี้เช่นfile:/order, jms:orderQueue, direct:distributeOrderDSLคือจุดสิ้นสุด อย่างที่คุณเห็นพวกเขาเป็นไปตามรูปแบบข้อกำหนด URI ในขณะที่ประเมิน URI นี้ไฟล์CamelContext สร้างไฟล์ Endpointตัวอย่าง; คุณไม่จำเป็นต้องกังวลเกี่ยวกับการสร้างอินสแตนซ์Endpoint การนำไปใช้ใน DSL ของคุณ

จากตัวอย่างก่อนหน้านี้คุณระบุจุดสิ้นสุดใน Java DSL ดังที่นี่ -

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

และในฤดูใบไม้ผลิที่นี่ -

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

ในทั้งสองกรณีจุดสิ้นสุดคือสตริงคงที่ ในบางกรณีคุณอาจต้องการสร้างสตริงนี้ในรันไทม์ คุณสามารถทำได้โดยใช้ JavaStringวิธีการจัดรูปแบบ Camel มีแนวทางที่ง่ายกว่าในการสร้างสตริง URI เหล่านี้ขณะรันไทม์ เพื่อจุดประสงค์นี้ Camel จัดให้fromF และ toFวิธีการที่ยอมรับอาร์กิวเมนต์ด้วยพารามิเตอร์ที่ผู้ใช้ระบุ คำสั่งต่อไปนี้แสดงให้เห็นถึงการใช้toF วิธีการ -

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

เนื่องจากวิธีการเหล่านี้จำเป็นต้องใช้ Java ในตัว String วิธีการฟอร์แมตเตอร์เป็นแบบ obviated

Camel ใช้ภาษาที่เรียบง่ายตามค่าเริ่มต้นเพื่อคำนวณนิพจน์ปลายทาง Simple ภาษาได้รับการออกแบบมาเพื่อประเมินเป็นหลัก Expressions และ Predicatesโดยไม่ต้องกังวลมากเกี่ยวกับความซับซ้อนของ XPath. สำหรับการประเมินเพรดิเคตคุณสามารถรวมภาษาอื่นเช่นxpath ด้วยค่าเริ่มต้น Simpleภาษา. ซึ่งทำได้โดยใช้เครื่องหมายบวกเพื่อแยกภาษาอื่น ข้อมูลโค้ดที่นี่แสดงวิธีการเชื่อมต่อxpath สตริงไปยังนิพจน์ที่เขียนด้วย Simple.

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

ใน Springคุณสามารถบรรลุได้เช่นเดียวกับที่นี่ -

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

คุณสามารถเชื่อมต่อภาษาต่างๆได้มากเท่าที่คุณต้องการโดยแต่ละภาษาคั่นด้วยเครื่องหมายบวกจากภาษาก่อนหน้า รายการภาษาที่สนับสนุนสามารถพบได้ที่นี่

อูฐมีส่วนประกอบที่สร้างไว้ล่วงหน้าหลายอย่าง

ในบทนี้เราจะพูดถึงส่วนประกอบที่สำคัญบางประการจากไฟล์ camel-core โมดูล.

ถั่ว

Beanส่วนประกอบผูกถั่วกับการแลกเปลี่ยนข้อความอูฐ URI ในการสร้าง Endpoint ระบุเป็นbean:beanID, ที่ไหน beanID คือชื่อของถั่วตามที่ระบุในไฟล์ 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");
   }
});

สังเกตว่าปลายทางถูกระบุโดยใช้ไฟล์ bean:มาตรการ. คุณสามารถเลือกที่จะระบุวิธีการ bean ที่จะเรียก; ในกรณีนี้วิธีการที่เรียกว่าplaceOrderจะถูกเรียกใช้ขณะประเมินนิพจน์ปลายทาง MilkOrder เป็นชื่อ JNDI ของไฟล์ MilkOrderProcessorJavabean ตามที่ลงทะเบียนในสองบรรทัดแรกของข้อมูลโค้ด ความหมายของMilkOrderProcessor ตัวเองถูกละไว้ที่นี่เพื่อความกะทัดรัด

โดยตรง

คุณต้องสังเกตเห็นการใช้ Directในตัวอย่างก่อนหน้านี้ของเรา ในการส่งคำสั่งซื้อไปยังผู้จำหน่ายน้ำมันเราใช้direct:oilในข้อกำหนดปลายทาง การใช้Directคอมโพเนนต์ช่วยให้คุณสามารถเรียกใช้ปลายทางได้พร้อมกัน ตัวอย่างโค้ดสองรายการต่อไปนี้จากตัวอย่างก่อนหน้านี้แสดงให้เห็นถึงการใช้งานDirect -

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

และ,

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

ไฟล์

Fileคอมโพเนนต์ให้การเข้าถึงระบบไฟล์บนเครื่องของคุณ เมื่อใช้ส่วนประกอบนี้คุณจะสามารถบันทึกข้อความจากส่วนประกอบอื่น ๆ ลงในดิสก์ภายในเครื่องได้ นอกจากนี้ยังอนุญาตให้คอมโพเนนต์ Camel อื่น ๆ ประมวลผลไฟล์ภายในเครื่อง คุณสามารถใช้อย่างใดอย่างหนึ่งfile:directoryName[?options] หรือ file://directoryName[?options]เป็นรูปแบบ URI ขณะใช้คอมโพเนนต์ไฟล์ ก่อนหน้านี้คุณได้เห็นการใช้ส่วนประกอบนี้ -

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

โปรดทราบว่าไฟล์ Fileคอมโพเนนต์โดยค่าเริ่มต้นใช้ชื่อไดเร็กทอรี ดังนั้นเนื้อหาของไดเร็กทอรีคำสั่งจะถูกนำมาเป็นเนื้อหาอินพุต เพื่อระบุไฟล์เฉพาะในไฟล์order ไดเรกทอรีคุณจะใช้คำสั่งต่อไปนี้ -

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

บันทึก

Logคอมโพเนนต์ช่วยให้คุณสามารถบันทึกข้อความไปยังกลไกการบันทึกพื้นฐาน Camel ใช้ Simple Logging Facade สำหรับ Java (SLF4J) เป็นนามธรรมสำหรับเฟรมเวิร์กการบันทึกต่างๆ คุณอาจใช้java.util.logging, logback, log4jสำหรับการบันทึก ข้อมูลโค้ดนี้แสดงให้เห็นถึงการใช้ไฟล์Log ส่วนประกอบ -

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

SEDA

SEDA คอมโพเนนต์ช่วยให้คุณสามารถโทรหาจุดสิ้นสุดอื่นแบบอะซิงโครนัสได้ CamelContext. หากคุณต้องการโทรข้ามอินสแตนซ์ CamelContext คุณต้องใช้VMส่วนประกอบ. การใช้ SEDA แสดงไว้ที่นี่ -

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

ในเส้นทางนี้เราจะกำหนดเส้นทางคำสั่งซื้อไปที่ nextOrderคิวแบบอะซิงโครนัส ลูกค้าที่สมัครรับคิวนี้จะรับข้อความจากคิวนี้

จับเวลา

Timerคอมโพเนนต์ใช้สำหรับการส่งข้อความในช่วงเวลาปกติดังนั้นจึงมีประโยชน์มากในขณะทดสอบแอปพลิเคชัน Camel ข้อมูลโค้ดที่นี่จะส่งข้อความทดสอบไปยังคอนโซลทุกๆสองวินาที -

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

โครงการผสานรวมส่วนใหญ่ใช้การส่งข้อความเนื่องจากช่วยในการสร้างสถาปัตยกรรมแอปพลิเคชันที่ทำงานร่วมกันอย่างหลวม ๆ ข้อความอาจเป็นแบบซิงโครนัสหรืออะซิงโครนัส JMS รองรับทั้งpoint-to-point และ publish-subscribeโมเดล คุณใช้ไฟล์Queue สำหรับจุดต่อจุดและ Topicสำหรับรูปแบบการสมัครสมาชิกเผยแพร่ บนแพลตฟอร์ม Java JMS - Java Messaging Service จัดเตรียมอินเตอร์เฟสไปยังเซิร์ฟเวอร์รับส่งข้อความ Apache activeMQ เป็นหนึ่งในผู้ให้บริการ JMS แบบโอเพนซอร์ส Camel ไม่ได้จัดส่งพร้อมกับผู้ให้บริการ JMS อย่างไรก็ตามสามารถกำหนดค่าให้ใช้ activeMQ ได้ ในการใช้ส่วนประกอบนี้คุณต้องรวมไหต่อไปนี้ไว้ในโครงการของคุณ - activemq, อูฐสปริงและอูฐ-jms

ข้อมูลโค้ดต่อไปนี้แสดงวิธีกำหนดค่า Camel สำหรับ 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>

ที่นี่แอปพลิเคชั่น Camel จะเริ่มฟังคิวที่เรียก orderQueue. คิวเองถูกตั้งค่าในเซิร์ฟเวอร์การส่งข้อความ activeMQ ที่รันบนโลคัลโฮสต์และแสดงรายการไปยังพอร์ต 61000 เมื่อดำเนินการเสร็จสิ้นแอปพลิเคชันของคุณสามารถส่งหรือรับข้อความไปยังคิวนี้จากปลายทางใดก็ได้ที่กำหนดไว้ในแอปพลิเคชันของคุณ

ในที่สุดก็ถึงเวลารวบรวมทุกอย่างเข้าด้วยกันในโปรเจ็กต์เพื่อทำความเข้าใจให้ลึกซึ้งยิ่งขึ้นเกี่ยวกับการสร้างแอปพลิเคชัน Camel

เราจะใช้ Maven เพื่อสร้างโครงการ Camel แม้ว่าเราควรใช้ IntelliJ IDE ในการพัฒนามากกว่า คุณสามารถใช้ IDE ใดก็ได้ที่คุณเลือกสำหรับโครงการนี้

การสร้างโครงการใหม่

สร้างไฟล์ Maven โครงการและระบุสิ่งต่อไปนี้ -

GroupId: Basket
ArtifactId: Basket

เลือกตำแหน่งเริ่มต้นสำหรับโครงการของคุณหรือหากคุณต้องการระบุไดเร็กทอรีที่คุณต้องการ

การเพิ่มการอ้างอิง

คุณต้องเพิ่มการอ้างอิงเล็กน้อยเพื่อใช้ Camel การอ้างอิงจะถูกเพิ่มเข้ามาpom.xml. ดังนั้นเปิด pom.xml และเพิ่มการอ้างอิงสองรายการต่อไปนี้ -

<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- เราต้องการการอ้างอิงขั้นต่ำสำหรับแอปพลิเคชันของเรา เมื่อคุณใช้ส่วนประกอบ Camel จากไลบรารีมากขึ้นคุณจะต้องเพิ่มการอ้างอิงที่เกี่ยวข้องในไฟล์ pom.xml นี้

การสร้าง Java DSL

จากนั้นคุณจะเขียนโค้ดการกรองและการกำหนดเส้นทางของคุณใน Java DSL สร้างคลาส Java ใหม่ที่เรียกว่าDistributeOrderDSL. เพิ่มรหัสต่อไปนี้ -

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();
      }
   }
}

ใน main วิธีแรกเราสร้าง CamelContext โดยการสร้างอินสแตนซ์การใช้งานเริ่มต้นที่มีให้ใน DefaultCamelContext ชั้นเรียน

CamelContext context = new DefaultCamelContext();

ต่อไปเราจะเพิ่มเส้นทางโดยการสร้างแบบไม่ระบุตัวตน RouteBuilder อินสแตนซ์ -

context.addRoutes(new RouteBuilder() {

เราลบล้างไฟล์ configure วิธีการเพิ่มเส้นทางจาก URI โดยตรง DistributeOrderDSLไปยังคอนโซลระบบ เราจัดเตรียมการกรองบางอย่างโดยใช้แบบสอบถาม xpath

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();

ต่อไปเราจะเพิ่มรหัสสำหรับสร้าง URI โดยตรงของเรา - DistributeOrderDSL.

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

ในที่สุดเราก็เริ่มการประมวลผล -

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

เมื่อโค้ด Java DSL ของคุณเสร็จสมบูรณ์สิ่งเดียวที่ยังคงอยู่ก่อนที่จะทดสอบแอปพลิเคชันคือการเพิ่มไฟล์ order.xmlไฟล์ไปยังโครงการของคุณ คุณสามารถใช้ XML ตัวอย่างที่แสดงในบทแนะนำเพื่อจุดประสงค์นี้

ผลการทดสอบ

เมื่อคุณเรียกใช้แอปพลิเคชันคุณจะเห็นผลลัพธ์ต่อไปนี้ -

<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>

โปรดทราบว่าเฉพาะคำสั่งซื้อสบู่เท่านั้นที่ระบุไว้ที่นี่ หากคุณต้องการจัดเก็บสิ่งนี้ลงในไฟล์ในเครื่องเพียงแค่แสดงความคิดเห็นที่ไฟล์stream.out บรรทัดและยกเลิกการใส่ข้อคิดเห็นบรรทัดต่อไปนี้ในไฟล์ configure วิธีการ -

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

ในส่วนต่อไปเราจะเรียนรู้วิธีใช้ Camel กับ Spring

ตอนนี้เราจะสร้างแอปพลิเคชันใหม่จากบทก่อนหน้าโดยใช้ Spring สิ่งนี้จะทำให้เรามีแนวคิดเกี่ยวกับวิธีสร้างการกำหนดเส้นทาง Camel ใน XML แทนที่จะเป็น DSL

การสร้างโครงการใหม่

สร้างไฟล์ Maven โครงการและระบุสิ่งต่อไปนี้ -

GroupId: BasketWithSpring
ArtifactId: BasketWithSpring

เลือกตำแหน่งเริ่มต้นสำหรับโครงการของคุณหรือหากคุณต้องการระบุไดเร็กทอรีที่คุณต้องการ

การเพิ่มการอ้างอิง

นอกเหนือจากการอ้างอิงหลักที่คุณใช้ในแอปพลิเคชันก่อนหน้านี้คุณยังต้องเพิ่มการอ้างอิงอีกเล็กน้อยเพื่อใช้ Spring การอ้างอิงถูกเพิ่มใน pom.xml ตอนนี้เปิด pom.xml และเพิ่มการอ้างอิงต่อไปนี้ -

<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>

การสร้าง Java DSL สำหรับ Spring

ตอนนี้ให้เราสร้างคลาส Java ใหม่ที่เรียกว่า DistributeOrderXML. เพิ่มรหัสต่อไปนี้ -

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();
      }
   }
}

ใน main วิธีแรกเราสร้างอินสแตนซ์ของ ApplicationContextซึ่งเป็นอินเทอร์เฟซส่วนกลางภายในแอปพลิเคชัน Spring ในตัวสร้างเราระบุชื่อของไฟล์ XML ที่มีข้อมูลการกำหนดเส้นทางและการกรองของเรา

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

ต่อไปเราจะสร้าง CamelContext ระบุสิ่งที่สร้างไว้ข้างต้น ApplicationContext ในพารามิเตอร์

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

ณ จุดนี้การกำหนดเส้นทางและการกรองของเราได้รับการตั้งค่าแล้ว ดังนั้นเราจึงเริ่มต้นCamelContext โดยใช้ startวิธี. เช่นในกรณีก่อนหน้านี้เรากำหนด Endpoint สำหรับการโหลดไฟล์ order.xml และเริ่มการประมวลผล ตอนนี้ให้เราเข้าใจว่าการกำหนดเส้นทางถูกกำหนดใน XML อย่างไร

การสร้างบริบทแอปพลิเคชัน

เพิ่มไฟล์ XML ใหม่ในโปรเจ็กต์และเรียกมัน SpringRouteContext.xml. ตัดและวางเนื้อหาต่อไปนี้ลงในไฟล์นี้

<?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>

ในที่นี้เรากำหนดคิวรี xpath ดังต่อไปนี้โปรดทราบว่าตอนนี้เราเลือกคำสั่งซื้อ "น้ำมัน" ทั้งหมด

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

จุดสิ้นสุดของเอาต์พุตมีหลายค่า จุดสิ้นสุดแรกระบุไฟล์order โฟลเดอร์และโฟลเดอร์ที่สองระบุคอนโซล

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

เรียกใช้แอปพลิเคชัน

ผลการทดสอบ

เมื่อคุณเรียกใช้แอปพลิเคชันคุณจะเห็นผลลัพธ์ต่อไปนี้บนหน้าจอ

<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โฟลเดอร์ในเส้นทางที่คุณระบุ คุณจะพบไฟล์ที่สร้างขึ้นใหม่ซึ่งมีโค้ด XML ด้านบน

สรุป

Camel จัดเตรียมเฟรมเวิร์กที่พร้อมใช้งานซึ่งใช้ EIP เพื่อทำให้โครงการรวมของคุณง่ายขึ้น รองรับการเข้ารหัสในภาษาเฉพาะโดเมนและการใช้ XML