Spring Integration предоставляет расширение среды Spring для поддержки хорошо известных шаблонов корпоративной интеграции. Он обеспечивает легкий обмен сообщениями в приложениях на базе Spring и поддерживает интеграцию с внешними системами. Одна из важнейших целей Spring Integration — предоставить простую модель для построения поддерживаемых и тестируемых решений для интеграции предприятия.
Основные компоненты :
Сообщение: это универсальная оболочка для любого объекта Java в сочетании с метаданными, используемыми платформой при обработке этого объекта. Он состоит из полезной нагрузки и заголовка (ов). Полезная нагрузка сообщения может быть любым объектом Java, а заголовок сообщения является строкой / картой объектов, содержащей имя и значение заголовка. MessageBuilder используется для создания сообщений, охватывающих полезную нагрузку и заголовки, следующим образом:
import org.springframework.messaging.Message; import org.springframework.messaging.support.MessageBuilder; Message<String> message = MessageBuilder.withPayload("Message Payload") .setHeader("Message_Header1", "Message_Header1_Value") .setHeader("Message_Header2", "Message_Header2_Value") .build();
Канал сообщений. Канал сообщений — это компонент, через который передаются сообщения, поэтому его можно рассматривать как канал между производителем сообщения и потребителем. Производитель отправляет сообщение на канал, а потребитель получает сообщение от канала. Канал сообщений может следовать семантике «точка-точка» или «публикация / подписка». С каналом «точка-точка» самое большее один потребитель может получить каждое сообщение, отправленное на канал. С помощью каналов публикации / подписки несколько подписчиков могут получать каждое сообщение, отправленное на канал. Spring Integration поддерживает оба из них.
В этом примере проекта используются прямой канал и нулевой канал. Прямой канал — это тип канала по умолчанию в Spring Integration и самый простой вариант двухточечного канала. Нулевой канал — это фиктивный канал сообщений, который используется в основном для тестирования и отладки. Он не отправляет сообщение от отправителя получателю, но его метод send всегда возвращает true, а метод receive возвращает нулевое значение. В дополнение к DirectChannel и NullChannel, Spring Integration предоставляет различные реализации каналов сообщений, такие как PublishSubscribeChannel, QueueChannel, PriorityChannel, RendezvousChannel, ExecutorChannel и ScopedChannel.
Конечная точка сообщения: конечная точка сообщения изолирует код приложения от инфраструктуры. Другими словами, это уровень абстракции между кодом приложения и структурой обмена сообщениями.
Главные конечные точки сообщения:
Трансформатор: Трансформатор сообщений отвечает за преобразование содержимого или структуры сообщения и возврат измененного сообщения. Например: его можно использовать для преобразования полезной нагрузки сообщения из одного формата в другой или для изменения значений заголовка сообщения.
Фильтр: Фильтр сообщений определяет, следует ли передавать сообщение в канал сообщений.
Маршрутизатор: Маршрутизатор сообщений решает, какой канал (каналы) должен получить сообщение следующим, если оно доступно.
Разделитель: Разделитель разбивает входящее сообщение на несколько сообщений и отправляет их на соответствующий канал.
Агрегатор: Агрегатор объединяет несколько сообщений в одно сообщение.
Активатор службы: Активатор службы — это общая конечная точка для подключения экземпляра службы к системе обмена сообщениями.
Адаптер канала: Адаптер канала — это конечная точка, которая соединяет канал сообщений с внешней системой. Канальные адаптеры могут быть входящими или исходящими. Конечная точка адаптера входящего канала соединяет внешнюю систему с MessageChannel. Конечная точка адаптера исходящего канала соединяет MessageChannel с внешней системой.
Шлюз обмена сообщениями. Шлюз является точкой входа для системы обмена сообщениями и скрывает API обмена сообщениями от внешней системы. Он двунаправлен, покрывая каналы запроса и ответа.
Также Spring Integration предоставляет различные канальные адаптеры и шлюзы обмена сообщениями (для AMQP, File, Redis, Gemfire, Http, Jdbc, JPA, JMS, RMI, Stream и т. Д.) Для поддержки обмена сообщениями с внешними системами. Пожалуйста, посетите справочную документацию Spring Integration для получения подробной информации.
В следующем примере реализации обмена сообщениями о грузе показано поведение базовых оконечных точек для простоты понимания. Система обмена сообщениями о грузе прослушивает сообщения о грузе из внешней системы с помощью интерфейса CargoGateway. Полученные грузовые сообщения обрабатываются с использованием CargoSplitter, CargoFilter, CargoRouter, CargoTransformer MessageEndpoints. После этого обработанные успешные внутренние и международные грузовые сообщения отправляются в CargoServiceActivator.
Spring Integration системы Cargo Messaging выглядит следующим образом:
Давайте рассмотрим пример внедрения системы обмена сообщениями.
Используемые технологии:
JDK 1.8.0_25
Spring 4.1.2
Spring Integration 4.1.0
Maven 3.2.2
Ubuntu 14.04
Иерархия проекта выглядит следующим образом:
ШАГ 1: Зависимости
Зависимости добавляются в Maven pom.xml.
<properties> <spring.version>4.1.2.RELEASE</spring.version> <spring.integration.version>4.1.0.RELEASE</spring.integration.version> </properties> <dependencies> <!-- Spring 4 dependencies --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${spring.version}</version> </dependency> <!-- Spring Integration dependencies --> <dependency> <groupId>org.springframework.integration</groupId> <artifactId>spring-integration-core</artifactId> <version>${spring.integration.version}</version> </dependency> </dependencies>
ШАГ 2: Грузовой строитель
CargoBuilder создан для создания запросов на груз.
public class Cargo { public enum ShippingType { DOMESTIC, INTERNATIONAL } private final long trackingId; private final String receiverName; private final String deliveryAddress; private final double weight; private final String description; private final ShippingType shippingType; private final int deliveryDayCommitment; private final int region; private Cargo(CargoBuilder cargoBuilder) { this.trackingId = cargoBuilder.trackingId; this.receiverName = cargoBuilder.receiverName; this.deliveryAddress = cargoBuilder.deliveryAddress; this.weight = cargoBuilder.weight; this.description = cargoBuilder.description; this.shippingType = cargoBuilder.shippingType; this.deliveryDayCommitment = cargoBuilder.deliveryDayCommitment; this.region = cargoBuilder.region; } // Getter methods... @Override public String toString() { return "Cargo [trackingId=" + trackingId + ", receiverName=" + receiverName + ", deliveryAddress=" + deliveryAddress + ", weight=" + weight + ", description=" + description + ", shippingType=" + shippingType + ", deliveryDayCommitment=" + deliveryDayCommitment + ", region=" + region + "]"; } public static class CargoBuilder { private final long trackingId; private final String receiverName; private final String deliveryAddress; private final double weight; private final ShippingType shippingType; private int deliveryDayCommitment; private int region; private String description; public CargoBuilder(long trackingId, String receiverName, String deliveryAddress, double weight, ShippingType shippingType) { this.trackingId = trackingId; this.receiverName = receiverName; this.deliveryAddress = deliveryAddress; this.weight = weight; this.shippingType = shippingType; } public CargoBuilder setDeliveryDayCommitment(int deliveryDayCommitment) { this.deliveryDayCommitment = deliveryDayCommitment; return this; } public CargoBuilder setDescription(String description) { this.description = description; return this; } public CargoBuilder setRegion(int region) { this.region = region; return this; } public Cargo build() { Cargo cargo = new Cargo(this); if ((ShippingType.DOMESTIC == cargo.getShippingType()) && (cargo.getRegion() <= 0 || cargo.getRegion() > 4)) { throw new IllegalStateException("Region is invalid! Cargo Tracking Id : " + cargo.getTrackingId()); } return cargo; } }
ШАГ 3: Грузовое сообщение
CargoMessage является родительским классом внутренних и международных грузовых сообщений.
public class CargoMessage { private final Cargo cargo; public CargoMessage(Cargo cargo) { this.cargo = cargo; } public Cargo getCargo() { return cargo; } @Override public String toString() { return cargo.toString(); } }
ШАГ 4: Внутреннее грузовое сообщение
Класс DomesticCargoMessage моделирует сообщения о внутренних грузоперевозках.
public class DomesticCargoMessage extends CargoMessage { public enum Region { NORTH(1), SOUTH(2), EAST(3), WEST(4); private int value; private Region(int value) { this.value = value; } public static Region fromValue(int value) { return Arrays.stream(Region.values()) .filter(region -> region.value == value) .findFirst() .get(); } } private final Region region; public DomesticCargoMessage(Cargo cargo, Region region) { super(cargo); this.region = region; } public Region getRegion() { return region; } @Override public String toString() { return "DomesticCargoMessage [cargo=" + super.toString() + ", region=" + region + "]"; } }
ШАГ 5: Международное грузовое сообщение
InternationalCargoMessage Class моделирует международные грузовые сообщения.
public class InternationalCargoMessage extends CargoMessage { public enum DeliveryOption { NEXT_FLIGHT, PRIORITY, ECONOMY, STANDART } private final DeliveryOption deliveryOption; public InternationalCargoMessage(Cargo cargo, DeliveryOption deliveryOption) { super(cargo); this.deliveryOption = deliveryOption; } public DeliveryOption getDeliveryOption() { return deliveryOption; } @Override public String toString() { return "InternationalCargoMessage [cargo=" + super.toString() + ", deliveryOption=" + deliveryOption + "]"; } }
ШАГ 6: Конфигурация приложения
AppConfiguration — это класс поставщика конфигурации для Spring Container. Он создает каналы сообщений и регистрируется в Spring BeanFactory. Также @EnableIntegration позволяет импортировать конфигурацию интеграции Spring, а @IntegrationComponentScan сканирует определенные компоненты Spring Integration. Оба они пришли с Spring Integration 4.0.
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.integration.annotation.IntegrationComponentScan; import org.springframework.integration.channel.DirectChannel; import org.springframework.integration.config.EnableIntegration; import org.springframework.messaging.MessageChannel; @Configuration @ComponentScan("com.onlinetechvision.integration") @EnableIntegration @IntegrationComponentScan("com.onlinetechvision.integration") public class AppConfiguration { /** * Creates a new cargoGWDefaultRequest Channel and registers to BeanFactory. * * @return direct channel */ @Bean public MessageChannel cargoGWDefaultRequestChannel() { return new DirectChannel(); } /** * Creates a new cargoSplitterOutput Channel and registers to BeanFactory. * * @return direct channel */ @Bean public MessageChannel cargoSplitterOutputChannel() { return new DirectChannel(); } /** * Creates a new cargoFilterOutput Channel and registers to BeanFactory. * * @return direct channel */ @Bean public MessageChannel cargoFilterOutputChannel() { return new DirectChannel(); } /** * Creates a new cargoRouterDomesticOutput Channel and registers to BeanFactory. * * @return direct channel */ @Bean public MessageChannel cargoRouterDomesticOutputChannel() { return new DirectChannel(); } /** * Creates a new cargoRouterInternationalOutput Channel and registers to BeanFactory. * * @return direct channel */ @Bean public MessageChannel cargoRouterInternationalOutputChannel() { return new DirectChannel(); } /** * Creates a new cargoTransformerOutput Channel and registers to BeanFactory. * * @return direct channel */ @Bean public MessageChannel cargoTransformerOutputChannel() { return new DirectChannel(); } }
ШАГ 7: Шлюз обмена сообщениями
Интерфейс CargoGateway предоставляет приложению метод, зависящий от домена. Другими словами, он обеспечивает доступ приложения к системе обмена сообщениями. Также @MessagingGateway поставляется с Spring Integration 4.0 и упрощает создание шлюза в системе обмена сообщениями. Его канал запроса по умолчанию — cargoGWDefaultRequestChannel .
import java.util.List; import org.springframework.integration.annotation.Gateway; import org.springframework.integration.annotation.MessagingGateway; import org.springframework.messaging.Message; import com.onlinetechvision.model.Cargo; @MessagingGateway(name = "cargoGateway", defaultRequestChannel = "cargoGWDefaultRequestChannel") public interface ICargoGateway { /** * Processes Cargo Request * * @param message SI Message covering Cargo List payload and Batch Cargo Id header. * @return operation result */ @Gateway void processCargoRequest(Message<List<Cargo>> message); }
ШАГ 8: Разделитель сообщений
CargoSplitter прослушивает канал cargoGWDefaultRequestChannel и разбивает входящий список грузов на сообщения Cargo. Грузовые сообщения отправляются в cargoSplitterOutputChannel.
import java.util.List; import org.springframework.integration.annotation.MessageEndpoint; import org.springframework.integration.annotation.Splitter; import org.springframework.messaging.Message; import com.onlinetechvision.model.Cargo; @MessageEndpoint public class CargoSplitter { /** * Splits Cargo List to Cargo message(s) * * @param message SI Message covering Cargo List payload and Batch Cargo Id header. * @return cargo list */ @Splitter(inputChannel = "cargoGWDefaultRequestChannel", outputChannel = "cargoSplitterOutputChannel") public List<Cargo> splitCargoList(Message<List<Cargo>> message) { return message.getPayload(); } }
ШАГ 9: Фильтр сообщений
CargoFilter определяет, следует ли передавать сообщение в канал сообщений. Он прослушивает канал cargoSplitterOutputChannel и фильтрует сообщения о грузе, превышающие ограничение по весу. Если сообщение Cargo ниже предела веса, оно отправляется на канал cargoFilterOutputChannel . Если сообщение Cargo превышает лимит веса, оно отправляется на канал cargoFilterDiscardChannel .
import org.springframework.integration.annotation.Filter; import org.springframework.integration.annotation.MessageEndpoint; import com.onlinetechvision.model.Cargo; @MessageEndpoint public class CargoFilter { private static final long CARGO_WEIGHT_LIMIT = 1_000; /** * Checks weight of cargo and filters if it exceeds limit. * * @param Cargo message * @return check result */ @Filter(inputChannel="cargoSplitterOutputChannel", outputChannel="cargoFilterOutputChannel", discardChannel="cargoFilterDiscardChannel") public boolean filterIfCargoWeightExceedsLimit(Cargo cargo) { return cargo.getWeight() <= CARGO_WEIGHT_LIMIT; } }
ШАГ 10: прослушиватель сброшенных грузовых сообщений
DiscardedCargoMessageListener прослушивает канал cargoFilterDiscard и обрабатывает сообщения Cargo, отклоненные CargoFilter.
import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.integration.annotation.MessageEndpoint; import org.springframework.integration.annotation.ServiceActivator; import org.springframework.messaging.handler.annotation.Header; import com.onlinetechvision.model.Cargo; @MessageEndpoint public class DiscardedCargoMessageListener { private final Logger logger = LoggerFactory.getLogger(DiscardedCargoMessageListener.class); /** * Handles discarded domestic and international cargo request(s) and logs. * * @param cargo domestic/international cargo message * @param batchId message header shows cargo batch id */ @ServiceActivator(inputChannel = "cargoFilterDiscardChannel") public void handleDiscardedCargo(Cargo cargo, @Header("CARGO_BATCH_ID") long batchId) { logger.debug("Message in Batch[" + batchId + "] is received with Discarded payload : " + cargo); } }
ШАГ 11: Маршрутизатор сообщений
CargoRouter определяет, какой канал (каналы) должен получить следующее сообщение, если оно доступно. Он прослушивает канал cargoFilterOutputChannel и возвращает название соответствующего канала в зависимости от типа доставки груза. Другими словами, он направляет входящие грузовые сообщения на внутренние ( cargoRouterDomesticOutputChannel ) или международные ( cargoRouterInternationalOutputChannel ) грузовые каналы. Также, если тип доставки не установлен, возвращается nullChannel . nullChannel — это фиктивный канал сообщений, который используется в основном для тестирования и отладки. Он не отправляет сообщение от отправителя получателю, но его метод send всегда возвращает true, а метод receive возвращает нулевое значение.
import org.springframework.integration.annotation.MessageEndpoint; import org.springframework.integration.annotation.Router; import com.onlinetechvision.model.Cargo; import com.onlinetechvision.model.Cargo.ShippingType; @MessageEndpoint public class CargoRouter { /** * Determines cargo request' s channel in the light of shipping type. * * @param Cargo message * @return channel name */ @Router(inputChannel="cargoFilterOutputChannel") public String route(Cargo cargo) { if(cargo.getShippingType() == ShippingType.DOMESTIC) { return "cargoRouterDomesticOutputChannel"; } else if(cargo.getShippingType() == ShippingType.INTERNATIONAL) { return "cargoRouterInternationalOutputChannel"; } return "nullChannel"; } }
ШАГ 12: Обмен сообщениями
CargoTransformer прослушивает cargoRouterDomesticOutputChannel & cargoRouterInternationalOutputChannel и преобразует входящие запросы Cargo в сообщения внутренних и международных грузов. После этого он отправляет их на канал cargoTransformerOutputChannel .
import org.springframework.integration.annotation.MessageEndpoint; import org.springframework.integration.annotation.Transformer; import com.onlinetechvision.model.Cargo; import com.onlinetechvision.model.DomesticCargoMessage; import com.onlinetechvision.model.DomesticCargoMessage.Region; import com.onlinetechvision.model.InternationalCargoMessage; import com.onlinetechvision.model.InternationalCargoMessage.DeliveryOption; @MessageEndpoint public class CargoTransformer { /** * Transforms Cargo request to Domestic Cargo obj. * * @param cargo * request * @return Domestic Cargo obj */ @Transformer(inputChannel = "cargoRouterDomesticOutputChannel", outputChannel = "cargoTransformerOutputChannel") public DomesticCargoMessage transformDomesticCargo(Cargo cargo) { return new DomesticCargoMessage(cargo, Region.fromValue(cargo.getRegion())); } /** * Transforms Cargo request to International Cargo obj. * * @param cargo * request * @return International Cargo obj */ @Transformer(inputChannel = "cargoRouterInternationalOutputChannel", outputChannel = "cargoTransformerOutputChannel") public InternationalCargoMessage transformInternationalCargo(Cargo cargo) { return new InternationalCargoMessage(cargo, getDeliveryOption(cargo.getDeliveryDayCommitment())); } /** * Get delivery option by delivery day commitment. * * @param deliveryDayCommitment delivery day commitment * @return delivery option */ private DeliveryOption getDeliveryOption(int deliveryDayCommitment) { if (deliveryDayCommitment == 1) { return DeliveryOption.NEXT_FLIGHT; } else if (deliveryDayCommitment == 2) { return DeliveryOption.PRIORITY; } else if (deliveryDayCommitment > 2 && deliveryDayCommitment < 5) { return DeliveryOption.ECONOMY; } else { return DeliveryOption.STANDART; } } }
ШАГ 13: Активатор службы сообщений
CargoServiceActivator — это общая конечная точка для подключения экземпляра службы к системе обмена сообщениями. Он прослушивает канал cargoTransformerOutputChannel и получает обработанные внутренние и международные грузовые сообщения и журналы.
import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.integration.annotation.MessageEndpoint; import org.springframework.integration.annotation.ServiceActivator; import org.springframework.messaging.handler.annotation.Header; import com.onlinetechvision.model.CargoMessage; @MessageEndpoint public class CargoServiceActivator { private final Logger logger = LoggerFactory.getLogger(CargoServiceActivator.class); /** * Gets processed domestic and international cargo request(s) and logs. * * @param cargoMessage domestic/international cargo message * @param batchId message header shows cargo batch id */ @ServiceActivator(inputChannel = "cargoTransformerOutputChannel") public void getCargo(CargoMessage cargoMessage, @Header("CARGO_BATCH_ID") long batchId) { logger.debug("Message in Batch[" + batchId + "] is received with payload : " + cargoMessage); } }
ШАГ 14: Применение
Класс приложения создан для запуска приложения. Он инициализирует контекст приложения и отправляет запросы на груз в систему обмена сообщениями.
import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.messaging.support.MessageBuilder; import com.onlinetechvision.integration.ICargoGateway; import com.onlinetechvision.model.Cargo; import com.onlinetechvision.model.Cargo.ShippingType; public class Application { public static void main(String[] args) { ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfiguration.class); ICargoGateway orderGateway = ctx.getBean(ICargoGateway.class); getCargoBatchMap().forEach( (batchId, cargoList) -> orderGateway.processCargoRequest(MessageBuilder .withPayload(cargoList) .setHeader("CARGO_BATCH_ID", batchId) .build())); } /** * Creates a sample cargo batch map covering multiple batches and returns. * * @return cargo batch map */ private static Map<Integer, List<Cargo>> getCargoBatchMap() { Map<Integer, List<Cargo>> cargoBatchMap = new HashMap<>(); cargoBatchMap.put(1, Arrays.asList( new Cargo.CargoBuilder(1, "Receiver_Name1", "Address1", 0.5, ShippingType.DOMESTIC) .setRegion(1).setDescription("Radio").build(), //Second cargo is filtered due to weight limit new Cargo.CargoBuilder(2, "Receiver_Name2", "Address2", 2_000, ShippingType.INTERNATIONAL) .setDeliveryDayCommitment(3).setDescription("Furniture").build(), new Cargo.CargoBuilder(3, "Receiver_Name3", "Address3", 5, ShippingType.INTERNATIONAL) .setDeliveryDayCommitment(2).setDescription("TV").build(), //Fourth cargo is not processed due to no shipping type found new Cargo.CargoBuilder(4, "Receiver_Name4", "Address4", 8, null) .setDeliveryDayCommitment(2).setDescription("Chair").build())); cargoBatchMap.put(2, Arrays.asList( //Fifth cargo is filtered due to weight limit new Cargo.CargoBuilder(5, "Receiver_Name5", "Address5", 1_200, ShippingType.DOMESTIC) .setRegion(2).setDescription("Refrigerator").build(), new Cargo.CargoBuilder(6, "Receiver_Name6", "Address6", 20, ShippingType.DOMESTIC) .setRegion(3).setDescription("Table").build(), //Seventh cargo is not processed due to no shipping type found new Cargo.CargoBuilder(7, "Receiver_Name7", "Address7", 5, null) .setDeliveryDayCommitment(1).setDescription("TV").build())); cargoBatchMap.put(3, Arrays.asList( new Cargo.CargoBuilder(8, "Receiver_Name8", "Address8", 200, ShippingType.DOMESTIC) .setRegion(2).setDescription("Washing Machine").build(), new Cargo.CargoBuilder(9, "Receiver_Name9", "Address9", 4.75, ShippingType.INTERNATIONAL) .setDeliveryDayCommitment(1).setDescription("Document").build())); return Collections.unmodifiableMap(cargoBatchMap); } }
ШАГ 15: Построить проект
Результаты работы с запросами на груз:
Груз 1: успешно отправлен активатору сервиса.
Груз 2: фильтруется по весу.
Карго 3: успешно отправлено активатору сервиса.
Груз 4: не обрабатывается из-за отсутствия типа доставки.
Груз 5: фильтруется по весу.
Груз 6: успешно отправлен активатору сервиса.
Груз 7: не обрабатывается из-за отсутствия типа доставки.
Карго 8: отправлено активатору сервиса успешно.
Груз 9: успешно отправлен активатору сервиса.
После того, как проект собран и запущен, будут видны следующие журналы вывода консоли:
2014-12-09 23:43:51 [main] DEBUG c.o.i.CargoServiceActivator - Message in Batch[1] is received with payload : DomesticCargoMessage [cargo=Cargo [trackingId=1, receiverName=Receiver_Name1, deliveryAddress=Address1, weight=0.5, description=Radio, shippingType=DOMESTIC, deliveryDayCommitment=0, region=1], region=NORTH] 2014-12-09 23:43:51 [main] DEBUG c.o.i.DiscardedCargoMessageListener - Message in Batch[1] is received with Discarded payload : Cargo [trackingId=2, receiverName=Receiver_Name2, deliveryAddress=Address2, weight=2000.0, description=Furniture, shippingType=INTERNATIONAL, deliveryDayCommitment=3, region=0] 2014-12-09 23:43:51 [main] DEBUG c.o.i.CargoServiceActivator - Message in Batch[1] is received with payload : InternationalCargoMessage [cargo=Cargo [trackingId=3, receiverName=Receiver_Name3, deliveryAddress=Address3, weight=5.0, description=TV, shippingType=INTERNATIONAL, deliveryDayCommitment=2, region=0], deliveryOption=PRIORITY] 2014-12-09 23:43:51 [main] DEBUG c.o.i.DiscardedCargoMessageListener - Message in Batch[2] is received with Discarded payload : Cargo [trackingId=5, receiverName=Receiver_Name5, deliveryAddress=Address5, weight=1200.0, description=Refrigerator, shippingType=DOMESTIC, deliveryDayCommitment=0, region=2] 2014-12-09 23:43:51 [main] DEBUG c.o.i.CargoServiceActivator - Message in Batch[2] is received with payload : DomesticCargoMessage [cargo=Cargo [trackingId=6, receiverName=Receiver_Name6, deliveryAddress=Address6, weight=20.0, description=Table, shippingType=DOMESTIC, deliveryDayCommitment=0, region=3], region=EAST] 2014-12-09 23:43:51 [main] DEBUG c.o.i.CargoServiceActivator - Message in Batch[3] is received with payload : DomesticCargoMessage [cargo=Cargo [trackingId=8, receiverName=Receiver_Name8, deliveryAddress=Address8, weight=200.0, description=Washing Machine, shippingType=DOMESTIC, deliveryDayCommitment=0, region=2], region=SOUTH] 2014-12-09 23:43:51 [main] DEBUG c.o.i.CargoServiceActivator - Message in Batch[3] is received with payload : InternationalCargoMessage [cargo=Cargo [trackingId=9, receiverName=Receiver_Name9, deliveryAddress=Address9, weight=4.75, description=Document, shippingType=INTERNATIONAL, deliveryDayCommitment=1, region=0], deliveryOption=NEXT_FLIGHT]
Исходный код
Исходный код доступен на Github
Ссылки
Шаблоны корпоративной интеграции
Spring Integration Справочное руководство
Spring Integration 4.1.0.RELEASE API
Pro Spring Integration Выпуск
Spring Integration 3.0.2 и 4.0 Milestone 4