首先我们新建一个注定会消费失败的案例:
@RestController
public class TestController {
@Autowired
private TestTopic testTopic;
@RequestMapping("test")
public void TestError(@RequestParam String message){
testTopic.output().send(MessageBuilder.withPayload(message).build());
}
}
public interface TestTopic {
String OUTPUT = "example-topic-output";
String INPUT = "example-topic-input";
@Output(OUTPUT)
MessageChannel output();
@Input(INPUT)
SubscribableChannel input();
}
@Slf4j
@Component
@EnableBinding(TestTopic.class)
public class TestListener {
@StreamListener(TestTopic.INPUT)
public void receive(String payload) {
log.info("Received payload : " + payload);
throw new RuntimeException("Message consumer failed!");
}
}
spring.cloud.stream.bindings.example-topic-input.destination=test-topic
spring.cloud.stream.bindings.example-topic-input.group=stream-exception-handler
spring.cloud.stream.bindings.example-topic-input.consumer.max-attempts=1
spring.cloud.stream.bindings.example-topic-output.destination=test-topic
针对消息消费失败,在TestListener
中针对消息消费逻辑创建一段错误处理逻辑
@Slf4j
@Component
static class TestListener {
@StreamListener(TestTopic.INPUT)
public void receive(String payload) {
log.info("Received payload : " + payload);
throw new RuntimeException("Message consumer failed!");
}
/**
* 消息消费失败的降级处理逻辑
*
* @param message
*/
@ServiceActivator(inputChannel = "test-topic.stream-exception-handler.errors")
public void error(Message<?> message) {
log.info("Message consumer failed, call fallback!");
}
}
通过使用@ServiceActivator(inputChannel = "test-topic.stream-exception-handler.errors")
指定了某个通道的错误处理映射。其中,inputChannel的配置中对应关系如下:
test-topic
:消息通道对应的目标(destination,即:spring.cloud.stream.bindings.example-topic-input.destination
的配置)stream-exception-handler
:消息通道对应的消费组(group,即:spring.cloud.stream.bindings.example-topic-input.group
的配置)
不过这个版本的stream有一个bug,错误措施是采取的轮训方式,即:如果你写了一个错误处理,那么两次中有一次是使用你的错误处理,不过据说会在新版本中进行修复