我正在尝试使用Spring Integration 4.1.2参考指南中提到的@IdempotentReceiver注释和以下Java Config示例(修改为包含我的逻辑):
@Configuration
@EnableIntegration
public class IdempotentReceiverConfig {
public static class MyPayload {
public String transactionId;
public String data;
public MyPayload(final String transactionId, final String data) {
this.transactionId = transactionId;
this.data = data;
}
}
public static class MyTransformer {
public MyPayload process(final MyPayload input) {
MyPayload newPayload = new MyPayload(input.transactionId, input.data.toUpperCase());
return newPayload;
}
}
@Bean
public IdempotentReceiverInterceptor idempotentReceiverInterceptor() {
ExpressionParser parser = new SpelExpressionParser();
Expression exp = parser.parseExpression("payload.transactionId");
MetadataStoreSelector selector = new MetadataStoreSelector(new ExpressionEvaluatingMessageProcessor<String>(exp));
IdempotentReceiverInterceptor interceptor = new IdempotentReceiverInterceptor(selector);
interceptor.setDiscardChannel(discardChannel());
return interceptor;
}
@Bean
@ServiceActivator(inputChannel = "inputChannel1")
@IdempotentReceiver("idempotentReceiverInterceptor")
public MessageHandler myService1() {
ServiceActivatingHandler handler = new ServiceActivatingHandler(new MyTransformer(), "process");
handler.setOutputChannel(outputChannel());
return handler;
}
@Bean
@ServiceActivator(inputChannel = "inputChannel2", outputChannel = "outputChannel")
@IdempotentReceiver("idempotentReceiverInterceptor")
public Transformer myService2() {
return new MethodInvokingTransformer(new MyTransformer(), "process");
}
@Bean
public MessageChannel inputChannel1() {
return new DirectChannel();
}
@Bean
public MessageChannel inputChannel2() {
return new DirectChannel();
}
@Bean
public MessageChannel outputChannel() {
return new DirectChannel();
}
@Bean
public MessageChannel discardChannel() {
return new DirectChannel();
}
@Bean
@ServiceActivator(inputChannel = "outputChannel")
public LoggingHandler outputLoggingHandler() {
LoggingHandler handler = new LoggingHandler("INFO");
handler.setLoggerName("Success.LoggingHandler");
handler.setExpression("'Message passed: ' + payload.data");
return handler;
}
@Bean
@ServiceActivator(inputChannel = "discardChannel")
public LoggingHandler discardLoggingHandler() {
LoggingHandler handler = new LoggingHandler("WARN");
handler.setLoggerName("Fail.LoggingHandler");
handler.setExpression("'Message discarded: ' + payload.data");
return handler;
}
}
但是,如果我使用ServiceActivatingHandler(inputChannel1),似乎不会将IdempotentReceiverInterceptor应用于端点。如果我更改为XML配置或使用Transformer(inputChannel2),程序运行正常。
我通过向inputChannel1和inputChannel2发送两条消息来测试上述内容:
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(IdempotentReceiverConfig.class);
MessageChannel channel;
MyPayload payload = new MyPayload("1234", "testing");
channel = (MessageChannel) ctx.getBean("inputChannel1");
channel.send(new GenericMessage<MyPayload>(payload));
channel.send(new GenericMessage<MyPayload>(payload));
channel = (MessageChannel) ctx.getBean("inputChannel2");
channel.send(new GenericMessage<MyPayload>(payload));
channel.send(new GenericMessage<MyPayload>(payload));
结果是:
[main] [LoggingHandler] INFO - Message passed: TESTING
[main] [LoggingHandler] INFO - Message passed: TESTING
[main] [LoggingHandler] INFO - Message passed: TESTING
[main] [LoggingHandler] WARN - Message discarded: testing
所以我可以确认消息仍然转到MessageHandler以获取inputChannel1的情况。
经过一番研究,我发现Spring的AbstractMethodAnnotationPostProcessor.postProcess(...)方法具有以下处理IdempotentReceiver注释的逻辑:
if (AnnotatedElementUtils.isAnnotated(method, IdempotentReceiver.class.getName()) && !AnnotatedElementUtils.isAnnotated(method, Bean.class.getName())) {
...
}
在我看来,它同时不允许@Bean和@IdempotentReceiver。
是否有@IdempotentReceiver的工作样本?我错过了什么吗?
已编辑:使用完整配置更新了问题。 myService1()将返回一个ServiceActivatingHandler,它调用一个POJO转换器,myService2()使用一个Transformer。变换器只对payload.data字段执行简单的toUpperCase()操作,因此我们可以看看它是否已被调用。
答案 0 :(得分:1)
@IdempotentReceiver
级@Bean
IdempotentReceiverAutoProxyCreatorInitializer
由IdempotentReceiverIntegrationTests
解析。
我们有一个关于此问题的测试案例 - myService()
。
从另一方面来说:你想如何确保它按预期工作?
请显示您的AbstractMessageProducingHandler
内容。对于任何outputChannel
,必须将AbstractMessageProducingHandler
指定为outputChannel
实施的设置者。与@ServiceActivator
的<{1}}属性不同。
当我对此事做一些测试时,我会回复你。
<强>更新强>
我的测试用例证实一切正常:
@Bean
@ServiceActivator(inputChannel = "inputService")
@IdempotentReceiver("idempotentReceiverInterceptor")
public MessageHandler messageHandler() {
return new MessageHandler() {
@Override
public void handleMessage(Message<?> message) throws MessagingException {
if (message.getHeaders().containsKey(IntegrationMessageHeaderAccessor.DUPLICATE_MESSAGE)) {
throw new RuntimeException("Duplicate message");
}
}
};
}
我这样做:
Message<String> message = new GenericMessage<String>("bar");
this.inputService.send(message);
this.inputService.send(message);
如果idempotentReceiverInterceptor
尚未应用,则第二个send
通过,但不会。至少对我而言。
您是否可以最小化配置和测试以允许我重现您的问题?