在Spring集成中处理低级套接字错误的最佳实践?

时间:2015-08-13 15:41:52

标签: spring exception-handling spring-integration tcp-ip socketexception

您好我在这里再次询问spring integration的tcp-ip相关问题。

假设我有一个动态配置的tcp-ip连接工厂:

<int-ip:tcp-connection-factory id="chatRoomTcpIpClientFactory"
    type="client"
    host="${host}"
    port="${port}"
    single-use="false"
    using-nio="false"
    so-keep-alive="false"
    so-timeout="${timeout}"
    serializer="${seri-deseri}"
    deserializer="${seri-deseri}"/>

这里,主持人&amp;端口在开始时都是未知的。有时,该计划不能授予主持人和端口有效。假设有一个ip /端口8.8.8.8:12345在目标服务器上未打开。现在Spring框架抛出:

2015-08-13 22:07:52.906 ERROR 24479 --- [nio-8080-exec-1] o.s.i.ip.tcp.TcpSendingMessageHandler    : Error creating connection
java.net.ConnectException: Connection refused

假设我的业务逻辑严重依赖于tcp-ip连接,并且程序希望对此特定套接字连接错误进行一些错误处理。 (例如,将错误写入redis缓存,使用其他ip / port重新连接等等)

我已经找到了解决方案,现在我知道在这种低级异常中没有触发“errorChannel”。这同样适用于tcp-connection-event-inbound-channel-adapter。

经过一些谷歌搜索,似乎工厂bean里面的“建议”或者带有chainFactory的TcpConnectionInterceptorSupport是要走的路......但我还是很困惑。 tcp连接失败很常见。有没有更简单的方法来处理连接异常?

编辑:我深入研究了源代码,现在我在我的方法中添加了一个try-catch。它现在有效。至于tcp-connection-event-inbound-channel-adapter,它仍然不起作用。似乎套接字创建异常未发布...

当服务尝试通过套接字发送消息时,TcpSendingMessageHandler会获取异常...

编辑2: 跟踪堆栈跟踪:

2015-08-14 10:31:53.694 ERROR 2531 --- [nio-8080-exec-1] o.s.i.ip.tcp.TcpSendingMessageHandler    : Error creating connection

java.net.ConnectException: Connection refused
at java.net.PlainSocketImpl.socketConnect(Native Method)
at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:345)
at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:206)
at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:188)
at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392)
at java.net.Socket.connect(Socket.java:589)
at java.net.Socket.connect(Socket.java:538)
at java.net.Socket.<init>(Socket.java:434)
at java.net.Socket.<init>(Socket.java:211)
at javax.net.DefaultSocketFactory.createSocket(SocketFactory.java:271)
at org.springframework.integration.ip.tcp.connection.TcpNetClientConnectionFactory.createSocket(TcpNetClientConnectionFactory.java:76)
at org.springframework.integration.ip.tcp.connection.TcpNetClientConnectionFactory.buildNewConnection(TcpNetClientConnectionFactory.java:49)
at org.springframework.integration.ip.tcp.connection.AbstractClientConnectionFactory.obtainNewConnection(AbstractClientConnectionFactory.java:114)
at org.springframework.integration.ip.tcp.connection.AbstractClientConnectionFactory.obtainConnection(AbstractClientConnectionFactory.java:77)
at org.springframework.integration.ip.tcp.connection.AbstractClientConnectionFactory.getConnection(AbstractClientConnectionFactory.java:67)
at org.springframework.integration.ip.tcp.connection.AbstractClientConnectionFactory.getConnection(AbstractClientConnectionFactory.java:31)
at org.springframework.integration.ip.tcp.TcpSendingMessageHandler.obtainConnection(TcpSendingMessageHandler.java:72)
at org.springframework.integration.ip.tcp.TcpSendingMessageHandler.doWrite(TcpSendingMessageHandler.java:144)
at org.springframework.integration.ip.tcp.TcpSendingMessageHandler.handleMessageInternal(TcpSendingMessageHandler.java:120)
at org.springframework.integration.handler.AbstractMessageHandler.handleMessage(AbstractMessageHandler.java:78)
at org.springframework.integration.dispatcher.AbstractDispatcher.tryOptimizedDispatch(AbstractDispatcher.java:116)
at org.springframework.integration.dispatcher.UnicastingDispatcher.doDispatch(UnicastingDispatcher.java:101)
at org.springframework.integration.dispatcher.UnicastingDispatcher.dispatch(UnicastingDispatcher.java:97)
at org.springframework.integration.channel.AbstractSubscribableChannel.doSend(AbstractSubscribableChannel.java:77)
at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:287)
at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:245)
at (My service call)

这里,在TcpNetClientConnectionFactory.buildNewConnecton()中,

写成:

protected TcpConnectionSupport buildNewConnection() throws IOException, SocketException, Exception {
    Socket socket = createSocket(this.getHost(), this.getPort());  //<--- Where exception is thrown
    setSocketAttributes(socket);
    TcpConnectionSupport connection = new TcpNetConnection(socket, false, this.isLookupHost(),
            this.getApplicationEventPublisher(), this.getComponentName());
    connection = wrapConnection(connection);
    initializeConnection(connection, socket);
    this.getTaskExecutor().execute(connection);
    this.harvestClosedConnections();
    return connection;
}

因此,甚至没有达到TcpConnectionSupport。事件驱动的适配器无法处理套接字创建期间发生的异常。这就是为什么我一直在努力寻找答案的原因。

在TcpSendingMessageHandler中,

protected TcpConnection obtainConnection(Message<?> message) {
    TcpConnection connection = null;
    Assert.notNull(this.clientConnectionFactory, "'clientConnectionFactory' cannot be null");
    try {
        connection = this.clientConnectionFactory.getConnection();
    }
    catch (Exception e) {
        logger.error("Error creating connection", e);
        throw new MessageHandlingException(message, "Failed to obtain a connection", e);
    }
    return connection;
}

这里只记录错误,并再次抛出新的异常。

2 个答案:

答案 0 :(得分:2)

请查看TcpConnectionEvent层次结构,尤其是TcpConnectionExceptionEvent。并调查TcpConnection实现发布它的位置。

请在Reference Manual

中找到有关此事的更多信息

答案 1 :(得分:0)

关闭套接字后,事件TcpConnectionFailedEvent被触发(它扩展了org.springframework.integration.ip.tcp.connection.IpIntegrationEvent)。

这里是使用方法:

  @EventListener
  public void handleEvent(TcpConnectionFailedEvent event) {
    // handle the event
  }