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

9.2.3 Трансформаторы

Трансформаторы выполняют некоторые операции над сообщениями, обычно приводя к другому сообщению и, возможно, с другим типом полезной нагрузки (см. рис.9.4). Преобразование может быть чем-то простым, например, выполнение математических операций над числом или манипулирование строковым значением.  Или преобразование может быть более сложным,например, использование строкового значения, представляющего ISBN, для поиска и возврата сведений о соответствующей книге.

Рисунок 9.4 Трансформаторы преобразуют сообщения по мере их прохождения через поток интеграции.

Например, предположим, что целочисленные значения публикуются на канале с именем numberChannel, и вы хотите преобразовать эти числа в String, содержащую Римский числовой эквивалент.  В этом случае вы можете объявить bean GenericTransformer и аннотировать его с помощью @Transformer следующим образом:

@Bean

@Transformer(inputChannel="numberChannel", outputChannel="romanNumberChannel")

public GenericTransformer<Integer, String> romanNumTransformer() {

    return RomanNumbers::toRoman;

}

Аннотация @Transformer определяет этот компонент как компонент transformer, который получает целочисленные значения из канала с именем numberChannel и использует статический метод с именем toRoman() для выполнения преобразования. (Метод toRoman () статически определен в классе с именем RomanNumbers и ссылается здесь со ссылкой на метод) Результат будет опубликован на канале с именем romanNumberChannel.

В стиле конфигурации Java DSL еще проще с вызовом transform(), передавая ссылку на метод toRoman():

@Bean

public IntegrationFlow transformerFlow() {

    return IntegrationFlows

        …

        .transform(RomanNumbers::toRoman)

        …

        .get();

}

Хотя вы использовали ссылку на метод в обоих примерах кода преобразователя, знайте, что преобразователь также можно указать как лямбду. Или, если преобразователь достаточно сложен, чтобы потребовался отдельный класс Java, вы можете внедрить его как bean-компонент в конфигурацию потока и передать ссылку на метод transform():

@Bean

public RomanNumberTransformer romanNumberTransformer() {

    return new RomanNumberTransformer();

}

@Bean

public IntegrationFlow transformerFlow( RomanNumberTransformer romanNumberTransformer) {

    return IntegrationFlows

        …

        .transform(romanNumberTransformer)

        …

        .get();

}

Здесь вы объявляете bean-компонент типа RomanNumberTransformer, который сам является реализацией Spring Integration Transformer или интерфейса GenericTransformer. Bean внедряется в метод transformerFlow() и передается в метод transform() при определении потока интеграции.

9.2.4 Маршрутизаторы

Маршрутизаторы, основанные на некоторых критериях маршрутизации, позволяют разветвляться в потоке интеграции,направляя сообщения в разные каналы (см. рисунок 9.5).

Рис. 9.5 Маршрутизаторы направляют сообщения в различные каналы на основе некоторых критериев, применяемых к сообщениям.

Например, предположим, что у вас есть канал с именем numberChannel, через который проходят целочисленные значения. Допустим, вы хотите направить все сообщения с четными номерами в канал с именем evenChannel, а сообщения с нечетными номерами направляются в канал с именем oddChannel. Чтобы создать такую маршрутизацию в потоке интеграции, вы можете объявить bean-компонент типа AbstractMessageRouter и аннотировать bean-компонент с помощью @Router:

@Bean

@Router(inputChannel="numberChannel")

public AbstractMessageRouter evenOddRouter() {

    return new AbstractMessageRouter() {

        @Override

        protected Collection<MessageChannel>

                determineTargetChannels(Message<?> message) {

            Integer number = (Integer) message.getPayload();

            if (number % 2 == 0) {

                return Collections.singleton(evenChannel());

            } 

            return Collections.singleton(oddChannel());

        }

    };

}

 

@Bean

public MessageChannel evenChannel() {

    return new DirectChannel();

}

@Bean

public MessageChannel oddChannel() {

    return new DirectChannel();

}

Объявленный здесь bean AbstractMessageRouter принимает сообщения от входного канала с именем numberChannel.  Реализация, определенная как анонимный внутренний класс, проверяет полезную нагрузку сообщения и, если это четное число, возвращает канал с именем evenChannel (объявленный как bean). В противном случае число в полезной нагрузке канала должно быть нечетным; в этом случае возвращается канал с именем oddChannel (также созданный как bean).

В Java DSL маршрутизаторы объявляются путем вызова route() в ходе определения потока, как показано ниже:

@Bean

public IntegrationFlow numberRoutingFlow(AtomicInteger source) {

    return IntegrationFlows

        …

        .<Integer, String>route(n -> n%2==0 ? "EVEN":"ODD", mapping -> mapping    

        .subFlowMapping("EVEN", sf -> sf .<Integer, Integer>transform(n -> n * 10)

        .handle((i,h) -> { ... })

        )