在弹簧集成中定制变压器

时间:2016-06-30 20:50:13

标签: java tcp spring-integration

基于Spring集成的我的TCP服务器运行良好。

如果服务需要很长时间,它还会在服务器上处理回复超时。当服务花费的时间超过回复超时时,它会将消息发送到错误通道,然后将错误消息发送回客户端。

这是我的代码:

<int:transformer id="errorHandler"
    input-channel="errorChannel"
    ref="myTransformer" method="transform" />
<bean id="myTransformer" class="com.sample.MyTransformer" />

public class MyTransformer {
    private static Logger logger = Logger.getLogger(MyTransformer.class);

    public String transform(org.springframework.integration.handler.ReplyRequiredException e) {
        logger.error("timeout exception is thrown");
        return "Error in processing request.";
    }
}

以上代码有效,客户端在处理请求时遇到错误&#39;并且服务器日志有条目&#39;超时异常被抛出&#39;。但我也在日志中看到以下异常:

2016-06-30 16:25:27,827 ERROR [org.springframework.integration.handler.LoggingHandler] org.springframework.integration.handler.ReplyRequiredException: No reply produced by handler 'org.springframework.integration.config.ServiceActivatorFactoryBean#0', and its 'requiresReply' property is set to true.
    at org.springframework.integration.handler.AbstractReplyProducingMessageHandler.handleMessageInternal(AbstractReplyProducingMessageHandler.java:109)
    at org.springframework.integration.handler.AbstractMessageHandler.handleMessage(AbstractMessageHandler.java:127)
    at org.springframework.integration.dispatcher.AbstractDispatcher.tryOptimizedDispatch(AbstractDispatcher.java:116)
    at org.springframework.integration.dispatcher.UnicastingDispatcher.doDispatch(UnicastingDispatcher.java:147)
    at org.springframework.integration.dispatcher.UnicastingDispatcher.dispatch(UnicastingDispatcher.java:120)
    at org.springframework.integration.channel.AbstractSubscribableChannel.doSend(AbstractSubscribableChannel.java:77)
    at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:442)
    at org.springframework.messaging.core.GenericMessagingTemplate.doSend(GenericMessagingTemplate.java:115)
    at org.springframework.messaging.core.GenericMessagingTemplate.doSendAndReceive(GenericMessagingTemplate.java:150)
    at org.springframework.messaging.core.GenericMessagingTemplate.doSendAndReceive(GenericMessagingTemplate.java:45)
    at org.springframework.messaging.core.AbstractMessagingTemplate.sendAndReceive(AbstractMessagingTemplate.java:42)
    at org.springframework.integration.core.MessagingTemplate.sendAndReceive(MessagingTemplate.java:97)
    at org.springframework.integration.gateway.MessagingGatewaySupport.doSendAndReceive(MessagingGatewaySupport.java:422)
    at org.springframework.integration.gateway.MessagingGatewaySupport.sendAndReceiveMessage(MessagingGatewaySupport.java:390)
    at org.springframework.integration.ip.tcp.TcpInboundGateway.doOnMessage(TcpInboundGateway.java:119)
    at org.springframework.integration.ip.tcp.TcpInboundGateway.onMessage(TcpInboundGateway.java:97)
    at org.springframework.integration.ip.tcp.connection.TcpNetConnection.run(TcpNetConnection.java:182)
    at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
    at java.lang.Thread.run(Thread.java:662)

MyTransformer的实现似乎不正确。

您能帮忙解决如何定制变压器的问题吗? 如何在转换方法中获取有效负载,以便我可以回复客户端作为处理请求中的错误。有效载荷=&#39; +有效负载?

由于

更新:为了避免记录ReplyRequiredException,我更改了tcp-inbound-gateway上的错误通道,如下所示:

<int-ip:tcp-inbound-gateway id="gatewayCrLf"
    connection-factory="crLfServer"
    request-channel="requestChannel"
    error-channel="tcpErrorChannel"
    reply-timeout="10000"
    />
<int:channel id="tcpErrorChannel" /> 

<int:service-activator input-channel="requestChannel" ref="gateway" requires-reply="true"/>
<int:gateway id="gateway" default-request-channel="timeoutChannel" default-reply-timeout="10000" />
<int:object-to-string-transformer id="serverBytes2String"
    input-channel="timeoutChannel"
    output-channel="serviceChannel"/>

<int:channel id="timeoutChannel">
    <int:dispatcher task-executor="timeoutExecutor"/>
</int:channel>

<bean id="timeoutExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
    <property name="corePoolSize" value="5" />
    <property name="maxPoolSize" value="100" />
    <property name="queueCapacity" value="50" />
</bean>

但是我收到了MessageDeliveryException。 tcpErrorChannel设置似乎是错误的。你能建议吗?这是Stacktrace:

