javascript
使用Spring Integration进行消息处理
Spring Integration提供了Spring框架的擴展,以支持著名的企業集成模式。 它在基于Spring的應用程序中啟用輕量級消息傳遞,并支持與外部系統的集成。 Spring Integration的最重要目標之一是為構建可維護且可測試的企業集成解決方案提供一個簡單的模型。
主要成分
消息:它是任何Java對象的通用包裝器,與處理該對象時框架使用的元數據結合在一起。 它由有效負載和標頭組成。 消息有效負載可以是任何Java對象,消息頭是字符串/對象映射,覆蓋頭名稱和值。 MessageBuilder用于創建覆蓋有效載荷和標頭的消息,如下所示:
import org.springframework.messaging.Message; import org.springframework.messaging.support.MessageBuilder;Message 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方法返回null值。 除了DirectChannel和NullChannel,Spring Integration還提供了不同的消息通道實現,例如PublishSubscribeChannel,QueueChannel,PriorityChannel,RendezvousChannel,ExecutorChannel和ScopedChannel。
消息端點:消息端點將應用程序代碼與基礎結構隔離。 換句話說,它是應用程序代碼和消息傳遞框架之間的抽象層。
主要消息端點
轉換程序:消息轉換程序負責轉換消息的內容或結構并返回修改后的消息。 例如:它可用于將消息有效負載從一種格式轉換為另一種格式或修改消息頭值。
過濾器:消息過濾器確定是否將消息傳遞到消息通道。
路由器:消息路由器決定哪個信道(如果可用)接下來應接收消息。
拆分器:拆分器將傳入的消息分解為多個消息,并將其發送到適當的通道。
聚合器:聚合器將多個消息組合為單個消息。
服務激活器:服務激活器是用于將服務實例連接到消息傳遞系統的通用端點。
通道適配器:通道適配器是將消息通道連接到外部系統的端點。 通道適配器可以是入站的或出站的。 入站通道適配器端點將外部系統連接到MessageChannel。 出站通道適配器端點將MessageChannel連接到外部系統。
消息傳遞網關:網關是消息傳遞系統的入口,它對外部系統隱藏消息傳遞API。 通過覆蓋請求和回復通道,它是雙向的。
Spring Integration還提供了各種通道適配器和消息傳遞網關(用于AMQP,文件,Redis,Gemfire,Http,Jdbc,JPA,JMS,RMI,Stream等),以支持與外部系統的基于消息的通信。 請訪問Spring Integration Reference文檔以獲取詳細信息。
以下示例貨物消息傳遞實現顯示了易于理解的基本消息端點的行為。 貨運信息系統通過使用CargoGateway接口監聽來自外部系統的貨運信息。 通過使用CargoSplitter,CargoFilter,CargoRouter,CargoTransformer MessageEndpoints處理收到的貨物消息。 之后,已處理的成功的國內和國際貨運消息將發送到CargoServiceActivator。
貨物信息系統的Spring整合流程如下:
讓我們看一下示例貨物消息傳遞實現。
二手技術
- JDK 1.8.0_25
- 春天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...@Overridepublic 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;}@Overridepublic 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;}@Overridepublic String toString() {return "DomesticCargoMessage [cargo=" + super.toString() + ", region=" + region + "]";}}步驟5:國際貨運訊息
InternationalCargoMessage類模擬國際貨運消息。
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;}@Overridepublic String toString() {return "InternationalCargoMessage [cargo=" + super.toString() + ", deliveryOption=" + deliveryOption + "]";}}步驟6:應用程序配置
AppConfiguration是Spring容器的配置提供程序類。 它創建消息通道并注冊到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*/@Beanpublic MessageChannel cargoGWDefaultRequestChannel() {return new DirectChannel();}/*** Creates a new cargoSplitterOutput Channel and registers to BeanFactory.** @return direct channel*/@Beanpublic MessageChannel cargoSplitterOutputChannel() {return new DirectChannel();}/*** Creates a new cargoFilterOutput Channel and registers to BeanFactory.** @return direct channel*/@Beanpublic MessageChannel cargoFilterOutputChannel() {return new DirectChannel();}/*** Creates a new cargoRouterDomesticOutput Channel and registers to BeanFactory.** @return direct channel*/@Beanpublic MessageChannel cargoRouterDomesticOutputChannel() {return new DirectChannel();}/*** Creates a new cargoRouterInternationalOutput Channel and registers to BeanFactory.** @return direct channel*/@Beanpublic MessageChannel cargoRouterInternationalOutputChannel() {return new DirectChannel();}/*** Creates a new cargoTransformerOutput Channel and registers to BeanFactory.** @return direct channel*/@Beanpublic MessageChannel cargoTransformerOutputChannel() {return new DirectChannel();}}STEP 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*/@Gatewayvoid processCargoRequest(Message<List<Cargo>> message); }步驟8:郵件分割器
CargoSplitter偵聽cargoGWDefaultRequestChannel通道并將傳入的“貨物清單”分解為“貨物”消息。 貨物消息被發送到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通道并過濾超出重量限制的貨物消息。 如果貨運消息低于重量限制,則將其發送到cargoFilterOutputChannel通道。 如果貨運消息高于重量限制,則將其發送到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通道并處理由CargoFilter丟棄的Cargo消息。
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方法返回null值。
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并將傳入的貨運請求轉換為國內和國際貨運消息。 之后,它將它們發送到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 limitnew 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 foundnew 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集成參考手冊
- Spring Integration 4.1.0.RELEASE API
- Pro Spring整合
- Spring Integration 3.0.2和4.0 Milestone 4發布
翻譯自: https://www.javacodegeeks.com/2014/12/message-processing-with-spring-integration.html
總結
以上是生活随笔為你收集整理的使用Spring Integration进行消息处理的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 安卓桌面锁屏怎么设置(安卓桌面锁)
- 下一篇: 如何在没有Springockito的情况