Java AggregatingMessageHandler的手动确认
我正在尝试构建这样的集成场景Java AggregatingMessageHandler的手动确认,java,spring,spring-integration,amqp,spring-amqp,Java,Spring,Spring Integration,Amqp,Spring Amqp,我正在尝试构建这样的集成场景Rabbit->AmqpInboundChannelAdapter(AcknowledgeMode.MANUAL)->DirectChannel->AggregatingMessageHandler->DirectChannel->amqOutboundEndpoint 我想聚合内存中的消息,如果我聚合了10条消息,或者达到了10秒的超时时间,就释放它。我想这个配置还可以: @Bean @ServiceActivator(inputChannel = "amqpInp
Rabbit->AmqpInboundChannelAdapter(AcknowledgeMode.MANUAL)->DirectChannel->AggregatingMessageHandler->DirectChannel->amqOutboundEndpoint
我想聚合内存中的消息,如果我聚合了10条消息,或者达到了10秒的超时时间,就释放它。我想这个配置还可以:
@Bean
@ServiceActivator(inputChannel = "amqpInputChannel")
public MessageHandler aggregator(){
AggregatingMessageHandler aggregatingMessageHandler = new AggregatingMessageHandler(new DefaultAggregatingMessageGroupProcessor(), new SimpleMessageStore(10));
aggregatingMessageHandler.setCorrelationStrategy(new HeaderAttributeCorrelationStrategy(AmqpHeaders.CORRELATION_ID));
//default false
aggregatingMessageHandler.setExpireGroupsUponCompletion(true); //when grp released (using strategy), remove group so new messages in same grp create new group
aggregatingMessageHandler.setSendPartialResultOnExpiry(true); //when expired because timeout and not because of strategy, still send messages grouped so far
aggregatingMessageHandler.setGroupTimeoutExpression(new ValueExpression<>(TimeUnit.SECONDS.toMillis(10))); //timeout after X
//timeout is checked only when new message arrives!!
aggregatingMessageHandler.setReleaseStrategy(new TimeoutCountSequenceSizeReleaseStrategy(10, TimeUnit.SECONDS.toMillis(10)));
aggregatingMessageHandler.setOutputChannel(amqpOutputChannel());
return aggregatingMessageHandler;
}
及
@服务
公共类ManualAckServiceActivator{
@ServiceActivator(inputChannel=“manualAckChannel”)
公共无效句柄(@表头(手动确认对)列表手动确认对){
manualAckPair.forEach(manualAckPair->{
manualAckPair.basicAck();
});
}
}
没错,聚合器不需要如此复杂的逻辑
您只需在聚合器发布后确认它们-在聚合器和该AmqpOutboundEndpoint
之间的service activator中
您必须在那里使用basicAck()
,并将multiple
标志设置为true
:
@param multiple true to acknowledge all messages up to and
因此,您肯定需要一个自定义的MessageGroupProcessor
来提取整个批处理的最高AmqpHeaders.DELIVERY_标记
,并将其设置为输出聚合消息的头
您可以只扩展DefaultAggregatingMessageGroupProcessor
并覆盖其aggregateHeaders()
:
/**
*此默认实现只返回组中没有冲突的所有头。缺席的头球
*在组中的一个或多个邮件上,不视为冲突。子类可以用
*如有必要,提供更高级的冲突解决策略。
*
*@param group消息组。
*@返回聚合的标题。
*/
受保护的映射聚合头(MessageGroup){
如果我在聚合器发布后确认消息,消息不可能到达AmqpOutboundEndpoint
但我仍然确认它们(意味着它们从AMQP队列中丢失)?我知道这不太可能,但仍然是一个问题???您正在确认接收到的消息。这与生成的消息无关。或者您只想在正确发送到其他AMQP队列时确认?是的,我想确认接收消息(在AmqpInboundChannelAdapter(AcknowledgeMode.MANUAL)
)。基本上等待10秒钟,以便聚合消息并将其释放到新的exchange。如果释放(到AMQP exchange)成功,则仅确认接收到的消息(在接收到的AMQP队列上)。我这里需要某种消息节流器/聚合器。好的。因此,使用那些AmqpHeaders.CHANNEL
和最高的AmqpHeaders.DELIVERY_标记
头作为basicAck()的选项
在amqoutboundendpoint
的confirmCalback
中。查看它的confirmAckChannel
:这里的最高值是否正确?因为我只能将1234条消息中的一条(2,3,4)进行聚合并发送,而1仍在等待聚合和发送。我假设如果使用最高值,我会丢失1?
public class ManualAckPair {
private Channel channel;
private Long deliveryTag;
public ManualAckPair(Channel channel, Long deliveryTag) {
this.channel = channel;
this.deliveryTag = deliveryTag;
}
public void basicAck(){
try {
this.channel.basicAck(this.deliveryTag, false);
}
catch (IOException e) {
e.printStackTrace();
}
}
}
public abstract class AbstractManualAckAggregatingMessageGroupProcessor extends AbstractAggregatingMessageGroupProcessor {
public static final String MANUAL_ACK_PAIRS = PREFIX + "manualAckPairs";
@Override
protected Map<String, Object> aggregateHeaders(MessageGroup group) {
Map<String, Object> aggregatedHeaders = super.aggregateHeaders(group);
List<ManualAckPair> manualAckPairs = new ArrayList<>();
group.getMessages().forEach(m -> {
Channel channel = (Channel)m.getHeaders().get(AmqpHeaders.CHANNEL);
Long deliveryTag = (Long)m.getHeaders().get(AmqpHeaders.DELIVERY_TAG);
manualAckPairs.add(new ManualAckPair(channel, deliveryTag));
});
aggregatedHeaders.put(MANUAL_ACK_PAIRS, manualAckPairs);
return aggregatedHeaders;
}
}
@Service
public class ManualAckServiceActivator {
@ServiceActivator(inputChannel = "manualAckChannel")
public void handle(@Header(MANUAL_ACK_PAIRS) List<ManualAckPair> manualAckPairs) {
manualAckPairs.forEach(manualAckPair -> {
manualAckPair.basicAck();
});
}
}
@param multiple true to acknowledge all messages up to and
/**
* This default implementation simply returns all headers that have no conflicts among the group. An absent header
* on one or more Messages within the group is not considered a conflict. Subclasses may override this method with
* more advanced conflict-resolution strategies if necessary.
*
* @param group The message group.
* @return The aggregated headers.
*/
protected Map<String, Object> aggregateHeaders(MessageGroup group) {