Java Spring集成事务在管道的其余部分之前提交

Java Spring集成事务在管道的其余部分之前提交,java,spring,transactions,spring-integration,Java,Spring,Transactions,Spring Integration,因此,这是我当前的设置: <int-amqp:inbound-channel-adapter channel="input-channel" queue-names="probni" message-converter="jsonMessageConverter" channel-transacted="true" transaction-manager=

因此,这是我当前的设置:

<int-amqp:inbound-channel-adapter channel="input-channel" queue-names="probni" message-converter="jsonMessageConverter"
                                  channel-transacted="true"
                                  transaction-manager="dataSourceTransactionManager"/>
<int:chain input-channel="input-channel" output-channel="inputc1">
    <int:service-activator ref="h1" method="handle" />
    <int:service-activator ref="h2" method="handle" />
    <int:service-activator ref="h3" method="handle" />
    <int:splitter  />
</int:chain>

<int:publish-subscribe-channel id="inputc1"/>

<int:claim-check-in input-channel="inputc1" output-channel="nullChannel" message-store="messageStore" order="1" />

<int:bridge input-channel="inputc1" output-channel="inputc2" order="2" />

<int:publish-subscribe-channel id="inputc2" task-executor="taskExecutor" />

<int-amqp:outbound-channel-adapter channel="inputc2" exchange-name="exch" amqp-template="rabbitTemplate" order="1" />
<int:service-activator input-channel="inputc2" output-channel="nullChannel"
                       expression="@messageStore.removeMessage(headers['id'])" order="2" />

在调用commit之后,但此时消息为null,所以看起来我并没有要转发到committed通道的内容。你知道怎么做这部分吗?

这只有通过
事务同步才能实现

网桥实际上是TX的“边界”,但这里的提交实际上发生在
send()
方法之后。因为您的下一个通道有一个
执行器
,所以,当前事务线程无需做更多的事情,只在发送之后而不是之前执行提交

为了实现您的目标,您应该实施
MethodInterceptor
建议,通过
建议链将其注入
。并尝试使用
表达式EvaluationTransactionSynchronizationProcessor
使用
DefaultTransactionSynchronizationFactory
的逻辑,您将能够在提交通道后向
发送消息

建议中的代码应使用以下模板:

if (TransactionSynchronizationManager.isActualTransactionActive()) {
                TransactionSynchronization synchronization = this.transactionSynchronizationFactory.create(key);
                TransactionSynchronizationManager.registerSynchronization(synchronization);
}
其中,
可以是任何唯一的对象,以区分与TX同步的资源

更新

但此时消息是空的,所以我似乎没有什么要转发到提交的通道

这是正确的,因为您以不同寻常的方式使用
事务同步工厂

好吧,不管怎么说,让我们试着欺骗它,因为对我来说,你走的是正确的道路

factory.create(“123”)这样做:

    DefaultTransactionalResourceSynchronization synchronization = new DefaultTransactionalResourceSynchronization(key);
    TransactionSynchronizationManager.bindResource(key, synchronization.getResourceHolder());
    return synchronization;
这里的要点是TransactionSynchronizationManager.bindResource()
。我的想法是在TX结束之前,在下游的某个地方,这样做:

IntegrationResourceHolder holder =
                    (IntegrationResourceHolder) TransactionSynchronizationManager.getResource("123");
holder.setMessage(message);
我认为,即使这样,也有可能:

 <int:outbound-channel-adapter 
        expression="T(org.springframework.transaction.support.TransactionSynchronizationManager).getResource('123').setMessage(#root)"/>


作为退出TX之前的最后一个端点。

顺便说一句,此解决方案的目的是什么?为什么“事务管理器中的所有内容”线程的常规方式不适合您?如果TX失败,则消息不会在RabbitMQ代理上得到确认。好吧,在本例中,您是如何解释的,在send()方法之后,事务可能会失败。这意味着jdbc回滚了,但amqp出站适配器已经发送了消息(在本例中的其他线程中)——这种情况不应该发生。此外,我需要在将消息发送到此处之前确认消息,并且事务只会在之后确认它(如果在同一线程中).在这种情况下,您不需要JDBC,也不需要带有
执行器的
发布-订阅频道
。只是因为不会有任何可担心的
索赔检查。您收到来自RabbitMQ的消息,执行一些逻辑(而不是
声明检查
)并将结果发送到另一个AMQP交换。同一发送中的所有内容都是从
开始的,为什么?在发送到某处之前确认它有什么意义?如果发送失败怎么办?你的解释似乎前后矛盾。邮件已确认,但后续处理失败。请检查更新2,因为我在实现此解决方案时遇到一些问题。谢谢。请在我的答案中查找更新。谢谢帮助。现在我对getResource('123')有一个问题,因为它在类而不是TransactionSynchronizationManager上找到了这个方法。类具有字符串类型的getResource,TransactionSynchronizationManager具有对象类型的getResource,因此我必须告诉spring它应该使用带有对象参数的getResource。请尝试以下操作:
T(org.springframework.transaction.support.TransactionSynchronizationManager)。resourceMap[123]。setMessage(#root)
仍然错误:EL1011E:(位置94):方法调用:尝试在空上下文对象上调用方法setMessage(org.springframework.messaging.support.GenericMessage)
IntegrationResourceHolder holder =
                    (IntegrationResourceHolder) TransactionSynchronizationManager.getResource("123");
holder.setMessage(message);
 <int:outbound-channel-adapter 
        expression="T(org.springframework.transaction.support.TransactionSynchronizationManager).getResource('123').setMessage(#root)"/>