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 доступны многие другие шаблоны интеграции и манипуляции с данными: