«1. Обзор

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

Эти мосты между сервисами и технологиями называются маршрутами. Маршруты реализованы на движке (CamelContext) и взаимодействуют с так называемыми «сообщениями обмена».

2. Зависимости Maven

Для начала нам нужно включить зависимости для Spring Boot, Camel, Rest API с Swagger и JSON:

<dependencies>
    <dependency>
        <groupId>org.apache.camel</groupId>
        <artifactId>camel-servlet-starter</artifactId>
        <version>${camel.version}</version>
    </dependency>
    <dependency>
        <groupId>org.apache.camel</groupId>
        <artifactId>camel-jackson-starter</artifactId>
        <version>${camel.version}</version>
    </dependency>
    <dependency>
        <groupId>org.apache.camel</groupId>
        <artifactId>camel-swagger-java-starter</artifactId>
        <version>${camel.version}</version>
    </dependency>
    <dependency>
        <groupId>org.apache.camel</groupId>
        <artifactId>camel-spring-boot-starter</artifactId>
        <version>${camel.version}</version>
    </dependency>    
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
        <version>${spring-boot-starter.version}</version>
    </dependency>
</dependencies>

Последние версии зависимостей Apache Camel можно найти здесь.

3. Основной класс

Давайте сначала создадим приложение Spring Boot:

@SpringBootApplication
@ComponentScan(basePackages="com.baeldung.camel")
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

4. Конфигурации Camel для 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

Один из способов начать использовать Camel — зарегистрировать его как сервлет, поэтому он может перехватывать HTTP-запросы и перенаправлять их в наше приложение.

Как упоминалось ранее, начиная с версии Camel 2.18 и ниже, мы можем воспользоваться преимуществами нашего application.yml, создав параметр для нашего конечного URL. Позже он будет внедрен в наш Java-код:

baeldung:
  api:
    path: '/camel'

Вернемся к нашему классу Application. Нам нужно зарегистрировать сервлет Camel в корне нашего контекстного пути, который будет внедрен из ссылки baeldung.api. путь в application.yml при запуске приложения:

@Value("${baeldung.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()

Теперь давайте реализуем вызов метода 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-компонент, тот же самый, который ранее был определен для типа( ) и обработайте его на нашем слое 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 доступно множество других шаблонов интеграции и манипуляций с данными:

    Шаблоны интеграции Camel Руководство пользователя Camel Camel SIMPLE Language ~ ~~»