【问题标题】:Best practice for handling low-level socket error in spring integration?在 Spring 集成中处理低级套接字错误的最佳实践?
【发布时间】:2015-08-13 15:41:52
【问题描述】:

您好,我又来这里询问 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}"/>

在这里,主机和端口一开始都是未知的。有时程序不能保证主机和端口是有效的。假设有一个 ip/port 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,还是不行。好像没有发布socket创建异常...

当服务尝试通过套接字发送消息时,该异常被 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;
}

这里只是简单地记录了错误并再次抛出一个新的异常。

【问题讨论】:

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


    【解决方案1】:

    请查看TcpConnectionEvent 层次结构,尤其是TcpConnectionExceptionEvent。并调查TcpConnection 实现发出它的地方。

    请在Reference Manual 中找到有关此事的更多信息。

    【讨论】:

    • 另外,在这种情况下(客户端套接字连接错误),异常被抛出给调用者,所以正常的error-channel处理会起作用。
    • 嗨,Gary,我已经尝试过各种方式的错误通道...(通过获取错误通道 bean 在 xml 文件和 POJO 中声明)它们都不起作用。控制台打印出错误通道已被订阅,但发生connectionException时从未调用过...
    • 感谢您的回复!请检查我的编辑...错误通道和 tcp 连接异常事件在这里都不起作用...
    【解决方案2】:

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

    这里是如何使用它:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-07-15
      • 1970-01-01
      • 2020-10-21
      • 2018-09-12
      • 2017-11-26
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多