Выбрать главу

        .subFlowMapping("ODD", sf -> sf .transform(RomanNumbers::toRoman) .handle((i,h) -> { ... })

        )

    )

    .get();

}

Хотя по-прежнему можно объявить AbstractMessageRouter и передать его в router(), в этом примере используется лямбда для определения того, является ли полезная нагрузка сообщения четной или нечетной. Если она четная, то возвращается строковое значение EVEN. Если нечетная, то возвращается ODD.Эти значения затем используются для определения того, какое под-сопоставление будет обрабатывать сообщение.

9.2.5 Разделители

Иногда в потоке интеграции может быть полезно разделить сообщение на несколько сообщений, которые будут обрабатываться независимо. Разделители, как показано на рис.9.6, будут разделять и обрабатывать эти сообщения для вас.

Рис. 9.6 Hазделители разбивают сообщения на два или более отдельных сообщения, которые могут обрабатываться отдельными подпотоками.

Splitter-ы полезны во многих случаях, но есть два основных варианта использования, для которых вы можете использовать сплиттер:

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

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

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

Например, предположим, что вы хотите разделить сообщение, содержащее заказ на покупку, на два сообщения: одно содержит платежную информацию, а другое-список элементов списка. Следующий OrderSplitter сделает работу:

public class OrderSplitter {

    public Collection<Object> splitOrderIntoParts(PurchaseOrder po) 

        ArrayList<Object> parts = new ArrayList<>();

        parts.add(po.getBillingInfo());

        parts.add(po.getLineItems());

        return parts;

    }

}

Затем вы можете объявить bean OrderSplitter как часть потока интеграции, аннотируя его с помощью @Splitter следующим образом:

@Bean

@Splitter(inputChannel="poChannel", outputChannel="splitOrderChannel")

public OrderSplitter orderSplitter() {

    return new OrderSplitter();

}

Здесь заказы на поставку поступают на канал с именем poChannel и делятся на OrderSplitter. Затем каждый элемент в возвращенной коллекции публикуется как отдельное сообщение в потоке интеграции в канал с именем splitOrderChannel. На этом этапе потока вы можете объявить PayloadTypeRouter для маршрутизации платежной информации и позиций в их собственный подпоток:

@Bean

@Router(inputChannel="splitOrderChannel")

public MessageRouter splitOrderRouter() {

    PayloadTypeRouter router = new PayloadTypeRouter();

    router.setChannelMapping(

        BillingInfo.class.getName(), "billingInfoChannel");

    router.setChannelMapping(

        List.class.getName(), "lineItemsChannel");

    return router;

}

Как следует из его названия, PayloadTypeRouter направляет сообщения на разные каналы на основе их типа полезной нагрузки. Здесь сконфигурировано так что, сообщения, чья полезная нагрузка имеет тип BillingInfo, направляются в канал с именем billingInfoChannel для дальнейшей обработки. Что касается позиций, они находятся в коллекции java.util.List; следовательно, вы сопоставили полезные нагрузки типа List для направления на канал с именем lineItemsChannel.

В настоящее время поток разделяется на два подпотока: один, через который проходят объекты BillingInfo, и другой, через который проходит List<LineItem>. Но что, если вы хотите разбить его дальше так, чтобы вместо работы со списком LineItems вы обрабатывали каждый LineItem отдельно? Все, что вам нужно сделать, чтобы разделить список элементов строки на несколько сообщений, по одному для каждой позиции, - это написать метод (не bean-компонент), который аннотируется с помощью @Splitter и возвращает коллекцию LineItems, возможно, что-то вроде этого:

@Splitter(inputChannel="lineItemsChannel", outputChannel="lineItemChannel")

public List<LineItem> lineItemSplitter(List<LineItem> lineItems) {

    return lineItems;

}

Когда сообщение, несущее полезную нагрузку List<LineItem>, поступает в канал с именем lineItemsChannel, оно передается методу lineItemSplitter(). Согласно правилам разделителя, метод должен возвращать коллекцию элементов, подлежащих разделению. В этом случае у вас уже есть коллекция LineItems, поэтому вы просто возвращаете коллекцию напрямую. В результате каждый LineItem в коллекции публикуется в своем собственном сообщении для канала с именем lineItemChannel.