Spring boot 如何配置仅连接客户端和发送消息的服务器的spring集成适配器
我尝试使用Spring集成实现以下场景: 我需要一个客户端通过TCP IP连接到服务器,并在30秒内等待接收消息。 我需要一个服务器向已连接的客户端发送0到n条消息。 我需要一种在不丢失消息的情况下启动和停止通道传输的方法。 我需要在停止和启动之间更改服务器正在侦听的端口 这是我目前的配置:Spring boot 如何配置仅连接客户端和发送消息的服务器的spring集成适配器,spring-boot,tcp,spring-integration,Spring Boot,Tcp,Spring Integration,我尝试使用Spring集成实现以下场景: 我需要一个客户端通过TCP IP连接到服务器,并在30秒内等待接收消息。 我需要一个服务器向已连接的客户端发送0到n条消息。 我需要一种在不丢失消息的情况下启动和停止通道传输的方法。 我需要在停止和启动之间更改服务器正在侦听的端口 这是我目前的配置: @Configuration public class TcpConfiguration { private static Logger LOG = LoggerFactory.getLogger(
@Configuration
public class TcpConfiguration {
private static Logger LOG = LoggerFactory.getLogger(TcpConfiguration.class);
@Value("${port}")
private Integer port;
@Value("${so-timeout}")
private Integer soTimeout;
@Value("${keep-alive}")
private Boolean keepAlive;
@Value("${send-timeout}")
private Integer sendTimeout;
@Bean
public AbstractServerConnectionFactory getMyConnFactory() {
LOG.debug("getMyConnFactory");
TcpNetServerConnectionFactory factory = new TcpNetServerConnectionFactory(port);
LOG.debug("getMyConnFactory port={}", port);
factory.setSoTimeout(soTimeout);
LOG.debug("getMyConnFactory soTimeout={}", soTimeout);
factory.setSoKeepAlive(true);
LOG.debug("getMyConnFactory keepAlive={}", keepAlive);
return factory;
}
@Bean
public AbstractEndpoint getMyChannelAdapter() {
LOG.debug("getMyChannelAdapter");
TcpReceivingChannelAdapter adapter = new TcpReceivingChannelAdapter();
adapter.setConnectionFactory(getMyConnFactory());
adapter.setOutputChannel(myChannelIn());
adapter.setSendTimeout(sendTimeout);
LOG.debug("getMyChannelAdapter adapter={}", adapter.getClass().getName());
return adapter;
}
@Bean
public MessageChannel myChannelIn() {
LOG.debug("myChannelIn");
return new DirectChannel();
}
@Bean
@Transformer(inputChannel = "myChannelIn", outputChannel = "myServiceChannel")
public ObjectToStringTransformer myTransformer() {
LOG.debug("myTransformer");
return new ObjectToStringTransformer();
}
@ServiceActivator(inputChannel = "myServiceChannel")
public void service(String in) {
LOG.debug("service received={}", in);
}
@Bean
public MessageChannel myChannelOut() {
LOG.debug("myChannelOut");
return new DirectChannel();
}
@Bean
public IntegrationFlow myOutbound() {
LOG.debug("myOutbound");
return IntegrationFlows.from(myChannelOut())
.handle(mySender())
.get();
}
@Bean
public MessageHandler mySender() {
LOG.debug("mySender");
TcpSendingMessageHandler tcpSendingMessageHandler = new TcpSendingMessageHandler();
tcpSendingMessageHandler.setConnectionFactory(getMyConnFactory());
return tcpSendingMessageHandler;
}
}
请指教
要更改服务器端口,我将关闭应用程序上下文,并在远程配置服务器中配置新端口后重新启动它。
我可以在不破坏当前消息传输的情况下关闭应用程序上下文吗?
我不知道如何处理仅连接客户端的事情。使用;只需获取连接即可打开它,而无需发送
@springboot应用程序
公共类SO62867670应用程序{
公共静态void main(字符串[]args){
SpringApplication.run(So62867670Application.class,args);
}
@豆子
公共应用程序运行程序(DynamicCpReceiver接收器){
返回args->{//只是一个演示,显示开始/停止
接收器。连接并监听(1234);
System.in.read();
接收器。停止();
System.in.read();
接收器。连接并监听(1235);
System.in.read();
接收器。停止();
};
}
}
@组成部分
类动态cReceiver{
@自动连线
私有集成流上下文;
私人综合流动登记;
public void connectAndListen(int端口)引发中断异常{
TcpClientConnectionFactorySpec client=Tcp.netClient(“本地主机”,端口)
.deserializer(TcpCodecs.lf());
IntegrationFlow=IntegrationFlows.from(Tcp.inboundAdapter(客户端))
.transform(Transformers.objectToString())
.handle(System.out::println)
.get();
this.registration=context.registration(flow.register();
client.get().getConnection();//只需打开单个共享连接
}
公共停车场(){
if(this.registration!=null){
这个.registration.destroy();
this.registration=null;
}
}
}
编辑
这是服务器端
@springboot应用程序
@使能调度
公共类So62867670ServerApplication{
公共静态void main(字符串[]args){
run(So62867670ServerApplication.class,args);
}
@豆子
公共应用程序运行程序(DynamicTcpServer接收器){
返回args->{//只是一个演示,显示开始/停止
接收人:tcpListen(1234);
System.in.read();
接收器。停止(1234);
System.in.read();
接收人:tcpListen(1235);
System.in.read();
接收器。停止(1235);
};
}
}
@组成部分
类动态Cpserver{
私有静态最终记录器LOG=LoggerFactory.getLogger(dynamictcserver.class);
@自动连线
私有集成流上下文流上下文;
@自动连线
私有应用上下文appContext;
私有最终映射注册=新HashMap();
私有最终映射客户端=新ConcurrentHashMap();
公共无效tcpListen(内部端口){
TcpServerConnectionFactorySpec服务器=Tcp.netServer(端口)
.id(“服务器-”+端口)
.serializer(TcpCodecs.lf());
server.get().registerListener(msg->false);//虚拟侦听器,因此接受线程不会退出
IntegrationFlow=f->f.handle(Tcp.outboundAdapter(服务器));
this.registrations.put(端口,flowContext.registration(flow.register());
}
公共空站(内部端口){
IntegrationFlowRegistration=this.registrations.remove(端口);
if(注册!=null){
注册。销毁();
}
}
@事件监听器
公共无效关闭(TcpConnectionOpenEvent事件){
LOG.info(event.toString());
字符串connectionId=event.getConnectionId();
String[]split=connectionId.split(“:”);
int port=Integer.parseInt(拆分[2]);
this.clients.put(connectionId,new AbstractMap.SimpleEntry(port,new AtomicInteger());
}
@事件监听器
公共无效关闭(TcpConnectionCloseEvent事件){
LOG.info(event.toString());
this.clients.remove(event.getConnectionId());
}
@事件监听器
公共无效侦听(TCPConnectionServerListingEvent事件){
LOG.info(event.toString());
}
@计划(固定延迟=5000)
公共无效发送者(){
this.clients.forEach((connectionId,portAndCount)->{
IntegrationFlowRegistration=this.registrations.get(portAndCount.getKey());
if(注册!=null){
日志信息(“发送到”+连接ID);
registration.getMessagingTemplate().send(MessageBuilder.withPayload(“foo”)
.setHeader(IpHeaders.CONNECTION_ID,connectionId).build());
如果(portAndCount.getValue().incrementAndGet()>9){
this.appContext.getBean(“服务器-”+portAndCount.getKey(),TcpNetServerConnectionFactory.class)
.紧密连接(连接ID);
}
}
});
}
}
非常感谢Gary!需要一些时间来检查它。我在侦听模式下使用了netcat
(nc
,在Mac上)来测试它-因此使用了linefeed反序列化器nc-l 1234
在一个终端中,而nc-l 1235
在另一个终端中。我有点麻烦,无法将代码包含在runner方法中以接收任何内容。但主要是我无法明确我的重点放在服务器端。Gary,你有没有另一段代码让服务器重新启动