Статьи

Интеграция с открытым исходным кодом с Apache Camel и как может помочь Fuse IDE

Возьмите любой интеграционный проект, и у вас будет несколько приложений, говорящих по нескольким транспортам на разных платформах. Как вы можете себе представить, на крупных предприятиях подобные приложения могут очень быстро усложняться. Большая часть сложности проистекает из двух вопросов:

  1. Работа со спецификой приложений и транспортов
  2. Придумать хорошие решения проблем интеграции

Заставить ваши приложения говорить на транспорте и API довольно легко. Я уверен, что все знают, как отправлять сообщения JMS выбранному брокеру; хотя это все еще требует глубокого знания спецификации JMS, которой многие разработчики могут не иметь. Кроме того, что происходит, когда вы хотите направить это сообщение JMS в другое приложение? Затем вам нужно позаботиться о сопоставлении сообщения JMS с приложением, а также обработать любые новые концепции, связанные с приложением. Добавьте в смесь дюжину других приложений, и у вас будет сильная головная боль.

Игнорируя механику соединения с несколькими транспортными системами и API, мы можем сосредоточиться на высокоуровневом дизайне взаимодействия приложений. К счастью, большинство решений проблем интеграции предприятий уже оформлены. Книга Грегора Хопе и Бобби Вулфа « Шаблоны корпоративной интеграции: проектирование, создание и развертывание решений для обмена сообщениями» объединяет многолетний опыт корпоративных архитекторов в набор из шестидесяти пяти шаблонов корпоративной интеграции (EIP). Это здорово, но мы все еще должны вручную закодировать все части этих шаблонов; это не пакетные решения, а только рекомендации.

Apache Camel был создан с целью решения этих двух проблем. В этой статье я сначала дам вам краткий обзор того, что такое Camel. Затем я расскажу вам, как Camel решает проблему с примером интеграции. Наконец, я покажу некоторые новые графические инструменты, которые еще более упрощают решение проблем интеграции с Camel.

Что такое верблюд?

Apache Camel — это Java-инфраструктура с открытым исходным кодом, цель которой — сделать интеграцию проще и доступнее для разработчиков. Это достигается путем предоставления:

  • Конкретные реализации всех широко используемых EIP

  • Возможность подключения к большому количеству транспортов и API

  • Простые в использовании доменно-специфические языки (DSL) для соединения EIP и транспорта

На рисунке 1 показано, как эти три элемента в действительности соответствуют концепциям Camel. Чтобы лучше понять, как организован Camel, мы обсудим компоненты, конечные точки, процессоры и DSL. Конечно, под капотом происходит гораздо больше, но мы оставим это для другого обсуждения.

Рисунок 1: Общий вид архитектуры Camel (из Camel в действии ).

Компоненты являются точкой расширения в Camel для добавления возможности подключения к другим системам. Ядро Camel очень маленькое, чтобы поддерживать низкие зависимости, способствовать встраиваемости и т. Д. И в результате содержит только 13 основных компонентов. За пределами ядра находится более 80 компонентов. Чтобы представить эти системы остальной части Camel, Компоненты предоставляют интерфейс конечной точки. Используя URI, вы можете отправлять или получать сообщения на конечных точках единообразным способом. Например, чтобы получать сообщения из очереди JMS aQueue и отправлять их в каталог файловой системы «/ tmp», вы можете использовать такие URI, как «jms: aQueue» и «file: / tmp».

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

Чтобы связать процессоры и конечные точки вместе, Camel определяет несколько DSL на обычных языках программирования, таких как Java, Scala и Groovy. Он также позволяет указывать правила маршрутизации в XML. Вот несколько примеров DSL, использующих разные языки и остающихся функционально эквивалентными:

  • Java DSL
from ("file:/tmp").to("jms:aQueue");
  • Spring DSL
<route>
  <from uri="file:/tmp"/>
  <to uri="jms:aQueue"/>
</route>
  • Scala DSL
from "file:/tmp" -> "jms:aQueue"

