SI 的基本接口和编程方法(官方文档摘录)
消息
消息结构
public interface Message<T> {
T getPayload();
MessageHeaders getHeaders();
}
消息头
public final class MessageHeaders implements Map<String, Object>, Serializable {
// ...
}
从消息头读取属性
Object someValue = message.getHeaders().get("someKey");
CustomerId customerId = message.getHeaders().get("customerId", CustomerId.class);
Long timestamp = message.getHeaders().getTimestamp();
只读消息头
- Message
- MessageHeaders.ID
- MessageHeaders.TIMESTAMP
包装成消息的几种方式
- 直接 new
new GenericMessage<T>(T payload);
new GenericMessage<T>(T payload, Map<String, Object> headers)
- 打包成消息
Message<String> message1 = MessageBuilder.withPayload("Hello World!")
.setHeader("foo", "bar")
.build();
- 复制消息
Message<String> message2 = MessageBuilder.fromMessage(message1).build();
- 打包负载 + 复制消息头
Message<String> message3 = MessageBuilder.withPayload("One More Thing!")
.copyHeaders(message1.getHeaders())
.build();
- 设置优先级
Message<Integer> importantMessage = MessageBuilder.withPayload("Hello Tiger!")
.setPriority(5)
.build();
消息通道
最基础的消息通道接口
public interface MessageChannel {
boolean send(Message message);
boolean send(Message message, long timeout);
}
轮询通道
public interface PollableChannel extends MessageChannel {
Message<?> receive();
Message<?> receive(long timeout);
}
订阅通道
public interface SubscribableChannel extends MessageChannel {
boolean subscribe(MessageHandler handler);
boolean unsubscribe(MessageHandler handler);
}
连接两个通道
@BridgeFrom
@Bean
public PollableChannel polled() {
return new QueueChannel();
}
@Bean
@BridgeFrom(value = "polled", poller = @Poller(fixedDelay = "5000", maxMessagesPerPoll = "10"))
public SubscribableChannel direct() {
return new DirectChannel();
}
@BridgeTo
@Bean
@BridgeTo(value = "direct", poller = @Poller(fixedDelay = "5000", maxMessagesPerPoll = "10"))
public PollableChannel polled() {
return new QueueChannel();
}
@Bean
public SubscribableChannel direct() {
return new DirectChannel();
}
BridgeHandler
@Bean
@ServiceActivator(inputChannel = "polled",
poller = @Poller(fixedRate = "5000", maxMessagesPerPoll = "10"))
public BridgeHandler bridge() {
BridgeHandler bridge = new BridgeHandler();
bridge.setOutputChannelName("direct");
return bridge;
}
JavaDSL
@Bean
public IntegrationFlow bridgeFlow() {
return IntegrationFlows.from("polled")
.bridge(e -> e.poller(Pollers.fixedDelay(5000).maxMessagesPerPoll(10)))
.channel("direct")
.get();
}
连接消息源
两种消费者,对应两种通道
- EventDrivenConsumer 从 SubscribableChannel 订阅消息
- PollingConsumer 从 PollableChannel 轮询消息
接入消息系统
- MessageProducerSupport
- MessageSource (通过 SourcePollingChannelAdapter 连接 MessageChannel)
范例:订阅数据源
@Bean
public MessageProducerSupport redisInboundChannelAdapter(RedisConnectionFactory redisConnectionFactory) {
RedisInboundChannelAdapter adapter = new RedisInboundChannelAdapter(redisConnectionFactory);
adapter.setTopics("foo");
return adapter;
}
范例:从消息源轮询数据
@Bean
@InboundChannelAdapter(value = "fooChannel", poller = @Poller(fixedDelay="5000"))
public MessageSource<?> storedProc(DataSource dataSource) {
return new JdbcPollingChannelAdapter(dataSource, "SELECT * FROM foo where status = 0");
}
router
基本的写法:用 JavaDSL 串流程,用 handle() 引用 router 定义方法
@Bean
public IntegrationFlow routerFlow() {
return IntegrationFlows.from("routingChannel")
.route(myCustomRouter())
.get();
}
自定义 router
public AbstractMessageRouter myCustomRouter() {
return new AbstractMessageRouter() {
@Override
protected Collection<MessageChannel> determineTargetChannels(Message<?> message) {
return // determine channel(s) for message
}
};
}
函数式写法
@Bean
public IntegrationFlow routerFlow() {
return IntegrationFlows.from("routingChannel")
.route(String.class, p -> p.contains("foo") ? "fooChannel" : "barChannel")
.get();
}
常用的几种 router
负载类型 router
public PayloadTypeRouter router() {
PayloadTypeRouter router = new PayloadTypeRouter();
router.setChannelMapping(String.class.getName(), "stringChannel");
router.setChannelMapping(Integer.class.getName(), "integerChannel");
return router;
}
头属性 router
public HeaderValueRouter router() {
HeaderValueRouter router = new HeaderValueRouter("testHeader");
router.setChannelMapping("someHeaderValue", "channelA");
router.setChannelMapping("someOtherHeaderValue", "channelB");
return router;
}
表达式 router
public ExpressionEvaluatingRouter router() {
ExpressionEvaluatingRouter router = new ExpressionEvaluatingRouter("payload.paymentType");
router.setChannelMapping("CASH", "cashPaymentChannel");
router.setChannelMapping("CREDIT", "authorizePaymentChannel");
router.setChannelMapping("DEBIT", "authorizePaymentChannel");
return router;
}
函数式写法的表达式 router
@Bean
public IntegrationFlow routerFlow() {
return IntegrationFlows.from("routingChannel")
.route("payload.paymentType", r -> r
.channelMapping("CASH", "cashPaymentChannel")
.channelMapping("CREDIT", "authorizePaymentChannel")
.channelMapping("DEBIT", "authorizePaymentChannel"))
.get();
}
Filter
MessageSelector
public interface MessageSelector {
boolean accept(Message<?> message);
}
使用 MessageSelector 构造 MessageFilter
MessageFilter filter = new MessageFilter(someSelector);
用注解定义一个过滤器
public class PetFilter {
...
@Filter
public boolean dogsOnly(String input) {
...
}
}
Splitter
用注解定义一个 Splitter
@Splitter
List<LineItem> extractItems(Order order) {
return order.getItems()
}
Handler
public interface MessageHandler {
void handleMessage(Message<?> message);
}
MessageGateway
@MessagingGateway
范例:三个入口方法的 Gateway
@MessagingGateway(defaultRequestChannel = "inputC", defaultHeaders = @GatewayHeader(name = "calledMethod", expression="#gatewayMethod.name"))
public interface TestGateway {
@Gateway(requestChannel = "inputA", replyTimeout = 2, requestTimeout = 200)
String echo(String payload);
@Gateway(requestChannel = "inputB", headers = @GatewayHeader(name = "thing1", value="thing2"))
String echoUpperCase(String payload);
String echoViaDefault(String payload);
}
JavaDSL
IntegrationFlows
- transform → Transformer
- filter → Filter
- handle → ServiceActivator
- split → Splitter
- aggregate → Aggregator
- route → Router
- bridge → Bridge
从 Channel 开始流程
@Bean
public IntegrationFlow testFlow1() {
return IntegrationFlows.from("some-channel")
.handle(m -> System.out.println(m)).get();
}
从 Gateway 开始流程
@Bean
public IntegrationFlow testFlow2() {
return IntegrationFlows.from("some-gateway.input")
.handle(m -> System.out.println(m)).get();
}
定义子流程
@Bean
public IntegrationFlow routeFlow() {
return f -> f
.<Integer, Boolean>route(p -> p % 2 == 0,
m -> m.channelMapping("true", "evenChannel")
.subFlowMapping("false", sf ->
sf.<Integer>handle((p, h) -> p * 3)))
.transform(Object::toString)
.channel(c -> c.queue("oddChannel"));
}
开发中的问题
- 怎么看文档 ref & javadoc
- 怎么看范例 xml & annotation & javadsl
spring-integration-samples-master
basic
applications
dsl
-
怎么创建项目
- 创建 Spring Boot 项目
- 添加 @EnableIntegration,启用 si 支持
- 如有必要,添加 @IntegrationComponentScan 或者 @ComponentScan 指定扫描路径
-
风格套路
- 用 Gateway 以 API 方式提供消息系统入口
- JavaDSL 和 Annotation 结合