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 в этом руководстве.
Apache Camel — Обзор
Верблюд — это черный ящик, который получает сообщения от одной конечной точки и отправляет ее другой. Внутри черного ящика сообщения могут быть обработаны или просто перенаправлены.
Итак, почему есть рамки для этого? В практических ситуациях, как показано во вводном примере, может быть много отправителей и много получателей, каждый из которых следует своему собственному протоколу, такому как ftp, http и jms. Системе может потребоваться множество сложных правил, например, сообщение от отправителя A должно быть доставлено только в B & C. В ситуациях вам может потребоваться перевести сообщение в другой формат, который ожидает получатель. Этот перевод может быть предметом определенных условий, основанных на содержании сообщения. По сути, вам может потребоваться выполнять трансляцию между протоколами, склеивать компоненты, определять правила маршрутизации и обеспечивать фильтрацию на основе содержимого сообщения. Это показано на следующем рисунке —
Чтобы удовлетворить вышеупомянутые требования и спроектировать правильную архитектуру программного обеспечения для многих таких ситуаций, Грегор Хоуп и Бобби Вульф в 2003 году задокументировали шаблоны интеграции предприятия ( EIP ). Apache Camel обеспечивает реализацию этих шаблонов, и цель этого учебного пособия — научить Вы знаете, как использовать Camel в ситуациях, подобных описанной во введении.
Apache Camel — это фреймворк с открытым исходным кодом. Это промежуточное программное обеспечение, ориентированное на сообщения, которое предоставляет механизм маршрутизации и передачи на основе правил. Вы можете определить правила, например, если это «молочный» заказ, перенаправить его поставщику молока, а если это «нефтяной» заказ, перенаправить его поставщику масла и т. Д. Используя Camel, вы сможете реализовать эти правила и выполнить маршрутизацию в привычном Java-коде. Это означает, что вы можете использовать знакомую вам Java IDE для определения этих правил в безопасной среде. Нам не нужно использовать файлы конфигурации XML, которые обычно бывают громоздкими. Однако Camel поддерживает настройку XML через Spring Framework, если вы предпочитаете использовать XML для настройки правил. Вы можете даже использовать конфигурационные файлы Blueprint XML и даже Scala DSL, если вы любитель Scala. Это также означает, что вы можете использовать вашу любимую Java, Scala IDE или даже простой редактор XML для настройки правил.
Входными данными для этого механизма могут быть текстовый файл с разделителями-запятыми, POJO (простой старый Java-объект), XML — любой из нескольких других форматов, поддерживаемых Camel. Точно так же выходные данные механизма могут быть перенаправлены в файл, в очередь сообщений или даже на экран вашего монитора, чтобы вы могли просматривать заказы, отправленные соответствующим поставщикам. Они называются конечными точками, и Camel поддерживает шаблон EIP сообщения конечной точки. Конечные точки Camel обсуждаются позже в главе «Конечные точки».
Camel обычно используется с Apache ServiceMix , Apache ActiveMQ и Apache CXF для реализации сервис-ориентированных архитектур.
Apache Camel — Особенности
Посмотрев обзор Apache Camel, давайте теперь углубимся в его возможности, чтобы увидеть, что он предлагает. Мы уже знаем, что Apache Camel — это инфраструктура Java с открытым исходным кодом, которая, по сути, обеспечивает реализацию различных EIP. Camel упрощает интеграцию, предоставляя возможность подключения к очень большому количеству транспортов и API. Например, вы можете легко направить JMS в JSON, JSON в JMS, HTTP в JMS, FTP в JMS, даже HTTP в HTTP и подключение к микросервисам. Вам просто нужно предоставить соответствующие конечные точки на обоих концах. Верблюд является расширяемым и, таким образом, в будущем можно будет легко добавить дополнительные конечные точки в платформу.
Чтобы соединить EIP и транспорты вместе, вы используете доменные языки (DSL), такие как Java, Scala и Groovy. Типичное правило маршрутизации Java может выглядеть так:
from ("file:/order").to("jms:orderQueue");
Это правило маршрутизации загружает файлы из каталога заказов , создает сообщение 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 поддерживает подключаемые форматы данных и преобразователи типов для таких преобразований сообщений, поэтому в будущем могут быть добавлены новые форматы и преобразователи. В настоящее время он поддерживает несколько популярных форматов и конвертеров; назвать несколько — CSV, EDI, JAXB, JSON, XmlBeans, XStream, Flatpack, Zip.
Camel поддерживает подключаемые языки для написания предикатов в DSL. Некоторые из поддерживаемых языков включают JavaScript, Groovy, Python, PHP, Ruby, SQL, XPath, XQuery.
Camel поддерживает модель POJO, так что вы можете подключать Javabeans в разных точках.
Camel облегчает тестирование таких больших распределенных и асинхронных систем с помощью обмена сообщениями.
Давайте теперь разберемся с архитектурой Camel и посмотрим, как реализованы различные функции.
Apache Camel — Архитектура
Архитектура Camel состоит из трех компонентов — модуля интеграции и маршрутизатора, процессоров и компонентов. Это показано на следующем рисунке —
Само ядро Camel очень маленькое и содержит 13 основных компонентов. Остальные 80+ компонентов находятся за пределами ядра. Это помогает поддерживать низкую зависимость от места его развертывания и способствует расширению в будущем. Модуль Компоненты обеспечивает интерфейс конечной точки с внешним миром. Конечные точки задаются URI, такими как file: / order и jms: orderQueue, которые вы видели в предыдущей главе.
Модуль Processors используется для манипулирования и передачи сообщений между конечными точками. EIP, которые я упоминал ранее, реализованы в этом модуле. В настоящее время он поддерживает более 40 шаблонов, как описано в книге EIP и других полезных процессорах.
Процессоры и конечные точки соединены вместе в Integration Engine и модуле маршрутизатора с использованием DSL. При их подключении вы можете использовать фильтры для фильтрации сообщений на основе определенных пользователем критериев. Как упоминалось ранее, у вас есть несколько вариантов написания этих правил. Для этого вы можете использовать Java, Scala, Groovy или даже XML.
Теперь мы подошли к самому важному компоненту Camel, который можно рассматривать как ядро, — CamelContext .
Apache Camel — CamelContext
CamelContext обеспечивает доступ ко всем другим сервисам в Camel, как показано на следующем рисунке —
Давайте посмотрим на различные услуги. Модуль Реестра по умолчанию является реестром JNDI, который содержит названия различных Javabeans, которые использует ваше приложение. Если вы используете Camel с Spring, это будет Spring ApplicationContext . Если вы используете Camel в контейнере OSGI, это будет реестр OSGI . Преобразователи типов, как следует из названия, содержат различные загруженные преобразователи типов, которые преобразуют ваш ввод из одного формата в другой. Вы можете использовать встроенные преобразователи типов или предоставить свой собственный механизм преобразования. Модуль Компоненты содержит компоненты, используемые вашим приложением. Компоненты загружаются путем автоматического обнаружения в указанном вами пути к классам . В случае контейнера OSGI они загружаются всякий раз, когда активируется новый пакет. Мы уже обсуждали конечные точки и маршруты в предыдущих главах. Модуль « Форматы данных » содержит загруженные форматы данных, и, наконец, модуль « Языки » представляет загруженные языки.
Фрагмент кода здесь даст вам представление о том, как CamelContext создается в приложении Camel —
CamelContext context = new DefaultCamelContext(); try { context.addRoutes(new RouteBuilder() { // Configure filters and routes } } );
Класс DefaultCamelContext обеспечивает конкретную реализацию CamelContext . В методе addRoutes мы создаем анонимный экземпляр RouteBuilder . Вы можете создать несколько экземпляров RouteBuilder, чтобы определить более одной маршрутизации. Каждый маршрут в одном и том же контексте должен иметь уникальный идентификатор. Маршруты могут быть добавлены динамически во время выполнения. Маршрут с идентификатором, идентичным ранее определенному, заменит старый маршрут.
Что происходит внутри экземпляра RouteBuilder, описано далее.
Маршруты
Маршрутизатор определяет правило перемещения сообщения из одного места в другое. Вы используете RouteBuilder для определения маршрута в Java DSL. Вы создаете маршрут, расширяя встроенный класс RouteBuilder . Маршрут начинается с конечной точки и заканчивается в одной или нескольких конечных точках. Между ними вы реализуете логику обработки. Вы можете настроить любое количество маршрутов в одном методе настройки .
Вот типичный пример того, как создается маршрут —
context.addRoutes(new RouteBuilder() { @Override public void configure() throws Exception { from("direct:DistributeOrderDSL") .to("stream:out"); } }
Мы переопределяем метод configure класса RouteBuilder и реализуем в нем наш механизм маршрутизации и фильтрации. В текущем случае мы перенаправляем ввод, полученный от Endpoint DistributeOrderDSL, на консоль, которая указана потоком Endpoint : out .
Выбор языка
Вы можете создавать маршруты на разных языках. Вот несколько примеров того, как один и тот же маршрут определяется на трех разных языках:
Java DSL
from ("file:/order").to("jms:orderQueue");
Spring DSL
<route> <from uri = "file:/order"/> <to uri = "jms:orderQueue"/> </route>
Scala DSL
from "file:/order" -> "jms:orderQueue"
фильтры
Вы используете фильтр, чтобы выбрать часть входного контента. Чтобы настроить фильтр, вы используете любую произвольную реализацию Predicate . Затем отфильтрованный входной сигнал отправляется в конечную точку по вашему желанию. В этом примере мы отфильтровываем все заказы на мыло, чтобы их можно было вместе отправить поставщику мыла.
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>
Посмотрев, как строятся маршруты, теперь мы увидим различные методы создания конечных точек.
Apache Camel — Конечные точки
Мы узнали о том, как конечные точки выглядят в нашем интеграционном коде. Выражения, которые мы использовали до сих пор, такие как file: / order, jms: orderQueue, direct: distribteOrderDSL, являются конечными точками. Как видите, они следуют форматам спецификации URI. При оценке этого URI CamelContext создает экземпляр Endpoint ; вам не нужно беспокоиться о реализации Endpoint в вашем DSL.
Взяв наши предыдущие примеры, вы указываете конечные точки в Java DSL, как здесь —
from ("file:/order").to("jms:orderQueue");
А весной как здесь —
<route> <from uri = "file:/order"/> <to uri = "jms:orderQueue"/> </route>
В обоих случаях конечная точка является константной строкой. В некоторых случаях вы можете захотеть построить эту строку во время выполнения. Вы можете сделать это, используя методы форматирования Java String . Camel предоставляет еще один более простой подход для создания этих строк URI во время выполнения. Для этой цели Camel предоставляет методы fromF и toF, которые принимают аргументы с указанными пользователем параметрами. Следующее утверждение иллюстрирует использование метода toF —
from("direct:distributeOrderDSL”).toF("file://%s?fileName=%s", path, name);
Благодаря этим методам устраняется необходимость использования встроенных в Java методов форматирования String .
Верблюд по умолчанию использует простой язык для вычисления выражения конечной точки. Язык Simple был разработан, прежде всего, для оценки выражений и предикатов, не беспокоясь о тонкостях XPath . Для оценки предикатов вы можете комбинировать другой язык, такой как xpath, с простым языком по умолчанию. Это делается с помощью знака плюс, чтобы отделить другой язык. Фрагмент кода здесь показывает, как объединить строку xpath с выражением, написанным на Simple .
from("direct:start") .toD("jms:${orderQueue}+language:xpath:/order/@id");
Весной можно добиться того же, что и здесь —
<route> <from uri = "direct:start"/> <toD uri = "jms:${orderQueue}+language:xpath:/order/@id"/> </route>
Вы можете объединить столько языков, сколько хотите, каждый из которых отделен знаком плюс от предыдущего. Список поддерживаемых языков можно найти здесь .
Apache Camel — Компоненты
Верблюд предоставляет несколько готовых компонентов.
В этой главе мы обсудим несколько важных компонентов из модуля Camel-Core .
боб
Компонент Bean связывает bean-компоненты с обменом сообщениями Camel. URI для создания конечной точки указывается как bean: beanID , где beanID — это имя компонента, указанное в реестре .
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 : . При желании вы можете указать метод бина, который должен быть вызван; в этом случае метод с именем placeOrder будет вызван при оценке выражения Endpoint. MilkOrder — это имя JNDI для Javabean MilkOrderProcessor, зарегистрированное в первых двух строках фрагмента кода. Само определение MilkOrderProcessor здесь для краткости опущено.
непосредственный
Вы, наверное, заметили использование Direct в наших предыдущих примерах. Чтобы отправить заказ поставщику масла, мы использовали direct: oil в спецификации Endpoint. Использование компонента Direct позволяет синхронно вызывать конечную точку. Следующие два фрагмента кода из наших предыдущих примеров иллюстрируют использование Direct —
.when(header("order").isEqualTo("oil")) .to("direct:oil")
А также,
from("direct:DistributeOrderDSL") .process(myProcessor);
файл
Компонент File обеспечивает доступ к файловой системе на вашем компьютере. Используя этот компонент, вы сможете сохранять сообщения от других компонентов на локальный диск. Кроме того, он позволяет другим компонентам Camel обрабатывать локальные файлы. Вы можете использовать либо file: directoryName [? Options], либо file: // directoryName [? Options] в качестве формата URI при использовании компонента File. Ранее вы видели использование этого компонента —
from ("file:/order").to("jms:orderQueue");
Обратите внимание, что компонент File по умолчанию принимает имя каталога. Следовательно, содержимое каталога заказов будет принято как входное содержимое. Чтобы указать конкретный файл в каталоге заказов , вы будете использовать следующий оператор —
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 позволяет асинхронно вызывать другую конечную точку в том же 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");
Apache Camel — очереди сообщений
В большинстве интеграционных проектов используется обмен сообщениями, поскольку он помогает создавать слабосвязанную архитектуру приложений. Обмен сообщениями может быть синхронным или асинхронным. JMS поддерживает модели « точка-точка» и « публикация-подписка» . Вы используете Очередь для двухточечного и Темы для модели публикации-подписки. На платформе Java JMS — Java Messaging Service предоставляет интерфейс к серверу обмена сообщениями. Apache activeMQ — один из таких провайдеров JMS с открытым исходным кодом. Camel не поставляется с JMS-провайдером; однако его можно настроить на использование activeMQ. Чтобы использовать этот компонент, вам нужно включить в свой проект следующие jar-файлы: activemq, camel-spring и camel-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.
Apache 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>
Примечание. Для нашего приложения нужны минимальные зависимости. Поскольку вы используете больше компонентов 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.
Apache 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 . Как и в предыдущем случае, мы определяем конечную точку для загрузки файла 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>
Конечные точки вывода являются множественными. Первая конечная точка указывает папку заказа, а вторая — консоль.
<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>
Проверьте папку заказа по указанному вами пути. Вы найдете недавно созданный файл, который содержит вышеуказанный код XML.
Заключение
Camel предоставляет готовую среду, которая реализует EIP для упрощения ваших интеграционных проектов. Он поддерживает кодирование на предметно-ориентированных языках, а также использование XML.