Во всех приведенных выше примерах мы определяем правило маршрутизации, которое загружает файлы из каталога «/ tmp» в память, создает новое сообщение JMS с содержимым файла и отправляет это сообщение в очередь JMS с именем aQueue .

Это концепции, на которых был построен Верблюд. С тех пор было добавлено много других интересных функций. Я рекомендую прочитать « Верблюд в действии » Клауса Ибсена и меня, чтобы действительно получить полную картину того, что может сделать Верблюд. Но, для начала, некоторые из этих дополнительных функций включают в себя:

  • Сменные форматы данных и преобразователи типов для простого преобразования сообщений между CSV, EDI, Flatpack, HL7, JAXB, JSON, XmlBeans, XStream, Zip и т. Д.
  • Сменные языки для создания выражений или предикатов для использования в DSL. Вот некоторые из этих языков: EL, JXPath, Mvel, OGNL, BeanShell, JavaScript, Groovy, Python, PHP, Ruby, SQL, XPath, XQuery и т. Д.
  • Поддержка интеграции бобов и POJO в различных местах в Camel.
  • Отличная поддержка для тестирования распределенных и асинхронных систем с использованием подхода обмена сообщениями
  • И многое другое…

Представляем автозапчасти Rider

Пример в этой статье основан на вымышленном мотоциклетном бизнесе, который используется в книге « Верблюд в действии» . Компания Rider Auto Parts поставляет запчасти производителям мотоциклов. За прошедшие годы они несколько раз меняли способ получения заказов. Первоначально заказы размещались путем загрузки файлов значений, разделенных запятыми (CSV), на FTP-сервер. Позднее формат сообщения был изменен на XML. В настоящее время они предоставляют веб-сайт, через который заказы отправляются в виде XML-сообщений по HTTP.

Rider Auto Parts просит новых клиентов использовать веб-интерфейс для размещения заказов, но из-за соглашений об уровне обслуживания (SLA) с существующими клиентами они должны поддерживать все старые форматы сообщений и интерфейсы в рабочем состоянии. Все эти сообщения перед обработкой преобразуются во внутренний формат Plain Old Java Object (POJO). Общее представление о системе обработки заказов показано на рисунке 2.

Рисунок 2: Высокоуровневое представление обработки заказов на автозапчастях Rider (от Camel в действии ).

Нам нужно найти наилучший способ реализации «интерфейса Rider Order» на рисунке 2 выше. Давайте сначала посмотрим, как это выглядит, используя нотацию из книги Enterprise Integration Patterns .

Решение с использованием EIP

Rider Auto Parts сталкивается с довольно распространенной проблемой; За годы работы предприятия приобретают программный багаж в виде популярных в то время форматов транспорта / данных. Используя шаблоны из книги EIP, мы можем представить решение в виде рисунка 3.

Рисунок 3: Это показывает решение проблемы интеграции Rider Auto Parts с использованием нотации из книги Enterprise Integration Patterns.

Таким образом, у нас есть несколько шаблонов в использовании здесь.

  1. Есть две конечные точки сообщения; один для FTP-соединения и другой для HTTP.

  2. Сообщения с этих конечных точек поступают в канал сообщений входящихOrders

  3. Сообщения поступают из канала сообщений входящих сообщений и маршрутизируются контентным маршрутизатором на один из двух трансляторов сообщений. Как следует из названия EIP, пункт назначения маршрутизации зависит от содержимого сообщения. В этом случае нам нужно выполнить маршрутизацию в зависимости от того, является ли контент файлом CSV или XML.

  4. Оба переводчика сообщений преобразуют содержимое сообщения в POJO, который подается в  канал сообщений заказов .

Весь раздел, в котором используется контентный маршрутизатор и несколько трансляторов сообщений, называется нормализатором. Этот составной шаблон имеет уникальную графику, чтобы изобразить его, но был оставлен здесь в пользу его подшаблонов, чтобы прояснить ситуацию.