2016-07-05 12:17:34,266 ERROR [org.springframework.integration.ip.tcp.connection.TcpNetConnection] Exception sending message: GenericMessage [payload=byte[67], headers={timestamp=1467735444239, id=30eb099e-955d-1bd3-1789-49aa9fc84b6f, ip_tcp_remotePort=64055, ip_address=127.0.0.1, ip_localInetAddress=/127.0.0.1, ip_hostname=127.0.0.1, ip_connectionId=127.0.0.1:64055:5678:908d39a1-d027-4753-b144-59b9c0390fd7}]
org.springframework.messaging.MessagingException: failure occurred in error-handling flow; nested exception is org.springframework.messaging.MessageDeliveryException: Dispatcher has no subscribers for channel 'org.springframework.context.support.FileSystemXmlApplicationContext@4876db09.tcpErrorChannel'.; nested exception is org.springframework.integration.MessageDispatchingException: Dispatcher has no subscribers
    at org.springframework.integration.gateway.MessagingGatewaySupport.doSendAndReceive(MessagingGatewaySupport.java:452)
    at org.springframework.integration.gateway.MessagingGatewaySupport.sendAndReceiveMessage(MessagingGatewaySupport.java:390)
    at org.springframework.integration.ip.tcp.TcpInboundGateway.doOnMessage(TcpInboundGateway.java:119)
    at org.springframework.integration.ip.tcp.TcpInboundGateway.onMessage(TcpInboundGateway.java:97)
    at org.springframework.integration.ip.tcp.connection.TcpNetConnection.run(TcpNetConnection.java:182)
    at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
    at java.lang.Thread.run(Thread.java:662)
Caused by: org.springframework.messaging.MessageDeliveryException: Dispatcher has no subscribers for channel 'org.springframework.context.support.FileSystemXmlApplicationContext@4876db09.tcpErrorChannel'.; nested exception is org.springframework.integration.MessageDispatchingException: Dispatcher has no subscribers
    at org.springframework.integration.channel.AbstractSubscribableChannel.doSend(AbstractSubscribableChannel.java:81)
    at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:442)
    at org.springframework.messaging.core.GenericMessagingTemplate.doSend(GenericMessagingTemplate.java:115)
    at org.springframework.messaging.core.GenericMessagingTemplate.doSendAndReceive(GenericMessagingTemplate.java:150)
    at org.springframework.messaging.core.GenericMessagingTemplate.doSendAndReceive(GenericMessagingTemplate.java:45)
    at org.springframework.messaging.core.AbstractMessagingTemplate.sendAndReceive(AbstractMessagingTemplate.java:42)
    at org.springframework.integration.core.MessagingTemplate.sendAndReceive(MessagingTemplate.java:97)
    at org.springframework.integration.gateway.MessagingGatewaySupport.doSendAndReceive(MessagingGatewaySupport.java:449)
    ... 7 more
Caused by: org.springframework.integration.MessageDispatchingException: Dispatcher has no subscribers
    at org.springframework.integration.dispatcher.UnicastingDispatcher.doDispatch(UnicastingDispatcher.java:153)
    at org.springframework.integration.dispatcher.UnicastingDispatcher.dispatch(UnicastingDispatcher.java:120)
    at org.springframework.integration.channel.AbstractSubscribableChannel.doSend(AbstractSubscribableChannel.java:77)
    ... 14 more

上述异常将通过将errorChennel更改为tcpErrorChannel来消失:

非常感谢Artem的完美解决方案。

1 个答案:

答案 0 :(得分:1)

看起来这是继续你的另一个问题reply-timeout meaning in tcp-inbound-gateway in spring integration

嗯,ReplyRequiredException<int:service-activator input-channel="requestChannel" ref="gateway" requires-reply="true"/>

的结果

requires-reply="true" - 请阅读其说明。您可以使用它并将其设为false(默认值为1),但是“超时”的逻辑将无效。所以,除非继续接受,否则你没有选择:

ERROR [org.springframework.integration.handler.LoggingHandler] org.springframework.integration.handler.ReplyRequiredException

虽然这只是默认errorChannel的订阅者之一的影响:http://docs.spring.io/spring-integration/reference/html/configuration.html#namespace-errorhandler

现在关于你的最后一个问题。所有异常都包含在ErrorMessage中并发送到errorChannel。通常,异常包含在MessagingException中,例如在我们的案例中,它就像:

else if (this.requiresReply && !isAsync()) {
    throw new ReplyRequiredException(message, "No reply produced by handler '" +
            getComponentName() + "', and its 'requiresReply' property is set to true.");
}

注意那个message ctor参数,它正好是requestMessage,在我们的场景中没有回复。您可以从中提取所需的payload

因此,现在您可以从failedMessage中的ReplyRequiredException获取transform(),并为您的目标提取payload

<强>更新

  

由于此ReplyRequiredException是已知异常,因此无需将其视为错误。

嗯,即使它是一个已知的例外,但它在其他组件和场景中是一个重要的例子,当它可能不合适时不接收回复。 ReplyRequiredException在Framework组件中非常常见,因此将其移动到不同的类别可能是您的应用程序的一个重大架构错误。

要避免这些日志,您不应使用默认的errorChannel,而应使用TCP入站网关中的其他日志。像error-channel="tcpErrorChannel"这样的东西就是全部。默认errorChannel仍然会将LoggingHandler作为订阅者,但您已经不会向该频道发送错误消息。