最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Spring Cloud Stream 高級(jí)特性使用詳解

 更新時(shí)間:2022年09月07日 14:30:40   作者:Java浮華  
這篇文章主要為大家介紹了Spring Cloud Stream 高級(jí)特性使用詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

重試

Consumer端可以配置重試次數(shù),當(dāng)消息消費(fèi)失敗的時(shí)候會(huì)進(jìn)行重試。

底層使用Spring Retry去重試,重試次數(shù)可自定義配置。

# 默認(rèn)重試次數(shù)為3,配置大于1時(shí)才會(huì)生效
spring.cloud.stream.bindings.<channelName>.consumer.maxAttempte=3 

消息發(fā)送失敗的處理

Producer發(fā)送消息出錯(cuò)的情況下,可以配置錯(cuò)誤處理,將錯(cuò)誤信息發(fā)送給對(duì)應(yīng)ID的MessageChannel

  • 消息發(fā)送失敗的場(chǎng)景下,會(huì)將消息發(fā)送到一個(gè)MessageChannel。這個(gè)MessageChannel會(huì)取ApplicationContext中name為topic.errorstopic就是配置的destination)的Bean。
  • 如果找不到就會(huì)自動(dòng)構(gòu)建一個(gè)PublishSubscribeChannel。
  • 然后使用BridgeHandler訂閱這個(gè)MessageChannel,同時(shí)再設(shè)置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
# 消息發(fā)送失敗的處理邏輯默認(rèn)是關(guān)閉的
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);
        }
    }

消費(fèi)錯(cuò)誤處理

Consumer消費(fèi)消息出錯(cuò)的情況下,可以配置錯(cuò)誤處理,將錯(cuò)誤信息發(fā)給對(duì)應(yīng)ID的MessageChannel

消息錯(cuò)誤處理與生產(chǎn)錯(cuò)誤處理大致相同。錯(cuò)誤的MessageChannel對(duì)應(yīng)的name為topic.group.errors,還會(huì)加上多個(gè)MessageHandler訂閱的一些判斷,使用ErrorMessageStrategy創(chuàng)建錯(cuò)誤消息等內(nèi)容。

  • 示例代碼
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這個(gè)消息通道,并設(shè)置發(fā)送到單播模式的DirectChannel消息通道中(使用@ServiceActivator注解接收會(huì)直接構(gòu)成DirectChannel),這樣會(huì)確保只會(huì)被唯一的一個(gè)訂閱了topic.group.errorsMessageHandler處理,否則可能會(huì)被多個(gè)MessageHandler處理,導(dǎo)致出現(xiàn)一些意想不到的結(jié)果。

自定義MessageHandler類型

默認(rèn)情況下,Output Binding對(duì)應(yīng)的MessageChannelInput Binding對(duì)應(yīng)的SubscribeChannel會(huì)被構(gòu)造成DirectChannel

SCS提供了BindingTargetFactory接口進(jìn)行擴(kuò)展,比如可以擴(kuò)展構(gòu)造PublishSubscribeChannel這種廣播類型的MessageChannel。

BindingTargetFactory接口只有兩個(gè)實(shí)現(xiàn)類

  • SubscribableChannelBindingTargetFactory:針對(duì)Input BindingOutput Binding都會(huì)構(gòu)造成DirectWithAttributesChannel類型的MessageChannel(一種帶有HashMap屬性的DirectChannel)。
  • MessageSourceBindingTargetFactory:不支持Output BindingInput Binding會(huì)構(gòu)造成DefaultPollableMessageSource。DefaultPollableMessageSource內(nèi)部維護(hù)著MessageSource屬性,該屬性用于拉取消息。

Endpoint端點(diǎn)

SCS提供了BindingsEndpoint,可以獲取Binding信息或?qū)?code>Binding生命周期進(jìn)行修改,比如start、stop、pauseresume。

BindingsEndpoint的ID是bindings,對(duì)外暴露了一下3個(gè)操作:

  • 修改Binding狀態(tài),可以改成STARTEDSTOPPED、PAUSEDRESUMED,對(duì)應(yīng)Binding接口的4個(gè)操作。
  • 查詢單個(gè)Binding的狀態(tài)信息。
  • 查詢所有Binding的狀態(tài)信息。
@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指標(biāo)

該功能自動(dòng)與micrometer集成進(jìn)行Metrics統(tǒng)計(jì),可以通過(guò)前綴spring.cloud.stream.metrics進(jìn)行相關(guān)配置,配置項(xiàng)spring.cloud.stream.bindings.applicationMetrics.destination會(huì)構(gòu)造MetersPublisherBinding,將相關(guān)的metrics發(fā)送到MQ中。

Serverless

默認(rèn)與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統(tǒng)一

SCS統(tǒng)一Partition相關(guān)的設(shè)置,可以屏蔽不同MQ Partition的設(shè)置。

Producer Binding提供的ProducerProperties提供了一些Partition相關(guān)的配置:

  • partitionKeyExpression:partition key提取表達(dá)式。
  • partitionKeyExtractorName:是一個(gè)實(shí)現(xiàn)PartitionKeyExtractorStrategy接口的Bean name。PartitionKeyExtractorStrategy是一個(gè)根據(jù)Message獲取partition key的接口。如果兩者都配置,優(yōu)先級(jí)高于partitionKeyExtractorName。
  • partitionSelectorName:是一個(gè)實(shí)現(xiàn)PartitionSelectorStrategy接口的Bean name。PartitionSelectorStrategy是一個(gè)根據(jù)partition key決定選擇哪個(gè)partition 的接口。
  • partitionSelectorExpression:partition 選擇表達(dá)式,會(huì)根據(jù)表達(dá)式和partition key得到最終的partition。如果兩者都配置,優(yōu)先partitionSelectorExpression表達(dá)式解析partition。
  • partitionCount:partition 個(gè)數(shù)。該屬性不一定會(huì)生效,Kafka Binder 和RocketMQ Binder會(huì)使用topic上的partition 個(gè)數(shù)覆蓋該屬性。
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

實(shí)現(xiàn)MessageSource進(jìn)行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();
}

支持多個(gè)Binder同時(shí)使用

支持多個(gè)Binder同時(shí)使用,在配置Binding的時(shí)候需要指定對(duì)應(yīng)的Binder。

配置全局默認(rèn)的Binderspring.cloud.stream.default-binder=rocketmq

配置各個(gè)Binder內(nèi)部的配置信息:

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

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

配置Binding對(duì)應(yīng)的Binder

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

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

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

建立事件機(jī)制

比如,新建BindingCreateEvent事件,用戶的應(yīng)用就可以監(jiān)聽(tīng)該事件在創(chuàng)建Input BindingOutput Binding 時(shí)做業(yè)務(wù)相關(guān)的處理。

以上就是Spring Cloud Stream 高級(jí)特性使用詳解的詳細(xì)內(nèi)容,更多關(guān)于Spring Cloud Stream 高級(jí)特性的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評(píng)論

辽宁省| 高台县| 岚皋县| 米易县| 崇明县| 乐昌市| 江口县| 呼玛县| 临朐县| 林州市| 梅州市| 内江市| 林口县| 阿巴嘎旗| 长丰县| 九台市| 兴隆县| 阜康市| 商洛市| 南雄市| 庄河市| 凉山| 开封市| 海淀区| 惠来县| 馆陶县| 楚雄市| 颍上县| 桂平市| 囊谦县| 平遥县| 宁化县| 姚安县| 广平县| 铁力市| 双鸭山市| 梅河口市| 长沙县| 长寿区| 什邡市| 夏邑县|