Реализация с использованием Camel

Как упоминалось ранее, Camel имеет небольшой базовый набор компонентов, включенных по умолчанию. Остальные компоненты существуют как отдельные модули. В приложениях, где требуется много типов подключения, полезно выяснить, какие модули Camel следует включить. В листинге 1 показаны зависимости, использующие Apache Maven для реализации Camel примера Rider Auto Parts. Конечно, вам не нужно использовать Apache Maven для зависимостей — это просто самый простой способ быстро добавить новые зависимости в ваши приложения. Список зависимостей включает поддержку ядра Camel, ActiveMQ, маршалинга JAXB, маршалинга CSV и HTTP. Чтобы облегчить пример, я решил использовать конечную точку File вместо FTP. Если бы мы использовали конечную точку FTP, нам нужно было бы также добавить зависимость от модуля camel-ftp.

Листинг 1. Maven-зависимости для реализации Camel

<dependencies>
    <!-- Core Camel -->
    <dependency>
      <groupId>org.apache.camel</groupId>
      <artifactId>camel-core</artifactId>
      <version>${camel-version}</version>
    </dependency>
    <dependency>
      <groupId>org.apache.camel</groupId>
      <artifactId>camel-spring</artifactId>
      <version>${camel-version}</version>
    </dependency>

    <!-- Embedded ActiveMQ broker -->
    <dependency>
      <groupId>org.apache.activemq</groupId>
      <artifactId>activemq-core</artifactId>
      <version>${activemq-version}</version>
    </dependency>
    <dependency>
      <groupId>org.apache.xbean</groupId>
      <artifactId>xbean-spring</artifactId>
      <version>${xbean-spring-version}</version>
    </dependency>

    <!-- ActiveMQ connectivity for Camel -->           
    <dependency>
      <groupId>org.apache.activemq</groupId>
      <artifactId>activemq-camel</artifactId>
      <version>${activemq-version}</version>
    </dependency>

    <!-- Add support for JAXB marshaling -->
    <dependency>
      <groupId>org.apache.camel</groupId>
      <artifactId>camel-jaxb</artifactId>
      <version>${camel-version}</version>
    </dependency>

    <!-- Add support for CSV marshaling -->   
    <dependency>
      <groupId>org.apache.camel</groupId>
      <artifactId>camel-bindy</artifactId>
      <version>${camel-version}</version>
    </dependency>    

    <!-- Add support for HTTP -->
    <dependency>
      <groupId>org.apache.camel</groupId>
      <artifactId>camel-jetty</artifactId>
      <version>${camel-version}</version>
    </dependency>

  </dependencies>

Хотя использование Camel в качестве автономного Java-приложения вполне законно, часто бывает полезно встроить его в контейнер. В этом случае мы будем загружать Camel полностью из Spring. Фактически, все решение (за исключением домена POJO и сценария сборки Maven) аккуратно помещается в один XML-файл Spring. Это потому, что мы реализуем наши правила маршрутизации, используя конфигурацию Spring XML, а не один из других DSL Camel. Конечно, у каждого есть свои плюсы и минусы, но в этом случае я в основном хотел показать некоторые интересные инструменты, которые в настоящее время работают только с правилами маршрутизации на основе XML. XML-файл Spring показан в листинге 2 ниже.

Листинг 2: Полный XML-файл Spring, который настраивает встроенный брокер ActiveMQ и инициализирует Camel Context тремя путями.

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:amq="http://activemq.apache.org/schema/core"
       xsi:schemaLocation="
       http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
       http://activemq.apache.org/camel/schema/spring
       http://activemq.apache.org/camel/schema/spring/camel-spring.xsd
       http://activemq.apache.org/schema/core
       http://activemq.apache.org/schema/core/activemq-core.xsd">

  <amq:broker brokerName="localhost" persistent="false" useJmx="false"/>

  <bean id="jms" class="org.apache.activemq.camel.component.ActiveMQComponent">
    <property name="brokerURL" value="vm://localhost" />
  </bean>

  <camelContext xmlns="http://camel.apache.org/schema/spring">
    <route id="FileToJMS">
      <from uri="file:target/placeorder" />
      <to uri="jms:incomingOrders" />
    </route>

    <route id="HTTPtoJMS">
      <from uri="jetty:http://0.0.0.0:8888/placeorder" />
      <inOnly uri="jms:incomingOrders" />
      <transform>
        <constant>OK</constant>
      </transform>
    </route>

    <route id="NormalizeMessageData">
      <from uri="jms:incomingOrders" />
      <convertBodyTo type="java.lang.String" />
      <choice>
        <when>
          <simple>${body} contains '?xml'</simple>
          <unmarshal>
            <jaxb contextPath="org.fusesource.camel" />
          </unmarshal>
          <to uri="jms:orders" />
        </when>
        <otherwise>
          <unmarshal>
            <bindy packages="org.fusesource.camel" type="Csv" />
          </unmarshal>
          <to uri="jms:orders" />
        </otherwise>
      </choice>     
    </route>
  </camelContext>
</beans>

В этом файле мы сначала запускаем встроенный брокер Apache ActiveMQ и подключаем к нему Camel. Далее идет элемент camelContext, где мы определяем наши правила маршрутизации. Возвращаясь к рисунку 3, нам нужно получать заказы от FTP (в данном примере замещенного File) и конечной точки HTTP, отформатированной, как показано в листинге 3. В конфигурации Spring XML мы можем указать эти входящие конечные точки с двумя элементами from . В «FileToJMS» и «HTTPtoJMS» маршруты начинаются с них из элементов. Оба из элементов подключены к производителю ( к и inOnly элементов) с использованием « JMS: incomingOrders» URI, который будет отправлять сообщения в очереди по имениincomingOrders на брокера ActiveMQ.

Листинг 3: Форматы входящих сообщений; XML слева, CSV справа.

<? xml version = «1.0» encoding = «UTF-8»?>
<order name = «motor» amount = «1» />

«имя», «сумма»,
«тормозная колодка», «2»

В случае с конечной точкой HTTP необходимо упомянуть еще пару вещей. Прежде всего, HTTP-клиент будет ожидать ответа от приложения, поэтому мы должны с этим справиться. В Camel мы имеем полный контроль над тем, что клиент получает от конечной точки HTTP. Каждый ответ определяется последним методом в нашем текущем определении маршрута. В нашем случае мы используем метод transform, чтобы установить ответ на константную строку «ОК». Так как мы обрабатываем ответ сами, мы не хотим никакого ответа прийти от JMS incomingOrders очереди. Для отправки в эту очередь методом « забыл и забыл» мы используем элемент inOnly, а не элемент to .

Маршрут «NormalizeMessageData» в листинге 2 задает нормализатор, дополненный маршрутизатором на основе содержимого и двумя переводчиками сообщений. Во-первых, мы указываем, что мы хотим получать сообщения из очереди входящих сообщений в брокере ActiveMQ. Контентная маршрутизация сообщений осуществляется с выбором , когда и другими элементами. В нашем случае мы хотим отправлять CSV-сообщения одному транслятору сообщений, а XML-сообщения — другому. Чтобы проверить, какой тип формата данных у нас есть, мы используем простое выражение, которое проверяет тело сообщения на начальный тег «<? Xml». простоэто язык выражения, встроенный в верблюда. Конечно, это только демонстрационный код. Для производственных случаев вы хотели бы добавить более тщательную проверку типов контента.

Чтобы демонтировать полезные нагрузки XML и CSV в объект Order , мы используем форматы данных Camel. В листинге 2 показано, как эти форматы данных определены в немаршальных элементах. Как показано в листинге 5, объект Order имеет аннотации JAXB и Camel Bindy для описания сопоставления с XML и CSV.

Листинг 5: Класс домена Order с аннотациями JAXB / Bindy для простого сопоставления с XML / CSV и из него.

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
@CsvRecord(separator = ",", skipFirstLine = true)
public class Order implements Serializable {
    @XmlAttribute
    @DataField(pos = 1)
    private String name;

    @XmlAttribute
    @DataField(pos = 2)
    private int amount;

   public Order() {
    }

    public Order(String name, int amount) {
        this.name = name;
        this.amount = amount;
    }
}

На этом этапе успешно нормализованные сообщения отправляются в очередь заказов для обработки другим приложением в компании Rider Auto Parts.

Реализация с использованием Fuse IDE для Camel

Как мы уже видели, Apache Camel, безусловно, облегчает создание интеграций. DSL на разных языках разработаны для того, чтобы быть краткими, мощными и удобными для чтения — все с целью сделать вас, разработчика, более продуктивным. Имея в виду повышение производительности, FuseSource создал IDE для разработки Camel под названием Fuse IDE для Camel .

Fuse IDE — это инструмент на основе Eclipse, который позволяет перетаскивать значки EIP (Enterprise Integration Pattern) на холст и соединять их вместе для формирования правил маршрутизации. Бэкэнд IDE генерирует правила маршрутизации Camel в Spring XML для вас, поэтому вам никогда не придется изучать особенности DSL Camel. По сути, вы можете создать рисунок, подобный рисунку 3, и заставить Fuse IDE сгенерировать приложение Camel для вас.

На рисунке 4 показано, как выглядит конструктор Fuse IDE, когда мы загрузили наш пример конфигурации из листинга 2.

Рисунок 4: XML-файл Spring в листинге 2, загруженный в конструктор Fuse IDE.

В представлении конструктора мы видим графическое представление каждого из маршрутов, которые мы предварительно создали в Spring XML. С этого момента мы можем изменить способ подключения значков EIP, свойства URI конечной точки, добавить дополнительные шаги к маршрутам и т. Д. Кроме того, начиная с версии 1.0, Fuse IDE будет поддерживать все EIP и компоненты, доступные в Apache Camel, поэтому версия 2.0 не будет использовать ваши любимые функции Camel.

В этой статье мы начали с создания конфигурации Spring XML вручную. Это не должно вводить вас в заблуждение, однако, это не требуется. Фактически, поскольку Fuse IDE поддерживает циклическое переключение 1: 1 между XML-конфигурацией Camel Spring и представлением конструктора, вы можете использовать все, что пожелаете. 

Когда вы закончите создавать свои маршруты, вы сможете воспользоваться другой удобной функцией, включенной в Fuse IDE: это возможность генерировать тестовый пример JUnit из любого XML-файла Camel Spring. После того как вы будете удовлетворены результатами тестирования, вы сможете отладить его в локальном контейнере Spring или развернуть в выбранном контейнере — и все это в среде IDE. Конечно, в будущем для Fuse IDE запланировано гораздо больше, поэтому разработка Camel будет только легче.

Резюме

В этой статье я показал две распространенные проблемы, с которыми может столкнуться разработчик интеграции: работа со спецификой приложений и транспортов и поиск хороших решений проблем интеграции. Проект Apache Camel дает хороший ответ на обе эти проблемы. Как показал пример, решение проблем интеграции с Camel является простым и приводит к очень кратким определениям маршрута. Основываясь на этом, мы увидели, как Fuse IDE для Camel делает разработку Camel еще проще.

связи

  1. Apache Camel — http://camel.apache.org
  2. 2FuseSource дистрибутив Apache Camel — http://fusesource.com/products/enterprise-camel
  3. Предохранитель IDE для Camel —  https://tools.jboss.org/features/fusetools.html
  4. Книга «Верблюд в действии» — http://www.manning.com/ibsen
  5. Блог Джона — http://janstey.blogspot.com
  6. Исходный код статьи — http://repo.fusesource.com/maven2/org/fusesource/examples/rider-auto-spring/2.0/rider-auto-spring-2.0.zip

Первоначально опубликовано 01.07.15