1. Обзор
По своей сути Apache Camel представляет собой механизм интеграции, который, проще говоря, можно использовать для облегчения взаимодействия между широким и разнообразным набором технологий.
Эти мосты между сервисами и технологиями называются маршрутами.
Маршруты реализованы на движке ( CamelContext
) и взаимодействуют с так называемыми «сообщениями обмена».
2. Зависимости Maven
Для начала нам нужно включить зависимости для Spring Boot, Camel, Rest API с Swagger и JSON:
<dependencies>
<dependency>
<groupId>org.apache.camel.springboot</groupId>
<artifactId>camel-servlet-starter</artifactId>
<version>3.15.0</version>
</dependency>
<dependency>
<groupId>org.apache.camel.springboot</groupId>
<artifactId>camel-jackson-starter</artifactId>
<version>3.15.0</version>
</dependency>
<dependency>
<groupId>org.apache.camel.springboot</groupId>
<artifactId>camel-swagger-java-starter</artifactId>
<version>3.15.0</version>
</dependency>
<dependency>
<groupId>org.apache.camel.springboot</groupId>
<artifactId>camel-spring-boot-starter</artifactId>
<version>3.15.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
Последние версии зависимостей Apache Camel можно найти здесь .
3. Основной класс
Давайте сначала создадим приложение Spring Boot
:
@SpringBootApplication
@ComponentScan(basePackages="com.foreach.camel")
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
4. Верблюжьи конфигурации для Spring Boot
Давайте теперь настроим наше приложение с помощью Spring, начиная с файлов конфигурации (свойств).
Например, давайте настроим журнал для нашего приложения в файле application.properties в
src/main/resources
:
logging.config=classpath:logback.xml
camel.springboot.name=MyCamel
server.address=0.0.0.0
management.address=0.0.0.0
management.port=8081
endpoints.enabled = true
endpoints.health.enabled = true
В этом примере показан файл application.properties
, который также устанавливает путь к конфигурации Logback. Установив IP-адрес «0.0.0.0», мы полностью ограничиваем доступ администратора
и управления
на веб-сервере, предоставляемом Spring Boot. Кроме того, мы обеспечиваем необходимый сетевой доступ к конечным точкам наших приложений, а также к конечным точкам проверки работоспособности.
Еще один файл конфигурации — application.yml
. В нем мы добавим некоторые свойства, которые помогут нам вводить значения в наши маршруты приложений:
server:
port: 8080
camel:
springboot:
name: ServicesRest
management:
port: 8081
endpoints:
enabled: false
health:
enabled: true
quickstart:
generateOrderPeriod: 10s
processOrderPeriod: 30s
5 . Настройка верблюжьего сервлета
Один из способов начать использовать Camel — зарегистрировать его как сервлет, чтобы он мог перехватывать HTTP-запросы и перенаправлять их в наше приложение.
Как упоминалось ранее, начиная с версии Camel 2.18 и ниже, мы можем воспользоваться нашим application.yml
, создав параметр для нашего конечного URL. Позже он будет внедрен в наш Java-код:
foreach:
api:
path: '/camel'
Вернемся к нашему классу Application
. Нам нужно зарегистрировать сервлет Camel в корне нашего контекстного пути, который будет внедрен из ссылки foreach.api.path
в application.yml
при запуске приложения:
@Value("${foreach.api.path}")
String contextPath;
@Bean
ServletRegistrationBean servletRegistrationBean() {
ServletRegistrationBean servlet = new ServletRegistrationBean
(new CamelHttpTransportServlet(), contextPath+"/*");
servlet.setName("CamelServlet");
return servlet;
}
Начиная с версии Camel 2.19, эта конфигурация была удалена, так как CamelServlet
по умолчанию имеет значение «/camel»
.
6. Построение маршрута
Давайте начнем создавать маршрут, расширив класс RouteBuilder
от Camel и установив его как @Component
, чтобы процедура сканирования компонентов могла найти его во время инициализации веб-сервера:
@Component
class RestApi extends RouteBuilder {
@Override
public void configure() {
CamelContext context = new DefaultCamelContext();
restConfiguration()...
rest("/api/")...
from("direct:remoteService")...
}
}
В этом классе мы переопределяем метод configure()
из класса Camel RouteBuilder
.
Верблюду всегда нужен экземпляр CamelContext
— основной компонент, в котором хранятся входящие и исходящие сообщения.
В этом простом примере достаточно DefaultCamelContext
, так как он просто связывает сообщения и маршрутизирует их, как служба REST, которую мы собираемся создать.
6.1. Маршрут restConfiguration(
)
Затем мы создаем объявление REST для конечных точек, которые мы планируем создать в методе restConfiguration()
:
restConfiguration()
.contextPath(contextPath)
.port(serverPort)
.enableCORS(true)
.apiContextPath("/api-doc")
.apiProperty("api.title", "Test REST API")
.apiProperty("api.version", "v1")
.apiContextRouteId("doc-api")
.component("servlet")
.bindingMode(RestBindingMode.json)
Здесь мы регистрируем контекстный путь с нашим внедренным атрибутом из файла YAML. Та же логика была применена к порту нашего приложения. CORS включен, что позволяет использовать эту веб-службу на нескольких сайтах. Режим привязки разрешает и преобразует аргументы в наш API.
Затем мы добавляем документацию Swagger к URI, заголовку и версии, которые мы ранее установили. По мере создания методов/конечных точек для нашей веб-службы REST документация Swagger будет автоматически обновляться.
Этот контекст Swagger сам по себе является маршрутом Camel, и мы можем увидеть некоторую техническую информацию о нем в журнале сервера во время процесса запуска. Наш пример документации по умолчанию находится по адресу http://localhost:8080/camel/api-doc.
6.2. Остальные ()
Маршрут
Теперь давайте реализуем вызов метода rest()
из метода configure()
, указанного выше:
rest("/api/")
.id("api-route")
.consumes("application/json")
.post("/bean")
.bindingMode(RestBindingMode.json_xml)
.type(MyBean.class)
.to("direct:remoteService");
Этот метод довольно прост для тех, кто знаком с API. Идентификатор — это идентификация
маршрута внутри CamelContext
. Следующая строка определяет тип MIME. Режим привязки определен здесь, чтобы показать, что мы можем установить режим в restConfiguration()
.
Метод post()
добавляет в API операцию, генерирующую конечную точку « POST/bean
», а MyBean
(обычный Java-бин с целочисленным идентификатором
и строковым именем
) определяет ожидаемые параметры.
Точно так же действия HTTP, такие как GET, PUT и DELETE, также доступны в форме get()
, put()
, delete()
.
Наконец, метод to()
создает мост к другому маршруту. Здесь он говорит Camel искать внутри своего контекста/движка другой маршрут, который мы собираемся создать, названный и обнаруженный по значению/идентификатору « direct: …
», совпадающий с маршрутом, определенным в методе from() .
6.3. Маршрут from()
с функцией transform()
При работе с Camel маршрут получает параметры, а затем конвертирует, преобразовывает и обрабатывает эти параметры. После этого он отправляет эти параметры на другой маршрут, который перенаправляет результат на желаемый выход (файл, базу данных, SMTP-сервер или ответ REST API).
В этой статье мы создаем еще один маршрут только внутри метода configure()
, который мы переопределяем. Это будет маршрут назначения для нашего последнего маршрута to()
:
from("direct:remoteService")
.routeId("direct-route")
.tracing()
.log(">>> ${body.id}")
.log(">>> ${body.name}")
.transform().simple("Hello ${in.body.name}")
.setHeader(Exchange.HTTP_RESPONSE_CODE, constant(200));
Метод from()
следует тем же принципам и имеет многие из тех же методов, что и метод rest()
, за исключением того, что он использует контекстные сообщения Camel. Это причина для параметра « direct-route
», который создает ссылку на вышеупомянутый метод rest().to()
.
Доступны многие другие преобразования , в том числе извлечение в виде примитивов (или объектов) Java и их отправка на уровень сохраняемости. Обратите внимание, что маршруты всегда считываются из входящих сообщений, поэтому связанные маршруты будут игнорировать исходящие сообщения.
Наш пример готов, и мы можем попробовать его:
- Запустите команду приглашения:
mvn spring-boot:run
- Сделайте POST-запрос к
http://localhost:8080/camel/api/bean
с параметрами заголовка:Content-Type: application/json
и полезной нагрузкой{"id": 1, name: "World"}
- Мы должны получить код возврата 201 и ответ:
Hello, World
6.4. ПРОСТОЙ язык сценариев
В этом примере журнал выводится с использованием метода tracing()
. Обратите внимание, что мы использовали заполнители ${} ;
они являются частью языка сценариев, который принадлежит Camel и называется SIMPLE. Он применяется к сообщениям, которыми обмениваются по маршруту, например к телу входящего сообщения.
В нашем примере мы используем SIMPLE для вывода в журнал атрибутов компонента, которые находятся внутри тела сообщения Camel.
Мы также можем использовать его для выполнения простых преобразований, как было показано с помощью метода transform() .
6.5. Маршрут from()
с помощью process()
Давайте сделаем что-нибудь более осмысленное, например, вызовем сервисный уровень для возврата обработанных данных. SIMPLE не предназначен для тяжелой обработки данных, поэтому давайте заменим transform(
) методом process()
:
from("direct:remoteService")
.routeId("direct-route")
.tracing()
.log(">>> ${body.id}")
.log(">>> ${body.name}")
.process(new Processor() {
@Override
public void process(Exchange exchange) throws Exception {
MyBean bodyIn = (MyBean) exchange.getIn().getBody();
ExampleServices.example(bodyIn);
exchange.getIn().setBody(bodyIn);
}
})
.setHeader(Exchange.HTTP_RESPONSE_CODE, constant(200));
Это позволяет нам извлекать данные в bean-компонент, тот же самый, который ранее был определен в методе type()
, и обрабатывать его на нашем уровне ExampleServices
.
Поскольку ранее мы установили для bindingMode()
значение JSON, ответ уже имеет правильный формат JSON, сгенерированный на основе нашего POJO. Это означает, что для класса ExampleServices
:
public class ExampleServices {
public static void example(MyBean bodyIn) {
bodyIn.setName( "Hello, " + bodyIn.getName() );
bodyIn.setId(bodyIn.getId() * 10);
}
}
Тот же HTTP-запрос теперь возвращается с кодом ответа 201 и телом: {“id”: 10”,name”: “Hello, World”}
.
7. Заключение
С помощью нескольких строк кода нам удалось создать относительно законченное приложение. Все зависимости создаются, управляются и запускаются автоматически с помощью одной команды. Более того, мы можем создавать API, связывающие воедино все виды технологий.
Этот подход также очень удобен для контейнеров, что приводит к очень простой серверной среде, которую можно легко реплицировать по запросу. Дополнительные возможности конфигурации можно легко включить в файл конфигурации шаблона контейнера.
Этот пример REST можно найти на GitHub .
Наконец, помимо API-интерфейсов filter()
, process()
, transform()
и marshall()
, в Camel доступно множество других шаблонов интеграции и манипуляций с данными: