[英]Using Spring Integration DSL, how do I configure I/O between different integrations?
I have a Spring Boot application, and I'm trying to connect two different Spring Integration services together.我有一个 Spring 引导应用程序,我正在尝试将两个不同的 Spring 集成服务连接在一起。 I have a WebSocket listener, and a TCP listener defined using the available DSL examples for those two integrations.我有一个 WebSocket 侦听器和一个 TCP 侦听器,使用这两个集成的可用 DSL 示例定义。
However, I have been unable to find documentation on how to bridge them together.但是,我一直无法找到有关如何将它们连接在一起的文档。 In other words, when a WebSocket connection is opened by a browser client, and an incoming TCP connection is accepted from another system, I simply want to blindly pass all input and output from one to the other, in a bidirectional capacity.换句话说,当浏览器客户端打开 WebSocket 连接,并从另一个系统接受传入的 TCP 连接时,我只是想盲目地将所有输入和 Z78E6221F6393D1356681DB398F14CED6 双向传递。 Think of it as a simple telnet bridge between two protocols, using my Spring Boot app as a bridge.将其视为两个协议之间的简单 telnet 桥,使用我的 Spring Boot 应用程序作为桥。
It seems like this sort of direct linking should be very simple with the Spring Integration DSL, but I can't even find an example of bridging multiple connections even with the annotation interface.使用 Spring 集成 DSL 似乎这种直接链接应该非常简单,但即使使用注释接口,我什至找不到桥接多个连接的示例。 Whenever I send a message from either interface, I see a "Dispatcher has no subscribers" error.每当我从任一界面发送消息时,我都会看到“调度程序没有订阅者”错误。
Am I overcomplicating this, or do I need to write some business logic code to do bidirectional forwarding?我是否过于复杂了,还是我需要编写一些业务逻辑代码来进行双向转发?
Here is a simple TCP<->TCP bridge...这是一个简单的 TCP<->TCP 桥...
@SpringBootApplication
public class So66993561Application {
public static void main(String[] args) {
SpringApplication.run(So66993561Application.class, args);
}
@Bean
AbstractServerConnectionFactory server() {
return Tcp.netServer(1234)
.deserializer(TcpCodecs.lf())
.serializer(TcpCodecs.lf())
.get();
}
@Bean
AbstractClientConnectionFactory client() {
return Tcp.netClient("localhost", 1235)
.deserializer(TcpCodecs.lf())
.serializer(TcpCodecs.lf())
.get();
}
@Bean
IntegrationFlow serverInbound(AbstractServerConnectionFactory server) {
return IntegrationFlows.from(Tcp.inboundAdapter(server))
.transform(Transformers.objectToString())
.handle("service", "sendToNCL")
.get();
}
@Bean
IntegrationFlow serverOutbound(AbstractServerConnectionFactory server) {
return IntegrationFlows.from(ServerGateway.class)
.handle(Tcp.outboundAdapter(server))
.get();
}
@Bean
IntegrationFlow clientInbound(AbstractClientConnectionFactory client) {
return IntegrationFlows.from(Tcp.inboundAdapter(client))
.transform(Transformers.objectToString())
.handle("service", "broadcastToClients")
.get();
}
@Bean
IntegrationFlow clientOutbound(AbstractClientConnectionFactory client) {
return IntegrationFlows.from(ClientGateway.class)
.handle(Tcp.outboundAdapter(client))
.get();
}
@Bean
@DependsOn("clientOutbound")
public ApplicationRunner runner(AbstractClientConnectionFactory client) {
return args -> {
System.out.println("Hit enter when netcat is running");
System.in.read(); // nc -l 1235
client.getConnection(); // just open the connection.
};
}
}
interface ServerGateway {
@Gateway(payloadExpression = "#args[0]",
headers = @GatewayHeader(name = IpHeaders.CONNECTION_ID, expression = "#args[1]" ))
void send(String out, String connectionId);
}
interface ClientGateway {
void send(String out);
}
@Component
@DependsOn({ "clientOutbound", "serverOutbound" })
class Service {
private final Set<String> serverClients = ConcurrentHashMap.newKeySet();
private final ClientGateway client;
private final ServerGateway server;
private volatile boolean clientOpen;
public Service(ClientGateway client, ServerGateway server) {
this.client = client;
this.server = server;
}
public void broadcastToClients(String in) {
System.out.println("received from server: " + in);
this.serverClients.forEach(client -> {
try {
this.server.send(in, client);
}
catch (Exception e) {
e.printStackTrace();
}
});
}
public void sendToNCL(String in) {
System.out.println("received from a client: " + in);
if (this.clientOpen) {
try {
this.client.send(in);
}
catch (Exception e) {
e.printStackTrace();
}
}
}
@EventListener
public void opens(TcpConnectionOpenEvent event) {
System.out.println(event);
if (event.getConnectionFactoryName().equals("server")) {
this.serverClients.add(event.getConnectionId());
}
else {
this.clientOpen = true;
}
}
@EventListener
public void closes(TcpConnectionCloseEvent event) {
System.out.println(event);
this.serverClients.remove(event.getConnectionId());
if (event.getConnectionFactoryName().equals("client")) {
this.clientOpen = false;
}
}
}
$ nc -l 1235
foo <<<<<<<<<<<<<<<<< received
bar <<<<<<<<<<<<<<<<< sent
$ nc localhost 1234
foo <<<<<<<<<<<<<<<<< sent
bar <<<<<<<<<<<<<<<<< received
EDIT编辑
Adding websocket server...添加websocket服务器...
@SpringBootApplication
public class So66993561Application {
public static void main(String[] args) {
SpringApplication.run(So66993561Application.class, args);
}
@Bean
AbstractServerConnectionFactory server() {
return Tcp.netServer(1234)
.deserializer(TcpCodecs.lf())
.serializer(TcpCodecs.lf())
.get();
}
@Bean
AbstractClientConnectionFactory client() {
return Tcp.netClient("localhost", 1235)
.deserializer(TcpCodecs.lf())
.serializer(TcpCodecs.lf())
.get();
}
@Bean
IntegrationFlow serverInbound(AbstractServerConnectionFactory server) {
return IntegrationFlows.from(Tcp.inboundAdapter(server))
.transform(Transformers.objectToString())
.handle("service", "sendToNCL")
.get();
}
@Bean
IntegrationFlow serverOutbound(AbstractServerConnectionFactory server) {
return IntegrationFlows.from(ServerGateway.class)
.handle(Tcp.outboundAdapter(server))
.get();
}
@Bean
IntegrationFlow clientInbound(AbstractClientConnectionFactory client) {
return IntegrationFlows.from(Tcp.inboundAdapter(client))
.transform(Transformers.objectToString())
.handle("service", "broadcastToClients")
.get();
}
@Bean
IntegrationFlow clientOutbound(AbstractClientConnectionFactory client) {
return IntegrationFlows.from(ClientGateway.class)
.handle(Tcp.outboundAdapter(client))
.get();
}
@Bean
@DependsOn("clientOutbound")
ApplicationRunner runner(AbstractClientConnectionFactory client) {
return args -> {
System.out.println("Hit enter when netcat is running");
System.in.read(); // nc -l 1235
client.getConnection(); // just open the connection.
};
}
@Bean
ServerWebSocketContainer serverWebSocketContainer() {
return new ServerWebSocketContainer("/relay").withSockJs();
}
@Bean
MessageHandler webSocketOutboundAdapter(ServerWebSocketContainer container) {
return new WebSocketOutboundMessageHandler(container);
}
@Bean
WebSocketInboundChannelAdapter wsInboundAdapter(ServerWebSocketContainer container) {
return new WebSocketInboundChannelAdapter(container);
}
@Bean
IntegrationFlow wsInbound(WebSocketInboundChannelAdapter wsInboundAdapter) {
return IntegrationFlows.from(wsInboundAdapter)
.handle("service", "sendToNCL")
.get();
}
@Bean
public IntegrationFlow wsOutbound(MessageHandler webSocketOutboundAdapter) {
return IntegrationFlows.from(WsServerGateway.class)
.handle(webSocketOutboundAdapter)
.get();
}
}
interface ServerGateway {
@Gateway(payloadExpression = "#args[0]",
headers = @GatewayHeader(name = IpHeaders.CONNECTION_ID, expression = "#args[1]" ))
void send(String out, String sessionId);
}
interface ClientGateway {
void send(String out);
}
interface WsServerGateway {
@Gateway(payloadExpression = "#args[0]",
headers = @GatewayHeader(name = SimpMessageHeaderAccessor.SESSION_ID_HEADER, expression = "#args[1]" ))
void send(String out, String connectionId);
}
@Component
@DependsOn({ "clientOutbound", "serverOutbound", "wsOutbound" })
class Service {
private final Set<String> serverClients = ConcurrentHashMap.newKeySet();
private final ClientGateway client;
private final ServerGateway server;
private final WsServerGateway wsServer;
private final ServerWebSocketContainer wsContainer;
private volatile boolean clientOpen;
public Service(ClientGateway client, ServerGateway server, WsServerGateway wsServer,
ServerWebSocketContainer wsContainer) {
this.client = client;
this.server = server;
this.wsServer = wsServer;
this.wsContainer = wsContainer;
}
public void broadcastToClients(String in) {
System.out.println("received from server: " + in);
this.serverClients.forEach(client -> {
try {
this.server.send(in, client);
}
catch (Exception e) {
e.printStackTrace();
}
});
this.wsContainer.getSessions().keySet().forEach(session -> this.wsServer.send(in, session));
}
public void sendToNCL(String in) {
System.out.println("received from a client: " + in);
if (this.clientOpen) {
try {
this.client.send(in);
}
catch (Exception e) {
e.printStackTrace();
}
}
}
@EventListener
public void opens(TcpConnectionOpenEvent event) {
System.out.println(event);
if (event.getConnectionFactoryName().equals("server")) {
this.serverClients.add(event.getConnectionId());
}
else {
this.clientOpen = true;
}
}
@EventListener
public void closes(TcpConnectionCloseEvent event) {
System.out.println(event);
this.serverClients.remove(event.getConnectionId());
if (event.getConnectionFactoryName().equals("client")) {
this.clientOpen = false;
}
}
}
$ websocat ws://localhost:8080/relay/websocket
foo <<<<<<<<<<<<<<<< received from nc -l connection
baz <<<<<<<<<<<<<<<< sent to nc -l connection
See https://github.com/spring-projects/spring-integration/blob/main/spring-integration-websocket/src/test/java/org/springframework/integration/websocket/server/WebSocketServerTests.java for a sample how to configure WebScoket components.有关示例,请参见https://github.com/spring-projects/spring-integration/blob/main/spring-integration-websocket/src/test/java/org/springframework/integration/websocket/server/WebSocketServerTests.java配置 WebScket 组件。
Since you talk about a browser connection, you probably need a ServerConfig
part to accept connections and forward messages to some webSocketInputChannel
.由于您谈论的是浏览器连接,因此您可能需要一个ServerConfig
部件来接受连接并将消息转发到某些webSocketInputChannel
。
The TcpSendingMessageHandler
could be a subscriber to that channel to bridge the data into a target TCP/IP connection. TcpSendingMessageHandler
可以是该通道的订阅者,以将数据桥接到目标 TCP/IP 连接。
A TcpReceivingChannelAdapter
with the same TcpNetClientConnectionFactory
could be used to receive a data from a TCP/IP connection and sends it to the webSocketOutputChannel
for forwarding to the WebSocket session.具有相同TcpReceivingChannelAdapter
的TcpNetClientConnectionFactory
可用于从 TCP/IP 连接接收数据并将其发送到webSocketOutputChannel
以转发到 WebSocket session。
Keep in mind though, that simpSessionId
header need to be transferred from the WebSocket request message to the TCP package and back for the future correlation when you are going to receive messages from TCP. Keep in mind though, that simpSessionId
header need to be transferred from the WebSocket request message to the TCP package and back for the future correlation when you are going to receive messages from TCP. Since there is no headers notation in TCP, you would need to think about some sort of data wrapper to embed headers alongside with the payload into TCP/IP package.由于 TCP 中没有标头符号,因此您需要考虑某种数据包装器以将标头与有效负载一起嵌入 TCP/IP package。
See more info about async collaborating channel adapters in docs: https://docs.spring.io/spring-integration/reference/html/ip.html#ip-collaborating-adapters .在文档中查看有关异步协作通道适配器的更多信息: https://docs.spring.io/spring-integration/reference/html/ip.html#ip-collaborating-adapters 。 And the next section about transferring headers.以及关于传输标头的下一部分。
This sample also provides some useful info about correlation and multiplexing with TCP/IP channel adapters: https://github.com/spring-projects/spring-integration-samples/tree/main/intermediate/tcp-client-server-multiplex此示例还提供了一些有关与 TCP/IP 通道适配器的关联和多路复用的有用信息: https://github.com/spring-projects/spring-integration-samples/tree/main/intermediate/tcp-client-server-multiplex
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.