Как стать автором
Обновить

Построение сложных маршрутов в Apache Camel с помощью компонента Direct

Время на прочтение3 мин
Количество просмотров2.3K

Введение

В данной статье я бы хотел раскрыть тему создания сложных маршрутов в Apache Camel с помощью компонента Direct.

Пример задачи

Предположим что перед нами стоит задача создания маршрутов со следующими характеристиками:

  1. Входная точка - REST.

  2. Поддержка throttling или rate limiting политик на входе.

  3. Возможность ветвления запроса в маршруте на основе некоторого условия (header, body и т.д.).

  4. Поддержка throttling или rate limiting политик для каждой из веток маршрута отдельно.

Решение

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

Из документации Apache Camel: “This endpoint can be used to connect existing routes in the same camel context.”

Реализация

Примечание: данная статья проверенно актуальна для Apache Camel версий 3.12-3.19

Создадим класс ComplexRouteBuilder, который является наследником абстрактного класса RouteBuilder и объявим реализацию метода configure().

Примечание: в данном примере метод configure() уже содержит вызовы пошагового построения составного маршрута, а также в первой строчке объявление коллекции для задания значений ветвления.

private static final List<String> CHOICE_ROUTES_NAMES = Arrays.asList("choice_1", "choice_2", "choice_3");

@Override
public void configure() throws Exception {
    defineInitialStep();
    defineThrottlingStep();
    defineChoiceStep();
    defineDestinationStep();
}

Точка входа в маршрут

В качестве точки входа объявим маршрут, слушающий REST запросы по адресу {contextPath}/api/complex_route и передающий сообщение дальше в direct:throttling.

private void defineInitialStep() {
    var firstPartRouteDefinition = rest("/api")
            .get("/complex_route")
            .to("direct:throttling");
}

Ограничение пропускной способности всего маршрута

Для ограничения пропускной способности маршрута объявим промежуточный шаг, на который применим Throttling Policy. Точка входа промежуточного маршрута - direct:throttling, выход - direct:choice.

Так как применение ограничения пропускной способности понадобится более одного раза - вынесем данное действие в отдельный метод.

    private void defineThrottlingStep() {
        var throttlingPartRouteDefinition = from("direct:throttling")
                .to("direct:choice");
        applyThrottlingPolicy(throttlingPartRouteDefinition);
    }
    
    private void applyThrottlingPolicy(RouteDefinition routeDefinition) {
        routeDefinition
                .throttle(10)
                .timePeriodMillis(1000)
                .rejectExecution(true)
                .onException(ThrottlerRejectedExecutionException.class)
                    .to("bean:logger")
                    .handled(true)
                    .process("routeErrorProcessor")
                    .stop()
                .end();
    }

Ветвление маршрута

Маршрут ветвления слушает сообщения из direct:choice и, в данном случае на основании контента в одном из заголовков запроса, перенаправляет их в соответствующий маршрут direct:{choice_route_name}_destination.

private void defineChoiceStep() {
    var choicePartRouteDefinition = from("direct:choice");
    var choiceDefinition = choicePartRouteDefinition.choice();
    CHOICE_ROUTES_NAMES.forEach(o -> {
        Predicate choicePredicate = header(o).isEqualTo(o + " header value");
        choicePartRouteDefinition.choice().when(choicePredicate)
                .to("direct:" + o + "_destination");
    });
    choiceDefinition.endChoice();
}

Точка назначения

Для каждого из вариантов ветвления создадим соответствующий маршрут, ведущий в конечный сервис. Соответственно для этой группы маршрутов точкой входа будет direct:{choice_route_name}_destination, а точкой выхода - http адрес на конечном сервисе.

Также для маршрута из этой группы применим ThrottlingPolicy для соотвествия начальному условию ограничения пропускной способности на каждой ветви (код метода applyThrottlingPolicy приводился выше).

private void defineDestinationStep() {
    CHOICE_ROUTES_NAMES.forEach(o -> {
        var destinationRouteDefinition = from("direct:" + o + "_destination")
                .to("http://localhost:9191/api/v1/test/first?bridgeEndpoint=true&someParam=" + o);
        applyThrottlingPolicy(destinationRouteDefinition);
    });
}

Схема маршрута из примера

Итог

По итогу приведённых действий мы построили довольно комплексный маршрут с большим количеством правил.

Данный подход применим как в сторону упрощения политик и правил так и в сторону их усложения.

Плюсы

  1. Слабая связность объявлений промежуточных маршрутов. Позволяет гибко структурировать код.

  2. Улучшение соответствия кода принципу Single Responsibility. Что может улучшить контроль за его качеством.

  3. Меньшая зависимость от реализации стандартных классов для объявления последовательностей операций.

Минусы

  1. Слабая связность требует большего контроля за соблюдением архитектуры.

  2. Производительность и потребление памяти. На небольших примерах это не так заметно. Но в целом создание промежуточных звеньев-маршрутов требует дополнительной памяти и вычислительной мощности. В каком именно размере и насколько сильно влияет такой подход на производтельность - на данный момент я не знаю.

Спасибо за внимание.

Теги:
Хабы:
Всего голосов 4: ↑3 и ↓1+2
Комментарии3

Публикации

Истории

Работа

Java разработчик
366 вакансий

Ближайшие события

7 – 8 ноября
Конференция byteoilgas_conf 2024
МоскваОнлайн
7 – 8 ноября
Конференция «Матемаркетинг»
МоскваОнлайн
15 – 16 ноября
IT-конференция Merge Skolkovo
Москва
22 – 24 ноября
Хакатон «AgroCode Hack Genetics'24»
Онлайн
28 ноября
Конференция «TechRec: ITHR CAMPUS»
МоскваОнлайн
25 – 26 апреля
IT-конференция Merge Tatarstan 2025
Казань