Статьи

Весенняя интеграция и Apache Camel

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

Apache Camel —


Apache Camel — это мощная интегрированная среда с открытым исходным кодом, основанная на известных корпоративных шаблонах интеграции с мощной интеграцией компонентов.

Весенняя интеграция —


Он обеспечивает расширение модели программирования Spring для поддержки хорошо известных шаблонов корпоративной интеграции, опираясь на существующую поддержку Spring Framework для интеграции предприятия.

По сути Spring Integration и Apache Camel позволяют приложениям интегрироваться с другими системами.

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

Проблема:

Чтобы проиллюстрировать использование этих структур, рассмотрим простой сценарий интеграции, описанный с использованием терминологии EIP:

 

Прикладная программа должна получить «Отчет» путем агрегирования «Разделов» из службы XML XML по разделу. Каждый запрос на отчет состоит из набора запросов на разделы — в этом конкретном примере есть запросы на три раздела, верхний и нижний колонтитулы. Служба XML через http возвращает раздел для запроса раздела. Ответы должны быть объединены в один отчет. Пример теста для этого сценария имеет следующий тип:

        ReportGenerator reportGenerator = reportGeneratorFactory.createReportGenerator();
List<SectionRequest> sectionRequests = new ArrayList<SectionRequest>();

String entityId="A Company";

sectionRequests.add(new SectionRequest(entityId,"header"));
sectionRequests.add(new SectionRequest(entityId,"body"));
sectionRequests.add(new SectionRequest(entityId,"footer"));

ReportRequest reportRequest = new ReportRequest(sectionRequests);

Report report = reportGenerator.generateReport(reportRequest);
List<Section> sectionOfReport = report.getSections();
System.out.println(report);
assertEquals(3, sectionOfReport.size());

«ReportGenerator» — это шлюз обмена сообщениями, скрывающий детали базовой инфраструктуры обмена сообщениями, а в данном конкретном случае и API интеграции — Apache Camel или Spring Integration. Для начала давайте реализуем решение этой проблемы интеграции, используя Spring Integration в качестве платформы, а затем Apache Camel. Полный рабочий код с использованием Spring Integration и Apache Camel также доступен в статье.

 

Решение с использованием Spring Integration:

Компонент Gateway легко настраивается с помощью следующей записи в Spring Configuration. Внутренне Spring Integration использует AOP для подключения компонента, который направляет запросы из внутреннего входного канала и ожидает ответа в ответном канале.

<si:gateway default-reply-channel="exit" default-request-channel="enter" id="reportGenerator" service-interface="org.bk.report.ReportGenerator">
</si:gateway>

Компонент для разделения запроса входного отчета на запрос раздела довольно прост:

public class SectionRequestSplitter {    
public List split(ReportRequest reportRequest){
return reportRequest.getSectionRequests();
}

}

и подключить этот сплиттер с помощью Spring Integration:

<bean class="org.bk.report.common.SectionRequestSplitter" id="sectionRequestSplitterBean">

<si:splitter id="sectionRequestSplitter" input-channel="enter" method="split" output-channel="sectionRequestToXMLChannel" ref="sectionRequestSplitterBean">

</si:splitter></bean>

Затем, чтобы преобразовать Запрос Раздела в формат XML — Компонент является следующим:

public class SectionRequestToXMLTransformer {
public String transform(SectionRequest sectionRequest){
//this needs to be optimized...purely for demonstration of the concept
String sectionRequestAsString = "<section><meta><entityId>" + sectionRequest.getEntityId()
+ "</entityId><sectionName>" + sectionRequest.getSectionId()
+ "</sectionName></meta></section>";

return sectionRequestAsString;

}
}

и подключается в файле конфигурации Spring Integration следующим образом:

<bean id="sectionRequestToXMLBean" class="org.bk.report.common.SectionRequestToXMLTransformer"/>
<si:transformer input-channel="sectionRequestToXMLChannel" ref="sectionRequestToXMLBean" method="transform" output-channel="sectionRequestChannel"/>

Чтобы отправить XML-запрос через http с помощью XML-запроса раздела в службу раздела:

<http:outbound-gateway id="httpHeaderGateway"
request-channel="sectionRequestChannel" reply-channel="sectionResponseChannel"
default-url="${sectionBaseURL}/section" extract-request-payload="true"
charset="UTF-8" request-timeout="1200" />

Чтобы преобразовать XML-код ответа секции в объект секции — Компонент имеет следующий вид:

public class SectionResponseXMLToSectionTransformer {
public Section transform(String sectionXML) {
SAXReader saxReader = new SAXReader();
Document document;
String sectionName = "";
String entityId = "";
try {
document = saxReader.read(new StringReader(sectionXML));

sectionName = document
.selectSingleNode("/section/meta/sectionName").getText();
entityId = document.selectSingleNode("/section/meta/entityId")
.getText();
} catch (DocumentException e) {
e.printStackTrace();
}
return new Section(entityId, sectionName, sectionXML);
}
}

и подключается в файле конфигурации Spring Integration следующим образом:

<bean id="sectionResponseXMLToSectionBean" class="org.bk.report.common.SectionResponseXMLToSectionTransformer" />
<si:transformer input-channel="sectionXMLResponseChannel"
ref="sectionResponseXMLToSectionBean" method="transform" output-channel="sectionResponseChannel" />


Чтобы объединить разделы в отчет, компонент имеет следующий вид:

public class SectionResponseAggregator {

public Report aggregate(List<Section> sections) {
return new Report(sections);
}

}

и подключается в файле конфигурации Spring Integration следующим образом:

<bean id="sectionResponseAggregator" class="org.bk.report.common.SectionResponseAggregator"/>
<si:aggregator input-channel="sectionResponseChannel" output-channel="exit" ref="sectionResponseAggregator" method="aggregate"/>

Это завершает реализацию Spring Integration для этой проблемы интеграции. Ниже приведен полный файл конфигурации Spring Integration:

<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context" xmlns:si="http://www.springframework.org/schema/integration"
xmlns:http="http://www.springframework.org/schema/integration/http"
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://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration-1.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
http://www.springframework.org/schema/integration/http http://www.springframework.org/schema/integration/http/spring-integration-http-1.0.xsd
">

<context:property-placeholder />
<si:channel id="enter" />

<si:channel id="exit" />

<si:gateway id="reportGenerator" default-request-channel="enter"
default-reply-channel="exit" service-interface="org.bk.report.ReportGenerator" />

<si:channel id="sectionRequestToXMLChannel" />
<si:splitter id="sectionRequestSplitter" input-channel="enter"
ref="sectionRequestSplitterBean" method="split" output-channel="sectionRequestToXMLChannel" />

<si:channel id="sectionRequestChannel" />
<si:transformer input-channel="sectionRequestToXMLChannel"
ref="sectionRequestToXMLBean" method="transform" output-channel="sectionRequestChannel" />

<si:channel id="sectionXMLResponseChannel" />
<http:outbound-gateway id="httpHeaderGateway"
request-channel="sectionRequestChannel" reply-channel="sectionXMLResponseChannel"
default-url="${sectionBaseURL}/section" extract-request-payload="true"
charset="UTF-8" request-timeout="1200" />

<si:channel id="sectionResponseChannel" />
<si:transformer input-channel="sectionXMLResponseChannel"
ref="sectionResponseXMLToSectionBean" method="transform" output-channel="sectionResponseChannel" />

<si:aggregator input-channel="sectionResponseChannel"
output-channel="exit" ref="sectionResponseAggregator" method="aggregate" />

<bean id="sectionRequestSplitterBean" class="org.bk.report.common.SectionRequestSplitter" />
<bean id="sectionRequestToXMLBean" class="org.bk.report.common.SectionRequestToXMLTransformer" />
<bean id="sectionResponseXMLToSectionBean" class="org.bk.report.common.SectionResponseXMLToSectionTransformer" />
<bean id="sectionResponseAggregator" class="org.bk.report.common.SectionResponseAggregator" />

</beans>

 

Рабочий образец предоставляется вместе со статьей (скачать, распаковать и запустить «mvn test»)

 

Решение с использованием Apache Camel:

Apache Camel позволяет определять маршрут с использованием нескольких реализаций DSL — Java DSL, Scala DSL и DSL на основе XML. Рекомендуемый подход заключается в использовании Spring CamelContext в качестве среды выполнения и Java DSL для разработки маршрутов. Ниже приведено построение контекста Spring Camel:

<camelContext id="camel" xmlns="http://camel.apache.org/schema/spring">
<template id="camelTemplate" />
<routeBuilder ref="routeBuilder"/>
</camelContext>


Маршрут настраивается DSL на основе Java:

public class CamelRouteBuilder extends RouteBuilder {
private String serviceURL;

@Override
public void configure() throws Exception {

from("direct:start")
.split().method("sectionRequestSplitterBean", "split")
.aggregationStrategy(new ReportAggregationStrategy())
.transform().method("sectionRequestToXMLBean", "transform")
.to(serviceURL)
.transform().method("sectionResponseXMLToSectionBean", "transform");
}

public void setServiceURL(String serviceURL) {
this.serviceURL = serviceURL;
}
}


Apache Camel не предоставляет встроенной функции шлюза сообщений, однако довольно легко создать компонент-обертку, который может скрывать основные детали следующим образом:

Reader davsclaus предоставил ссылки на два механизма с Apache Camel для предоставления готового шлюза обмена сообщениями — Messaging Gateway EIP и Camel Proxy, который позволяет использовать POJO в качестве шлюза обмена сообщениями. 

Camel Proxy будет использоваться со статьей и может быть настроен в файлах конфигурации Camel следующим образом:

	<camelContext id="camel" xmlns="http://camel.apache.org/schema/spring">

		<proxy id="consumerMessageGateway" serviceInterface="org.bk.report.ReportGenerator"
			serviceUrl="direct:start" />

		<template id="camelTemplate" />
		<routeBuilder ref="routeBuilder" />
	</camelContext>

В davsclaus, есть ошибка в Apache Camel (версии 2.1 или старше) при вызове bean-компонента позже на маршруте (bean-сплиттера), который должен быть исправлен в Apache Camel 2.2. Чтобы обойти эту ошибку, на пути будет представлен шаг convertBody:

        from("direct:start")
.convertBodyTo(ReportRequest.class)
.split(bean("sectionRequestSplitterBean", "split"), new ReportAggregationStrategy())
.transform().method("sectionRequestToXMLBean", "transform")
.to(serviceURL)
.transform().method("sectionResponseXMLToSectionBean", "transform");

 

Компонент для разделения запроса входного отчета на запрос раздела точно такой же, как компонент Spring Integration:

public class SectionRequestSplitter {

public List<SectionRequest> split(ReportRequest reportRequest){
return reportRequest.getSectionRequests();
}

}

Чтобы подключить компонент с Apache Camel:

<bean id="sectionRequestSplitterBean" class="org.bk.report.si.SectionRequestSplitter" />

from("direct:start")
.split().method("sectionRequestSplitterBean", "split")
....

Далее, чтобы преобразовать Запрос Раздела в формат XML, снова это точно так же, как реализация для Spring Integration, с ловушкой, предоставляемой следующим образом:

......
.transform().method("sectionRequestToXMLBean", "transform")
......

Чтобы отправить XML-запрос через http с помощью XML-запроса раздела в службу раздела:

......
.transform().method("sectionRequestToXMLBean", "transform")
.to(serviceURL)
.........

Чтобы преобразовать XML ответа секции в объект секции, компонент точно такой же, как тот, который используется в Spring Integration, со следующим выделенным хуком на маршруте Camel:

......
.transform().method("sectionResponseXMLToSectionBean", "transform");

Чтобы объединить ответы Раздела в отчет, этот компонент немного сложнее, чем Spring Integration. Apache Camel поддерживает шаблон Scatter / Gather, используя маршрут следующего типа:

......
.split().method("sectionRequestSplitterBean", "split")
.aggregationStrategy(new ReportAggregationStrategy())

с передачей стратегии агрегации в Splitter, реализация стратегии агрегации выглядит следующим образом:

public class ReportAggregationStrategy implements AggregationStrategy {
@Override
public Exchange aggregate(Exchange oldExchange, Exchange newExchange) {
if (oldExchange == null) {
Section section = newExchange.getIn().getBody(Section.class);
Report report = new Report();
report.addSection(section);
newExchange.getIn().setBody(report);
return newExchange;
}

Report report = oldExchange.getIn().getBody(Report.class);
Section section = newExchange.getIn().getBody(Section.class);
report.addSection(section);
oldExchange.getIn().setBody(report);
return oldExchange;

}
}

Это завершает реализацию на основе Apache Camel. В статье приведен рабочий образец для Camel — просто скачайте, распакуйте и запустите «mvn test».

Вывод:

Spring Integration и Apache Camel обеспечивают простой и понятный подход к проблемам интеграции в типичном предприятии. Это легковесные фреймворки — Spring Integration основывается на портфеле Spring и расширяет привычную модель программирования для домена Integration и легко выбирается; Apache camel предоставляет хороший DSL на основе Java и хорошо интегрируется с Spring Core, с довольно щадящим обучением кривая. Статья не рекомендует один продукт по сравнению с другим, но призывает читателя оценить и изучить обе эти основы.

Рекомендации:

Веб-сайт Spring Integration: http://www.springsource.org/spring-integration
Веб-сайт

Apache Camel:
http://camel.apache.org/

Справочник по интеграции Spring:
http://static.springsource.org/spring-integration/reference /htmlsingle/spring-integration-reference.html

Руководство пользователя Apache Camel:
http://camel.apache.org/user-guide.html

Плагин для моего блога:
http://biju-allandsundry.blogspot.com/