与Spring Integration框架

时间:2016-03-04 03:48:44

标签: java sockets tcp spring-integration

我正在尝试创建一个接受入站连接的Tcp服务器,并异步向连接的客户端发送消息。 有一个Tcp服务器示例,但它使用的是网关,即请求/响应,不支持异步。

我的目标,

  1. 服务器侦听套接字,例如9000
  2. tcp客户端连接到9000
  3. 服务器接受连接和接收消息。 (使用TcpReceivingChannelAdapter?)
  4. 服务器保留连接/套接字并记下ip_connectId标头。
  5. 当某个事件或计划任务为客户端生成消息时,它会查找ip_connectId并向该客户端发送消息。 (使用TcpSendingMessageHandler?)
  6. 从参考文档中,我应该使用Collaborating Outbound和Inbound Channel Adapters。但是没有java配置示例。我不明白如何使用java配置执行此操作,尤其是查找客户端的方式和位置。

    我需要两个频道吗?一个用于入站,一个用于出站? inboundAdapter-> fromTcpChannel->消费者 生产者 - > outboundAdapter-> toTcpChannel

    我是否创建ServiceActivator或端点作为消费者/制作人? Spring默认情况下,spring集成是否保持连接?当我需要向它发送消息时,只需将ip_connectId标头添加到消息中? 我是使用TcpSendingMessageHandler将邮件发送给客户还是需要实施gateway

    清理我的代码并在Gary的帮助下再次测试,这是我的代码到目前为止。

    @EnableIntegration
    @IntegrationComponentScan
    @Configuration
    public class IntegrationConfig implements
            ApplicationListener<TcpConnectionEvent> {
        @Value("${listen.port:8000}")
        private int port;
    
        @Bean  //for accepting text message from TCP, putty
        public MessageChannel fromTcp() {
            return new DirectChannel();
        }
    
        @Bean  //for sending text message to TCP client, outbound
        public MessageChannel toTcp() {
            return new DirectChannel();
        }
    
        // receive from MVC controller
        @Bean
        public MessageChannel invokeChannel() {
            return new DirectChannel();
        }   
    
        @Bean  //inbound, it is working, I could read the inbound message while debugging
        public TcpReceivingChannelAdapter in(
                AbstractServerConnectionFactory connectionFactory) {
            TcpReceivingChannelAdapter adapter = new TcpReceivingChannelAdapter();
            adapter.setOutputChannel(fromTcp());
            adapter.setConnectionFactory(connectionFactory);
            return adapter;
        }
    
        //transform TCP bytes to string message, working
        @Transformer(inputChannel = "fromTcp", outputChannel = "toCollaborate")
        public String convert(byte[] bytes) {
    
            return new String(bytes);
        }
    
        MessageHeaders staticheader;  //save ip_connectinId, use this to collaborate outbound message later, for testing purpose only
        @ServiceActivator(inputChannel = "toCollaborate", outputChannel = "toTcp")
        public Message<String> handleTcpMessage(Message<String> stringMsg) {
            staticheader = stringMsg.getHeaders();
            return stringMsg;
            // save the header, collaborate to output channel
        }
    
        //collaborate message from REST API invokeChannel to a outbound tcp client, this fail
        @Transformer(inputChannel = "invokeChannel", outputChannel = "toTcp")
        public Message<String> headerBeforeSend(String test) {
            GenericMessage<String> msg = new GenericMessage<String>(
                    "from rest api");
            if (staticheader != null) {         
                MessageBuilder
                        .fromMessage(msg)
                        .setHeader("ip_connectionId",
                                staticheader.get("ip_connectionId")).build();
            }
            return msg;
        }
    
        @ServiceActivator(inputChannel = "toTcp")
        @Bean
        public TcpSendingMessageHandler out(
                AbstractServerConnectionFactory connectionFactory) {
            TcpSendingMessageHandler tcpOutboundAdp = new TcpSendingMessageHandler();
            tcpOutboundAdp.setConnectionFactory(connectionFactory);
    
    
            return tcpOutboundAdp;
        }   
    
        // should need only 1 factory? and keep connectin alive
        // server for in coming connection
        @Bean
        public AbstractServerConnectionFactory serverCF() {
            return new TcpNetServerConnectionFactory(this.port);
        }
    
        @Override
        public void onApplicationEvent(TcpConnectionEvent tcpEvent) {
            // TODO Auto-generated method stub
            TcpConnection source = (TcpConnection) tcpEvent.getSource();
    
        }
    
    }
    //The MVC controller
    @Autowired
        MessageChannel invokeChannel;
        @RequestMapping(value="/invoke")
        public String sayHello()
        {
            //trigger gateway to send a message
            String msg = "hello";
            MessagingTemplate template = new MessagingTemplate();
            template.send(invokeChannel, new GenericMessage<String>(msg));      
            return msg;
        }
    

    测试结果: 1. putty连接好,发短信 2. SI收到消息确定 3.使用REST API localhost/webappname/rest/invoke向invokeChannel发送消息,确定 4. transformer设置邮件标题 5.例外如下

      

    exception org.springframework.web.util.NestedServletException:Request   处理失败;嵌套异常是   org.springframework.messaging.MessageHandlingException:无法找到   出站套接字     org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:981)     org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:860)     javax.servlet.http.HttpServlet.service(HttpServlet.java:622)     org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:845)     javax.servlet.http.HttpServlet.service(HttpServlet.java:729)     org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)

1 个答案:

答案 0 :(得分:1)

是;默认情况下连接保持打开状态;是的,您可以使用@ServiceActivator来处理请求;是的,你只需要设置连接ID头。

要在Java Configuration中配置出站适配器,请将@ServiceActivator添加到处理程序bean ...

@Bean
public TcpReceivingChannelAdapter() in() {

    ...
    adapter.setOutputChannel(newRequests());

}


...

@ServiceActivator(inputChannel="toClientChannel")
@Bean
public TcpSendingMessageHandler out() {

    ...

}