【问题标题】:Reuse of service-activator for several gateway methods with Splitter使用 Splitter 为多个网关方法重用服务激活器
【发布时间】:2016-03-23 17:15:16
【问题描述】:

是否有人碰巧知道使用多种方法(入站)重用服务激活器以及输出通道是否有效,尤其是使用拆分器和聚合器。

--> 始终在网关上显示结果。

在几个测试中,它似乎工作正常。一旦我添加了一个带有聚合器的拆分器,我就会将错误结果路由到网关,然后网关失败并出现转换异常(在我的情况下,它无法将布尔值转换为整数)。

谢谢,

保罗

流程

Spring 集成配置

    <?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:int="http://www.springframework.org/schema/integration"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd">

    <int:gateway service-interface="activity.BulbMessageGateway">
        <int:method name="sendToBulb" request-channel="bulbMessages" reply-channel="bulbSendResult"></int:method>
        <int:method name="updateHomeLightStatus" request-channel="homeBulbEntity" reply-channel="homeBulbEntityResult">
        </int:method>
        <int:method name="updateLightStatus" request-channel="bulbEntities" reply-channel="bulbSendResult">
            <int:header name="homeId" expression="#args[0].homeId"/>
            <int:header name="bulbId" expression="#args[0].strongId"/>
        </int:method>
    </int:gateway>

    <int:channel id="bulbMessages" />
    <int:channel id="bulbSendResult" />
    <int:channel id="bulbEntities" />

    <int:channel id="homeBulbEntity" />
    <int:channel id="homeBulbEntityResult" />

    <int:chain input-channel="homeBulbEntity" output-channel="bulbEntities">
        <int:splitter expression="payload.bulbs" />
        <int:header-enricher>
            <int:header name="bulbId" expression="payload.strongId"/>
            <int:header name="homeId" expression="payload.homeId"/>
        </int:header-enricher>
    </int:chain>

    <int:transformer method="bulbToLightStatus" input-channel="bulbEntities" output-channel="bulbMessages">
        <bean class="util.BulbTransformer"></bean>
    </int:transformer>

    <int:aggregator input-channel="bulbSendResult" output-channel="homeBulbEntityResult" method="aggregate">
        <bean class="util.BooleanAggregator" />
    </int:aggregator>

    <int:service-activator input-channel="bulbMessages" output-channel="bulbSendResult" method="send">
        <bean class="activity.BulbWebsocketMessageSenderBA" />
    </int:service-activator>
</beans>

单元测试

@Test
public void sendMessageNoReceiver() {
    assertFalse(gateway.sendToBulb(new HomeId("1"), new BulbId("1"), BulbMessageBuilder.restart("foo")));
}

@Test
public void sendMessageWithReceiver() {
    MockSession<BulbId, BulbBE> bulbSession = new MockSession<BulbId, BulbBE>(new BulbBE(HomeId.of("1"), BulbId.of("1"), "bulb", "pass"));
    registry.addBulbSession(bulbSession);
    assertTrue(gateway.sendToBulb(new HomeId("1"), new BulbId("1"), BulbMessageBuilder.restart("foo")));
    assertEquals(1, bulbSession.receivedMessages());
}

@Test
public void updateBulbStatus() {
    final MockSession<BulbId, BulbBE> bulbSession1 = new MockSession<BulbId, BulbBE>(new BulbBE(HomeId.of("1"), BulbId.of("1"), "bulb", "pass"));
    assertFalse(gateway.updateLightStatus(bulbSession1.getIdentity()));

    registry.addBulbSession(bulbSession1);
    assertTrue(gateway.updateLightStatus(bulbSession1.getIdentity()));
    assertEquals(1, bulbSession1.receivedMessages());

    final MockSession<BulbId, BulbBE> bulbSession2 = new MockSession<BulbId, BulbBE>(new BulbBE(HomeId.of("1"), BulbId.of("2"), "bulb", "pass"));
    assertFalse(gateway.updateLightStatus(bulbSession2.getIdentity()));

    registry.addBulbSession(bulbSession2);
    assertTrue(gateway.updateLightStatus(bulbSession2.getIdentity()));
    assertTrue(gateway.updateLightStatus(bulbSession2.getIdentity()));

    assertEquals(2, bulbSession2.receivedMessages());
    assertEquals(1, bulbSession1.receivedMessages());
}
@Test
public void updateHomeBulbStatus() {
    final HomeBE home = new HomeBE();
    home.setId(new ObjectId());

    final MockSession<BulbId, BulbBE> bulbSession1 = new MockSession<BulbId, BulbBE>(new BulbBE(home.getStrongId(), BulbId.of("1"), "bulb", "pass"));
    registry.addBulbSession(bulbSession1);
    final MockSession<BulbId, BulbBE> bulbSession2 = new MockSession<BulbId, BulbBE>(new BulbBE(home.getStrongId(), BulbId.of("2"), "bulb", "pass"));
    registry.addBulbSession(bulbSession2);

    home.addBulb(bulbSession1.getIdentity());

    assertEquals(1, gateway.updateHomeLightStatus(home));
    assertEquals(1, bulbSession1.receivedMessages());
    assertEquals(0, bulbSession2.receivedMessages());

    home.addBulb(bulbSession2.getIdentity());
    assertEquals(2, gateway.updateHomeLightStatus(home));
    assertEquals(2, bulbSession1.receivedMessages());
    assertEquals(1, bulbSession2.receivedMessages());
}

