所以,这是我目前的设置:
<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" />
并且图像是:
我需要的是事务(transaction-manager =&#34; dataSourceTransactionManager&#34;它应该是粉红色的部分)在任何消息被转发到int:brdige或int:bridge(蓝色)之前完全提交arrow - 所以bridge是边界组件,只有在jdbc已提交时才应实际转发消息。)
谢谢!
更新
以下是我需要这种设置的原因:
USE CASE:接收amqp消息,处理它并保存到db并将生成的amqp消息转发到管道中。消息不应丢失(既没有到达也没有消息,例如断电等)。 形成序列的多条消息可以到达具有相同组织的多个不同进程,如下所示。
我想如何解决它:
线程1:
线程2:
THREAD3:
更新2
试过这个设置,但有一些问题:
<int:transaction-synchronization-factory id="transactionSynchronizationFactory">
<int:after-commit expression="payload" channel="committed-channel" />
</int:transaction-synchronization-factory>
<int-amqp:inbound-channel-adapter channel="input-channel" queue-names="probni" message-converter="jsonMessageConverter"
channel-transacted="true"
transaction-manager="dataSourceTransactionManager" advice-chain="amqpMethodInterceptor"/>
和
@Component
public class AmqpMethodInterceptor implements MethodInterceptor {
private TransactionSynchronizationFactory factory;
public AmqpMethodInterceptor(TransactionSynchronizationFactory factory){
this.factory = factory;
}
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
if (TransactionSynchronizationManager.isActualTransactionActive()) {
TransactionSynchronization synchronization = factory.create("123");
TransactionSynchronizationManager.registerSynchronization(synchronization);
}
Object result = invocation.proceed();
return result;
}
}
调用after-commit,但此时此消息为null,因此似乎没有任何内容可以转发到committed-channel。知道如何做这个部分吗?
答案 0 :(得分:1)
只有使用TransactionSynchronization
才能实现。
这座桥真的是边界&#34; TX,但这里的提交确实发生在send()
方法之后。仅仅因为你的下一个频道有一个executor
,所以,当前的事务线程无需做更多事情,只在发送之后执行提交,而不是之前。
为了实现目标,您应该通过MethodInterceptor
实施<int-amqp:inbound-channel-adapter>
建议以注入advice-chain
。并尝试将DefaultTransactionSynchronizationFactory
的逻辑与ExpressionEvaluatingTransactionSynchronizationProcessor
一起使用,您可以在其中向afterCommitChannel
发送消息。
Advice
中的代码应使用此模板:
if (TransactionSynchronizationManager.isActualTransactionActive()) {
TransactionSynchronization synchronization = this.transactionSynchronizationFactory.create(key);
TransactionSynchronizationManager.registerSynchronization(synchronization);
}
其中key
可以是任何唯一的对象,以区分与TX同步的资源。
<强>更新强>
但此时此消息为空,因此我似乎无需转发到已提交的通道。
这是真的,因为你以不寻常的方式使用TransactionSynchronizationFactory
。
好吧,不管怎样,让我们试着欺骗它,因为对我来说你是正确的。
factory.create("123");
执行此操作:
DefaultTransactionalResourceSynchronization synchronization = new DefaultTransactionalResourceSynchronization(key);
TransactionSynchronizationManager.bindResource(key, synchronization.getResourceHolder());
return synchronization;
主要有{{1}}。我的想法在下游的某个地方,在TX结束之前,这样做:
TransactionSynchronizationManager.bindResource()
我认为即便可以做到这一点:
IntegrationResourceHolder holder =
(IntegrationResourceHolder) TransactionSynchronizationManager.getResource("123");
holder.setMessage(message);
作为退出TX之前的最后一个端点。