这是个好问题,也是个好主意.但它不会那么容易.
首先,我们必须自己确定网关意味着请求/回复,因此相关性.这可以在@MessagingGateway中通过面向TemporaryReplyChannel实例的replyChannel头文件获得.即使您有明确的replyChannel = AccountChannels.ACCOUNT_CREATED,也只能通过提到的标头及其值进行关联.事实上,此TemporaryReplyChannel不可序列化,无法通过网络传输到另一方的消费者.
幸运的是,Spring Integration为我们提供了一些解决方案.它是HeaderEnricher及其HeaderChannelRegistry后面的headerChannelsToString选项的一部分:
Starting with Spring Integration 3.0, a new sub-element is available; it has no attributes. This converts existing replyChannel and errorChannel headers (when they are a MessageChannel) to a String and stores the channel(s) in a registry for later resolution when it is time to send a reply, or handle an error. This is useful for cases where the headers might be lost; for example when serializing a message into a message store or when transporting the message over JMS. If the header does not already exist, or it is not a MessageChannel, no changes are made.
但在这种情况下,您必须引入从网关到HeaderEnricher的内部通道,只有最后一个通道会将消息发送到AccountChannels.CREATE_ACCOUNT_REQUEST.因此,replyChannel标头将转换为字符串表示,并能够通过网络传输.在消费者方面,当您发送回复时,您应该确保转移该replyChannel标头,就像它一样.因此,当消息将到达生产者端的AccountChannels.ACCOUNT_CREATED时,我们有@MessagingGateway,相关机制能够将信道标识符转换为适当的TemporaryReplyChannel,并将回复与等待网关调用相关联.
这里只有您的生产者应用程序必须作为AccountChannels.ACCOUNT_CREATED组中的单个使用者的问题 – 我们必须确保云中只有一个实例一次运行.仅仅因为只有一个实例在其内存中具有TemporaryReplyChannel.
UPDATE
一些帮助代码:
@EnableBinding(AccountChannels.class)
@MessagingGateway
public interface AccountService {
@Gateway(requestChannel = AccountChannels.INTERNAL_CREATE_ACCOUNT_REQUEST, replyChannel = AccountChannels.ACCOUNT_CREATED, replyTimeout = 60000, requestTimeout = 60000)
Account createAccount(@Payload Account account, @Header("Authorization") String authorization);
}
@Bean
public IntegrationFlow headerEnricherFlow() {
return IntegrationFlows.from(AccountChannels.INTERNAL_CREATE_ACCOUNT_REQUEST)
.enrichHeaders(headerEnricher -> headerEnricher.headerChannelsToString())
.channel(AccountChannels.CREATE_ACCOUNT_REQUEST)
.get();
}
UPDATE
一些简单的应用程序来演示PoC:
@EnableBinding({ Processor.class, CloudStreamGatewayApplication.GatewayChannels.class })
@SpringBootApplication
public class CloudStreamGatewayApplication {
interface GatewayChannels {
String REQUEST = "request";
@Output(REQUEST)
MessageChannel request();
String REPLY = "reply";
@Input(REPLY)
SubscribableChannel reply();
}
private static final String ENRICH = "enrich";
@MessagingGateway
public interface StreamGateway {
@Gateway(requestChannel = ENRICH, replyChannel = GatewayChannels.REPLY)
String process(String payload);
}
@Bean
public IntegrationFlow headerEnricherFlow() {
return IntegrationFlows.from(ENRICH)
.enrichHeaders(HeaderEnricherSpec::headerChannelsToString)
.channel(GatewayChannels.REQUEST)
.get();
}
@StreamListener(Processor.INPUT)
@SendTo(Processor.OUTPUT)
public Message> process(Message request) {
return MessageBuilder.withPayload(request.getPayload().toUpperCase())
.copyHeaders(request.getHeaders())
.build();
}
public static void main(String[] args) {
ConfigurableApplicationContext applicationContext =
SpringApplication.run(CloudStreamGatewayApplication.class, args);
StreamGateway gateway = applicationContext.getBean(StreamGateway.class);
String result = gateway.process("foo");
System.out.println(result);
}
}
application.yml:
spring:
cloud:
stream:
bindings:
input:
destination: requests
output:
destination: replies
request:
destination: requests
reply:
destination: replies
我使用spring-cloud-starter-stream-rabbit.
该
MessageBuilder.withPayload(request.getPayload().toUpperCase())
.copyHeaders(request.getHeaders())
.build()
技巧是否将请求标头复制到回复消息.因此,网关能够在回复侧将报头中的信道标识符转换为适当的TemporaryReplyChannel,以将回复正确地传送给网关的呼叫者.