Apache Camel с весенней загрузкой

Apache Camel с весенней загрузкой

1. обзор

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

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

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

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


    
        org.apache.camel
        camel-servlet-starter
        ${camel.version}
    
    
        org.apache.camel
        camel-jackson-starter
        ${camel.version}
    
    
        org.apache.camel
        camel-swagger-java-starter
        ${camel.version}
    
    
        org.apache.camel
        camel-spring-boot-starter
        ${camel.version}
    
    
        org.springframework.boot
        spring-boot-starter-web
        ${spring-boot-starter.version}
    

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

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

Давайте сначала создадим Spring BootApplication:

@SpringBootApplication
@ComponentScan(basePackages="com.example.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», мы полностью ограничиваем доступadmin иmanagement на веб-сервере, предоставляемом 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. Setting up the Camel Servletс

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

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

example:
  api:
    path: '/camel'

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

@Value("${example.api.path}")
String contextPath;

@Bean
ServletRegistrationBean servletRegistrationBean() {
    ServletRegistrationBean servlet = new ServletRegistrationBean
      (new CamelHttpTransportServlet(), contextPath+"/*");
    servlet.setName("CamelServlet");
    return servlet;
}

Начиная с версии 2.19 Camel, эта конфигурация была удалена, так как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() из классаRouteBuilder Camel.

Camel always needs a CamelContext instance - основной компонент, в котором хранятся входящие и исходящие сообщения.

В этом простом примере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 сам по себе является верблюжьим маршрутом, и мы можем увидеть некоторую техническую информацию о нем в журнале сервера во время процесса запуска. Документация нашего примера по умолчанию обслуживается в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. id - это идентификация маршрута внутриCamelContext. Следующая строка определяет тип MIME. Режим привязки определяется здесь, чтобы показать, что мы можем установить режим дляrestConfiguration().

Методpost() добавляет операцию к API, генерируя конечную точку «POST /bean», в то время какMyBean (обычный компонент Java сInteger id иString name ) определяет ожидаемые параметры.

Точно так же HTTP-действия, такие как GET, PUT и DELETE, также доступны в формеget(),put(),delete().

Наконец, методto() создает мост к другому маршруту. Здесь он сообщает Camel искать внутри своего контекста / движка другой маршрут, который мы собираемся создать - который назван и обнаружен значением / id «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().

Many other conversions are available, включая извлечение в виде примитивов (или объектов) 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 можно найти вover on GitHub.

Наконец, помимо APIfilter(),process(),transform() иmarshall(), в Camel доступны многие другие шаблоны интеграции и манипуляции с данными: