Spring Cloud Stream 高级特性使用详解

2023-01-21 0 3,959

目录

重试

Consumer端可以配置重试次数,当消息消费失败的时候会进行重试。

底层使用Spring Retry去重试,重试次数可自定义配置。

# 默认重试次数为3,配置大于1时才会生效
spring.cloud.stream.bindings.<channelName>.consumer.maxAttempte=3 

消息发送失败的处理

Producer发送消息出错的情况下,可以配置错误处理,将错误信息发送给对应ID的MessageChannel

  • 消息发送失败的场景下,会将消息发送到一个MessageChannel。这个MessageChannel会取ApplicationContextnametopic.errorstopic就是配置的destination)的Bean。
  • 如果找不到就会自动构建一个PublishSubscribeChannel
  • 然后使用BridgeHandler订阅这个MessageChannel,同时再设置ApplicationContext中name为errorChannelPublishSubscribeChannel消息通道为BridgeHandleroutputChannel
    public static final String ERROR_CHANNEL_BEAN_NAME = \"errorChannel\"
    private SubscribableChannel registerErrorInfrastructure(
            ProducerDestination destination) {
        // destination.getName() + \".errors\"
        String errorChannelName = errorsBaseName(destination);
        SubscribableChannel errorChannel;
        if (getApplicationContext().containsBean(errorChannelName)) {
            Object errorChannelObject = getApplicationContext().getBean(errorChannelName);
            if (!(errorChannelObject instanceof SubscribableChannel)) {
                throw new IllegalStateException(\"Error channel \'\" + errorChannelName
                        + \"\' must be a SubscribableChannel\");
            }
            errorChannel = (SubscribableChannel) errorChannelObject;
        }
        else {
            errorChannel = new PublishSubscribeChannel();
            ((GenericApplicationContext) getApplicationContext()).registerBean(
                    errorChannelName, SubscribableChannel.class, () -> errorChannel);
        }
        MessageChannel defaultErrorChannel = null;
        if (getApplicationContext()
                .containsBean(IntegrationContextUtils.ERROR_CHANNEL_BEAN_NAME)) {
            defaultErrorChannel = getApplicationContext().getBean(
                    IntegrationContextUtils.ERROR_CHANNEL_BEAN_NAME,
                    MessageChannel.class);
        }
        if (defaultErrorChannel != null) {
            BridgeHandler errorBridge = new BridgeHandler();
            errorBridge.setOutputChannel(defaultErrorChannel);
            errorChannel.subscribe(errorBridge);
            String errorBridgeHandlerName = getErrorBridgeName(destination);
            ((GenericApplicationContext) getApplicationContext()).registerBean(
                    errorBridgeHandlerName, BridgeHandler.class, () -> errorBridge);
        }
        return errorChannel;
    }
  • 示例代码
spring.cloud.stream.bindings.output.destination=test-output
# 消息发送失败的处理逻辑默认是关闭的
spring.cloud.stream.bindings.output.producer.errorChannelEnabled=true
    @Bean(\"test-output.errors\")
    MessageChannel testOutputErrorChannel() {
        return new PublishSubscribeChannel();
    }
    @Service
    class ErrorProduceService {
        @ServiceActivator(inputChannel = \"test-output.errors\")
        public void receiveProduceError(Message receiveMsg) {
            System.out.println(\"receive error msg: \" + receiveMsg);
        }
    }

消费错误处理

Consumer消费消息出错的情况下,可以配置错误处理,将错误信息发给对应ID的MessageChannel

消息错误处理与生产错误处理大致相同。错误的MessageChannel对应的name为topic.group.errors,还会加上多个MessageHandler订阅的一些判断,使用ErrorMessageStrategy创建错误消息等内容。

  • 示例代码
spring.cloud.stream.bindings.input.destination=test-input
spring.cloud.stream.bindings.input.group=test-input-group
@StreamListener(Sink.INPUT)
public void receive(String receiveMsg) {
    throw new RuntimeException(\"Oops\");
}
@ServiceActivator(inputChannel = \"test-input.test-input-group.errors\")
public void receiveConsumeError(Message receiveMsg) {
    System.out.println(\"receive error msg: \" + receiveMsg);
}

建议直接使用topic.group.errors这个消息通道,并设置发送到单播模式的DirectChannel消息通道中(使用@ServiceActivator注解接收会直接构成DirectChannel),这样会确保只会被唯一的一个订阅了topic.group.errorsMessageHandler处理,否则可能会被多个MessageHandler处理,导致出现一些意想不到的结果。

自定义MessageHandler类型

默认情况下,Output Binding对应的MessageChannelInput Binding对应的SubscribeChannel会被构造成DirectChannel

SCS提供了BindingTargetFactory接口进行扩展,比如可以扩展构造PublishSubscribeChannel这种广播类型的MessageChannel

BindingTargetFactory接口只有两个实现类

  • SubscribableChannelBindingTargetFactory:针对Input BindingOutput Binding都会构造成DirectWithAttributesChannel类型的MessageChannel(一种带有HashMap属性的DirectChannel)。
  • MessageSourceBindingTargetFactory:不支持Output BindingInput Binding会构造成DefaultPollableMessageSourceDefaultPollableMessageSource内部维护着MessageSource属性,该属性用于拉取消息。

Endpoint端点

SCS提供了BindingsEndpoint,可以获取Binding信息或对Binding生命周期进行修改,比如startstoppauseresume

BindingsEndpoint的ID是bindings,对外暴露了一下3个操作:

  • 修改Binding状态,可以改成STARTEDSTOPPEDPAUSEDRESUMED,对应Binding接口的4个操作。
  • 查询单个Binding的状态信息。
  • 查询所有Binding的状态信息。
@Endpoint(id = \"bindings\")
public class BindingsEndpoint {
  ...
  @WriteOperation
    public void changeState(@Selector String name, State state) {
        Binding<?> binding = BindingsEndpoint.this.locateBinding(name);
        if (binding != null) {
            switch (state) {
            case STARTED:
                binding.start();
                break;
            case STOPPED:
                binding.stop();
                break;
            case PAUSED:
                binding.pause();
                break;
            case RESUMED:
                binding.resume();
                break;
            default:
                break;
            }
        }
    }
    @ReadOperation
    public List<?> queryStates() {
        List<Binding<?>> bindings = new ArrayList<>(gatherInputBindings());
        bindings.addAll(gatherOutputBindings());
        return this.objectMapper.convertValue(bindings, List.class);
    }
    @ReadOperation
    public Binding<?> queryState(@Selector String name) {
        Assert.notNull(name, \"\'name\' must not be null\");
        return this.locateBinding(name);
    }
  ...
}

Metrics指标

该功能自动与micrometer集成进行Metrics统计,可以通过前缀spring.cloud.stream.metrics进行相关配置,配置项spring.cloud.stream.bindings.applicationMetrics.destination会构造MetersPublisherBinding,将相关的metrics发送到MQ中。

Serverless

默认与Spring Cloud Function集成。

可以使用Function处理消息。配置文件需要加上function配置。

spring.cloud.stream.function.definition=uppercase | addprefix

  @Bean
  public Function<String, String> uppercase() {
      return x -> x.toUpperCase();
  }
  @Bean
  public Function<String, String> addprefix() {
      return x -> \"prefix-\" + x;
  }

Partition统一

SCS统一Partition相关的设置,可以屏蔽不同MQ Partition的设置。

Producer Binding提供的ProducerProperties提供了一些Partition相关的配置:

  • partitionKeyExpression:partition key提取表达式。
  • partitionKeyExtractorName:是一个实现PartitionKeyExtractorStrategy接口的Bean name。PartitionKeyExtractorStrategy是一个根据Message获取partition key的接口。如果两者都配置,优先级高于partitionKeyExtractorName
  • partitionSelectorName:是一个实现PartitionSelectorStrategy接口的Bean name。PartitionSelectorStrategy是一个根据partition key决定选择哪个partition 的接口。
  • partitionSelectorExpression:partition 选择表达式,会根据表达式和partition key得到最终的partition。如果两者都配置,优先partitionSelectorExpression表达式解析partition。
  • partitionCount:partition 个数。该属性不一定会生效,Kafka Binder 和RocketMQ Binder会使用topic上的partition 个数覆盖该属性。
public final class PartitioningInterceptor implements ChannelInterceptor {
      ...
      @Override
      public Message<?> preSend(Message<?> message, MessageChannel channel) {
      if (!message.getHeaders().containsKey(BinderHeaders.PARTITION_OVERRIDE)) {
        int partition = this.partitionHandler.determinePartition(message);
        return MessageConverterConfigurer.this.messageBuilderFactory
          .fromMessage(message)
          .setHeader(BinderHeaders.PARTITION_HEADER, partition).build();
      }
      else {
        return MessageConverterConfigurer.this.messageBuilderFactory
          .fromMessage(message)
          .setHeader(BinderHeaders.PARTITION_HEADER,
                     message.getHeaders()
                     .get(BinderHeaders.PARTITION_OVERRIDE))
          .removeHeader(BinderHeaders.PARTITION_OVERRIDE).build();
      }
    }
}
public class PartitionHandler {
      ...
      public int determinePartition(Message<?> message) {
        Object key = extractKey(message);
        int partition;
        if (this.producerProperties.getPartitionSelectorExpression() != null) {
            partition = this.producerProperties.getPartitionSelectorExpression()
                    .getValue(this.evaluationContext, key, Integer.class);
        }
        else {
            partition = this.partitionSelectorStrategy.selectPartition(key,
                    this.partitionCount);
        }
        // protection in case a user selector returns a negative.
        return Math.abs(partition % this.partitionCount);
    }
    private Object extractKey(Message<?> message) {
        Object key = invokeKeyExtractor(message);
        if (key == null && this.producerProperties.getPartitionKeyExpression() != null) {
            key = this.producerProperties.getPartitionKeyExpression()
                    .getValue(this.evaluationContext, message);
        }
        Assert.notNull(key, \"Partition key cannot be null\");
        return key;
    }
      ...
}

Polling Consumer

实现MessageSource进行polling操作的Consumer

普通的Pub/Sub模式需要定义SubscribeableChannel类型的返回值,Polling Consumer需要定义PollableMessageSource类型的返回值。

public interface PollableSink {
    /**
     * Input channel name.
     */
    String INPUT = \"input\";
    /**
     * @return input channel.
     */
    @Input(Sink.INPUT)
    PollableMessageSource input();
}

支持多个Binder同时使用

支持多个Binder同时使用,在配置Binding的时候需要指定对应的Binder

配置全局默认的Binderspring.cloud.stream.default-binder=rocketmq

配置各个Binder内部的配置信息:

spring.cloud.stream.binders.rocketmq.environment.<xx>=xx

spring.cloud.stream.binders.rocketmq.type=rocketmq

配置Binding对应的Binder

spring.cloud.stream.bindings.<channelName>.binder=kafka

spring.cloud.stream.bindings.<channelName>.binder=rocketmq

spring.cloud.stream.bindings.<channelName>.binder=rabbit

建立事件机制

比如,新建BindingCreateEvent事件,用户的应用就可以监听该事件在创建Input BindingOutput Binding 时做业务相关的处理。

以上就是Spring Cloud Stream 高级特性使用详解的详细内容,更多关于Spring Cloud Stream 高级特性的资料请关注其它相关文章!

:本文采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可, 转载请附上原文出处链接。
1、本站提供的源码不保证资源的完整性以及安全性,不附带任何技术服务!
2、本站提供的模板、软件工具等其他资源,均不包含技术服务,请大家谅解!
3、本站提供的资源仅供下载者参考学习,请勿用于任何商业用途,请24小时内删除!
4、如需商用,请购买正版,由于未及时购买正版发生的侵权行为,与本站无关。
5、本站部分资源存放于百度网盘或其他网盘中,请提前注册好百度网盘账号,下载安装百度网盘客户端或其他网盘客户端进行下载;
6、本站部分资源文件是经压缩后的,请下载后安装解压软件,推荐使用WinRAR和7-Zip解压软件。
7、如果本站提供的资源侵犯到了您的权益,请邮件联系: 442469558@qq.com 进行处理!

猪小侠源码-最新源码下载平台 Java教程 Spring Cloud Stream 高级特性使用详解 http://www.20zxx.cn/463885/xuexijiaocheng/javajc.html

猪小侠源码,优质资源分享网

常见问题
  • 本站所有资源版权均属于原作者所有,均只能用于参考学习,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担
查看详情
  • 最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,建议提前注册好百度网盘账号,使用百度网盘客户端下载
查看详情

相关文章

官方客服团队

为您解决烦忧 - 24小时在线 专业服务