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 в этом руководстве.

Camel - это черный ящик, который получает сообщения от одной конечной точки и отправляет их на другую. В черном ящике сообщения могут обрабатываться или просто перенаправляться.

Так зачем для этого есть рамки? В практических ситуациях, как показано во введении, может быть много отправителей и много получателей, каждый из которых следует своему собственному протоколу, например ftp, http и jms. Система может потребовать множество сложных правил, например, сообщение от отправителя A должно быть доставлено только B и C. В некоторых ситуациях вам может потребоваться перевести сообщение в другой формат, который ожидает получатель. Этот перевод может зависеть от определенных условий в зависимости от содержания сообщения. По сути, вам может потребоваться перевод между протоколами, склеивание компонентов вместе, определение правил маршрутизации и обеспечение фильтрации на основе содержимого сообщения. Это показано на следующем рисунке -

Чтобы удовлетворить вышеуказанные требования и разработать правильную архитектуру программного обеспечения для многих таких ситуаций, в 2003 году Грегор Хоуп и Бобби Вульф задокументировали шаблоны интеграции предприятия ( EIP ). Apache Camel обеспечивает реализацию этих шаблонов, и цель этого руководства - научить вы узнаете, как использовать Camel в ситуациях, подобных описанной во введении.

Apache Camel - это фреймворк с открытым исходным кодом. Это промежуточное ПО, ориентированное на сообщения, которое предоставляет механизм маршрутизации и посредничества на основе правил. Вы можете определить правила, например, если это «молочный» заказ, перенаправить его поставщику молока, а если «масляный» - перенаправить его поставщику масла, и так далее. Используя Camel, вы сможете реализовать эти правила и выполнить маршрутизацию в знакомом Java-коде. Это означает, что вы можете использовать знакомую вам среду разработки Java IDE для определения этих правил в типобезопасной среде. Нам не нужно использовать файлы конфигурации XML, которые обычно бывают громоздкими. Однако Camel поддерживает конфигурацию XML через платформу Spring, если вы предпочитаете использовать 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 - это среда Java с открытым исходным кодом, которая по существу обеспечивает реализацию различных EIP. Camel упрощает интеграцию, обеспечивая возможность подключения к очень большому количеству транспортов и API. Например, вы можете легко перенаправить JMS в JSON, JSON в JMS, HTTP в JMS, FTP в JMS, даже HTTP в HTTP и возможность подключения к микросервисам. Вам просто нужно предоставить соответствующие конечные точки на обоих концах. Camel является расширяемым, и поэтому в будущем в структуру можно будет легко добавить больше конечных точек.

Чтобы связать 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 состоит из трех компонентов - механизма интеграции и маршрутизатора, процессоров и компонентов. Это показано на следующем рисунке -

Само ядро ​​Camel очень маленькое и содержит 13 основных компонентов. Остальные 80+ компонентов находятся вне ядра. Это помогает поддерживать низкую зависимость от места развертывания и способствует продвижению расширений в будущем. ВComponents модуль обеспечивает Endpointинтерфейс с внешним миром. Конечные точки указываются URI, напримерfile:/order и jms:orderQueue что вы видели в предыдущей главе.

В Processorsмодуль используется для управления и передачи сообщений между конечными точками. EIP, о которых я упоминал ранее, реализованы в этом модуле. В настоящее время он поддерживает более 40 шаблонов, как описано в книге EIP и других полезных процессорах.

В 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как следует из названия, содержит различные конвертеры загруженного типа, которые преобразуют ваш ввод из одного формата в другой. Вы можете использовать встроенные преобразователи типов или предоставить свой собственный механизм преобразования. ВComponentsmodule содержит компоненты, используемые вашим приложением. Компоненты загружаются путем автоматического обнаружения на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экземпляры для определения нескольких маршрутов. Каждый маршрут в одном контексте должен иметь уникальный идентификатор. Маршруты можно добавлять динамически во время выполнения. Маршрут с таким же идентификатором, как и ранее определенный, заменит старый маршрут.

Что входит в 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");
   }
}

Мы переопределяем метод настройки RouteBuilderclass и реализуем в нем наш механизм маршрутизации и фильтрации. В текущем случае мы перенаправляем ввод, полученный от Конечной точки.DistributeOrderDSL на консоль, которая указана Конечной точкой 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. При оценке этого URICamelContext создает 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 методы форматирования исключены.

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 предоставляет несколько готовых компонентов.

В этой главе мы обсудим несколько важных компонентов из camel-core модуль.

Фасоль

В BeanКомпонент связывает beans к обмену сообщениями Camel. URI для создания конечной точки указывается как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:протокол. Вы можете дополнительно указать метод компонента, который должен быть вызван; в этом случае метод называетсяplaceOrderбудет вызываться при оценке выражения Endpoint. В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 при использовании компонента File. Вы ранее видели использование этого компонента -

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. Чтобы использовать этот компонент, вам необходимо включить в свой проект следующие 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.

Мы будем использовать 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метод. Как и в предыдущем случае, мы определяем конечную точку для загрузки файла 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.