如果最后一个测试与其他测试一起执行,则它会失败。如果单独执行,则通过。

错误是最后一个方法(使用拆分器)现在接收一个布尔值,这似乎是其他两个方法注册的结果。这些方法的结果是一个布尔值。

【问题讨论】:

  • - BooleanAggregator 计算真值 - BulbTransformer 将转换为服务在激活器中期望的类型 * 方法:sendToBulb 按原样发送消息 * 方法:updateLightStatus 发送消息但只转换一次 * 方法: updateHomeLightStatus 现在发送一个集合,该集合是使用拆分器表达式 payload.bulbs 提取的给定参数的一部分
  • 也将其移至您的问题。

标签: spring-integration


【解决方案1】:

请分享关于此事的配置。

根据您的图表,如果您尽可能减少配置以隔离问题,那会更好。

另一方面,请更具体一点:您的问题完全不清楚。

那是你自己的服务。我们如何确定在不同的地方使用它是安全的?只有作为作者的您才能确定这一点。

更新

抱歉耽搁了。正忙于发布。

感谢您分享您的用例的配置。

现在我看到了问题。

您在网关的方法上到处使用reply-channel。当您需要时,请参阅documentation

通常您不必指定默认回复通道,因为网关会自动创建一个临时的匿名回复通道,它会在其中侦听回复。但是,在某些情况下,可能会提示您定义默认回复通道(或带有适配器网关的回复通道,例如 HTTP、JMS 等)。

由于您在不同的地方使用相同的bulbSendResult,因此行为确实是不可预测的。而且那个频道是DirectChannel,所以round-robin平衡器就在现场。

您应该完全摆脱那些reply-channel,而只依赖replyChannel 标头上的下游组件。因此,您应该删除那些旨在向您的网关返回回复的组件中的output-channels。

例如最后一个service-activator应该是这样的:

<int:service-activator input-channel="bulbMessages" method="send">
    <bean class="activity.BulbWebsocketMessageSenderBA"/>
</int:service-activator>

由于您普遍质疑如何重用此 service-activator,因此我正在回答您的配置问题:

<int:chain input-channel="homeBulbEntity">
    <int:splitter expression="payload.bulbs"/>
    <int:header-enricher>
        <int:header name="bulbId" expression="payload.strongId"/>
        <int:header name="homeId" expression="payload.homeId"/>
    </int:header-enricher>
    <int:transformer method="bulbToLightStatus">
        <bean class="util.BulbTransformer"/>
    </int:transformer>
    <int:gateway request-channel="bulbMessages"/>
    <int:aggregator method="aggregate">
        <bean class="util.BooleanAggregator"/>
    </int:aggregator>
</int:chain>

注意&lt;chain&gt;的缺席output-channel。因此,它直接从标头向replyChannel 发送回复,并作为return 向您的updateHomeLightStatus 网关的方法发送回复。

另一个技巧是&lt;int:gateway request-channel="bulbMessages"/&gt;&lt;chain&gt; 的中间发送消息到您的&lt;service-activator&gt; 并等待来自那里的回复与顶级网关完全相同 - 通过replyChannel 标头.对于没有output-channel&lt;service-activator&gt;,它是一个发送回复的黑匣子。它只使用标题中的replyChannel

&lt;chain&gt;收到回复gateway后,将消息推送到&lt;aggregator&gt;

aggregator 执行其逻辑时,结果将作为&lt;chain&gt; 的输出发送到顶级网关。

就是这样。

让我知道还有什么不清楚的地方。

【讨论】:

  • 新增xml配置和测试,希望对您有帮助
  • 抱歉耽搁了,但是,请在我的回答中找到更新。
  • 太棒了,非常感谢 Artem!这真的很有帮助。只是通过阅读它,我已经知道我做错了什么。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-06-24
  • 1970-01-01
  • 2023-03-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多