如何从Spring Integration中的方法返回值而不中断原始Message流?

时间:2014-05-26 20:18:46

标签: java spring spring-integration

encode bean的fileProcessor方法负责编码视频文件。如果遇到问题,则不应删除该文件,否则如果一切正常,则可以删除。现在,在不更改有效负载的情况下保留Message流的唯一方法是使encode方法返回void。我需要返回一些“标题”信息,以便SI以后可以删除该文件。我尝试使用MessageBuilder创建Message<File>并将其返回,但是当它到达下一个频道时,它已被包装,Message内有Message,因此我的表达式无法触发删除。

我想我可以使用一个包裹的Message并在对象图中挖掘一个级别,但这看起来很笨拙。

在不破坏原始消息有效负载且不使用SI通道和发送方式污染我的POJO编码方法的情况下,获取某些返回值的最佳方法是什么?

这是我的配置:

<!-- ########################## -->
<!-- ###      Encoding      ### -->
<!-- ########################## -->

<file:inbound-channel-adapter 
    directory="${paths.encode}"
    channel="encodeChannel"
    filename-regex="${encode.regex}"
    prevent-duplicates="false">
    <int:poller fixed-rate="5000"/>
</file:inbound-channel-adapter>

<int:service-activator
    input-channel="encodeChannel"
    output-channel="encodeResultChannel"
    ref="fileProcessor"
    method="encode">
</int:service-activator>    

<!-- This is where I'm having trouble.  -->
<!-- I don't expect this router to work. -->
<int:router
    input-channel="encodeResultChannel"
    expression="payload">       
    <int:mapping value="true" channel="encodeDeleteChannel"/>
    <int:mapping value="false" channel="stdout"/>
</int:router>

<int:service-activator
    input-channel="encodeDeleteChannel"
    expression="payload.delete()"
    output-channel="stdout">
</int:service-activator>

<stream:stdout-channel-adapter 
    id="stdout" 
    append-newline="true" />

编辑:

我正在使用:

<properties>
    <spring-framework.version>3.2.3.RELEASE</spring-framework.version>
</properties>

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>${spring-framework.version}</version>
</dependency>

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-integration</artifactId>
    <version>1.1.0.BUILD-SNAPSHOT</version>
</dependency>

EDIT2:

这是更新的配置

<!-- ########################## -->
<!-- ###      Encoding      ### -->
<!-- ########################## -->

<file:inbound-channel-adapter 
    directory="${paths.encode}"
    channel="filePickupChannel"
    filename-regex="${encode.regex}"
    prevent-duplicates="false">
    <int:poller fixed-rate="5000"/>
</file:inbound-channel-adapter>

<int:header-enricher
    input-channel="filePickupChannel"
    output-channel="encodeChannel">
    <int:header name="origFile" expression="payload"/>
</int:header-enricher>

<int:service-activator
    input-channel="encodeChannel"
    output-channel="encodeResultChannel"
    ref="fileProcessor"
    method="encode">
</int:service-activator>    

<int:router
    input-channel="encodeResultChannel"
    ignore-send-failures="false"
    default-output-channel="stdout"
    expression="payload">       
    <int:mapping value="true" channel="encodeDeleteChannel"/>
    <int:mapping value="false" channel="stdout"/>
</int:router>

<int:service-activator
    input-channel="encodeDeleteChannel"
    expression="headers['origFile'].delete()"
    output-channel="stdout">
</int:service-activator>

1 个答案:

答案 0 :(得分:3)

您使用的是什么版本的Spring Integration和Spring Framework?

fileProcessor.encode()的签名是什么样的?

您不应该获得嵌套Message<?>AbstractReplyProducingMessageHandler具有以下逻辑......

private Message<?> createReplyMessage(Object reply, MessageHeaders requestHeaders) {
    AbstractIntegrationMessageBuilder<?> builder = null;
    if (reply instanceof Message<?>) {
        if (!this.shouldCopyRequestHeaders()) {
            return (Message<?>) reply;
        }
        builder = this.getMessageBuilderFactory().fromMessage((Message<?>) reply);
    }

...

    if (this.shouldCopyRequestHeaders()) {
        builder.copyHeadersIfAbsent(requestHeaders);
    }
    return builder.build();
}

因此,如果您返回Message<?>,则会返回您的消息(使用您未设置的任何入站标头进行增强)。

您是否在Spring Framework 4.0.x中使用Spring Integration 3.0.x?如果是这样,您需要小心返回org.springframework.integration消息,而不是org.springframework.messaging消息。

如果返回org.springframework.messaging消息,Spring Integration确实会将其包装在Spring Integration消息中。

核心消息传递类已移至Spring Framework 4.0中的spring-messaging模块,因此它们可用于websockets,STOMP等。

Spring Integration 4.0.x现在也使用这些类,因此您不会在类路径中看到这两个类;避免混淆。将Spring Integration 3.0.x与Spring Framework 4.0.x一起使用时,您需要非常谨慎地使用正确的类。

但是,一般情况下,我们不建议在代码中添加框架类(例如Message<?>),而是使用POJO,框架将处理消息传递细节......

boolean encode(File file) {...}

如果您需要在编码后访问有效负载,请考虑事先将其提升为标头。

<int:header-enricher ...>
    <int:header name="origFile" expression="payload" />
</int:header-enricher>

然后在编码后使用expression="headers['origFile'].delete()

编辑:

或者,在成功时返回文件(因此它成为新的有效负载),如果失败,则返回null或抛出异常,并且不会执行下游流程。