spring cloud stream整合rocketmq流程

在学习 rocketmq,因为参数比较乱,在查看源码的过程中发现了 spring cloud stream整合rocketmq 发送消息的过程。记录如下

通过 @EnableBinding 引入 spring cloud stream 相关功能

@SpringBootApplication
@EnableBinding({ SyncAsyncMessageSource.class })
public class UseSpringCloudAlibabaSyncAsyncApplication {
    public static void main(String[] args) {
        SpringApplication.run(UseSpringCloudAlibabaSyncAsyncApplication.class, args);
    }
}

@EnableBinding

@Target({ ElementType.TYPE, ElementType.ANNOTATION_TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Configuration
@Import({ BindingBeansRegistrar.class, BinderFactoryAutoConfiguration.class })
@EnableIntegration
public @interface EnableBinding {

   /**
    * A list of interfaces having methods annotated with {@link Input} and/or
    * {@link Output} to indicate binding targets.
    * @return list of interfaces
    */
   Class<?>[] value() default {};

}

通过注解 @Import 得知引入 BinderFactoryAutoConfiguration 进行自动配置

BinderFactoryAutoConfiguration

@Bean
public BinderTypeRegistry binderTypeRegistry(
      ConfigurableApplicationContext configurableApplicationContext) {
   Map<String, BinderType> binderTypes = new HashMap<>();
   ClassLoader classLoader = configurableApplicationContext.getClassLoader();
   try {
      Enumeration<URL> resources = classLoader.getResources("META-INF/spring.binders");
      // see if test binder is available on the classpath and if so add it to the binderTypes
      try {
         BinderType bt = new BinderType("integration", new Class[] {
               classLoader.loadClass("org.springframework.cloud.stream.binder.test.TestChannelBinderConfiguration")});
         binderTypes.put("integration", bt);
      }
      catch (Exception e) {
         // ignore. means test binder is not available
      }

      if (binderTypes.isEmpty() && !Boolean.valueOf(this.selfContained)
            && (resources == null || !resources.hasMoreElements())) {
         this.logger.debug(
               "Failed to locate 'META-INF/spring.binders' resources on the classpath."
                     + " Assuming standard boot 'META-INF/spring.factories' configuration is used");
      }
      else {
         while (resources.hasMoreElements()) {
            URL url = resources.nextElement();
            UrlResource resource = new UrlResource(url);
            for (BinderType binderType : parseBinderConfigurations(classLoader, resource)) {
               binderTypes.put(binderType.getDefaultName(), binderType);
            }
         }
      }

   }
   catch (IOException | ClassNotFoundException e) {
      throw new BeanCreationException("Cannot create binder factory:", e);
   }
   return new DefaultBinderTypeRegistry(binderTypes);
}

通过 binderTypeRegistry() 加载 META-INF/spring.binders 文件中的配置。

pom.xml

<dependencies>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-starter-stream-rocketmq</artifactId>
        <exclusions>
            <exclusion>
                <groupId>org.apache.rocketmq</groupId>
                <artifactId>rocketmq-spring-boot-starter</artifactId>
            </exclusion>
        </exclusions>
    </dependency>

    <dependency>
        <groupId>org.apache.rocketmq</groupId>
        <artifactId>rocketmq-spring-boot-starter</artifactId>
        <version>2.0.2</version>
    </dependency>

</dependencies>

rocketmq-spring-boot-starter 引入了

<dependency>
    <groupId>org.apache.rocketmq</groupId>
    <artifactId>rocketmq-spring-boot</artifactId>
</dependency>

spring.binders

rocketmq:com.alibaba.cloud.stream.binder.rocketmq.config.RocketMQBinderAutoConfiguration

RocketMQBinderAutoConfiguration

@Configuration(proxyBeanMethods = false)
@Import({ RocketMQAutoConfiguration.class,
      RocketMQBinderHealthIndicatorAutoConfiguration.class })
@EnableConfigurationProperties({ RocketMQBinderConfigurationProperties.class,
      RocketMQExtendedBindingProperties.class })
public class RocketMQBinderAutoConfiguration {

   private final RocketMQExtendedBindingProperties extendedBindingProperties;

   private final RocketMQBinderConfigurationProperties rocketBinderConfigurationProperties;

   @Autowired(required = false)
   private RocketMQProperties rocketMQProperties = new RocketMQProperties();

   @Autowired
   public RocketMQBinderAutoConfiguration(
         RocketMQExtendedBindingProperties extendedBindingProperties,
         RocketMQBinderConfigurationProperties rocketBinderConfigurationProperties) {
      this.extendedBindingProperties = extendedBindingProperties;
      this.rocketBinderConfigurationProperties = rocketBinderConfigurationProperties;
   }

   @Bean
   public RocketMQTopicProvisioner provisioningProvider() {
      return new RocketMQTopicProvisioner();
   }

   @Bean
   public RocketMQMessageChannelBinder rocketMessageChannelBinder(
         RocketMQTopicProvisioner provisioningProvider,
         InstrumentationManager instrumentationManager) {
      RocketMQMessageChannelBinder binder = new RocketMQMessageChannelBinder(
            provisioningProvider, extendedBindingProperties,
            rocketBinderConfigurationProperties, rocketMQProperties,
            instrumentationManager);
      binder.setExtendedBindingProperties(extendedBindingProperties);
      return binder;
   }

   @Bean
   public InstrumentationManager instrumentationManager() {
      return new InstrumentationManager();
   }

}

配置类中创建了 RocketMQMessageChannelBinder 对象,将 rocketmq 相关配置赋值到对象中。

RocketMQMessageChannelBinder

创建 RocketMQMessageHandler 对象,间接调用 RocketMQTemplate 的相关方法进行数据操作。

protected MessageHandler createProducerMessageHandler(ProducerDestination destination,
        ExtendedProducerProperties<RocketMQProducerProperties> producerProperties,
        MessageChannel channel, MessageChannel errorChannel) throws Exception {
    if (producerProperties.getExtension().getEnabled()) {

        // 省略代码

        RocketMQMessageHandler messageHandler = new RocketMQMessageHandler(
                rocketMQTemplate, destination.getName(), producerGroup,
                producerProperties.getExtension().getTransactional(),
                instrumentationManager, producerProperties,
                ((AbstractMessageChannel) channel).getInterceptors().stream().filter(
                        channelInterceptor -> channelInterceptor instanceof MessageConverterConfigurer.PartitioningInterceptor)
                        .map(channelInterceptor -> ((MessageConverterConfigurer.PartitioningInterceptor) channelInterceptor))
                        .findFirst().orElse(null));
        messageHandler.setBeanFactory(this.getApplicationContext().getBeanFactory());
        messageHandler.setSync(producerProperties.getExtension().getSync());
        messageHandler.setHeaderMapper(createHeaderMapper(producerProperties));
        if (errorChannel != null) {
            messageHandler.setSendFailureChannel(errorChannel);
        }
        return messageHandler;
    }
    else {
        throw new RuntimeException("Binding for channel " + destination.getName()
                + " has been disabled, message can't be delivered");
    }
}

RocketMQMessageHandler 中通过handleMessageInternal() 调用 RocketMQTemplate 的相关方法进行数据操作

protected void handleMessageInternal(
        org.springframework.messaging.Message<?> message) {
    try {
        // issue 737 fix
        Map<String, String> jsonHeaders = headerMapper
                .fromHeaders(message.getHeaders());
        message = org.springframework.messaging.support.MessageBuilder
                .fromMessage(message).copyHeaders(jsonHeaders).build();

        final StringBuilder topicWithTags = new StringBuilder(destination);
        String tags = Optional
                .ofNullable(message.getHeaders().get(RocketMQHeaders.TAGS)).orElse("")
                .toString();
        if (!StringUtils.isEmpty(tags)) {
            topicWithTags.append(":").append(tags);
        }

        SendResult sendRes = null;
        if (transactional) {
            sendRes = rocketMQTemplate.sendMessageInTransaction(groupName,
                    topicWithTags.toString(), message, message.getHeaders()
                            .get(RocketMQBinderConstants.ROCKET_TRANSACTIONAL_ARG));
            log.debug("transactional send to topic " + topicWithTags + " " + sendRes);
        }
        else {
            int delayLevel = 0;
            try {
                Object delayLevelObj = message.getHeaders()
                        .getOrDefault(MessageConst.PROPERTY_DELAY_TIME_LEVEL, 0);
                if (delayLevelObj instanceof Number) {
                    delayLevel = ((Number) delayLevelObj).intValue();
                }
                else if (delayLevelObj instanceof String) {
                    delayLevel = Integer.parseInt((String) delayLevelObj);
                }
            }
            catch (Exception e) {
                // ignore
            }
            boolean needSelectQueue = message.getHeaders()
                    .containsKey(BinderHeaders.PARTITION_HEADER);
            if (sync) {
                if (needSelectQueue) {
                    sendRes = rocketMQTemplate.syncSendOrderly(
                            topicWithTags.toString(), message, "",
                            rocketMQTemplate.getProducer().getSendMsgTimeout());
                }
                else {
                    sendRes = rocketMQTemplate.syncSend(topicWithTags.toString(),
                            message,
                            rocketMQTemplate.getProducer().getSendMsgTimeout(),
                            delayLevel);
                }
                log.debug("sync send to topic " + topicWithTags + " " + sendRes);
            }
            else {
                Message<?> finalMessage = message;
                SendCallback sendCallback = new SendCallback() {
                    @Override
                    public void onSuccess(SendResult sendResult) {
                        log.debug("async send to topic " + topicWithTags + " "
                                + sendResult);
                    }

                    @Override
                    public void onException(Throwable e) {
                        log.error("RocketMQ Message hasn't been sent. Caused by "
                                + e.getMessage());
                        if (getSendFailureChannel() != null) {
                            getSendFailureChannel().send(
                                    RocketMQMessageHandler.this.errorMessageStrategy
                                            .buildErrorMessage(new MessagingException(
                                                    finalMessage, e), null));
                        }
                    }
                };
                if (needSelectQueue) {
                    rocketMQTemplate.asyncSendOrderly(topicWithTags.toString(),
                            message, "", sendCallback,
                            rocketMQTemplate.getProducer().getSendMsgTimeout());
                }
                else {
                    rocketMQTemplate.asyncSend(topicWithTags.toString(), message,
                            sendCallback);
                }
            }
        }
        if (sendRes != null && !sendRes.getSendStatus().equals(SendStatus.SEND_OK)) {
            if (getSendFailureChannel() != null) {
                this.getSendFailureChannel().send(message);
            }
            else {
                throw new MessagingException(message,
                        new MQClientException("message hasn't been sent", null));
            }
        }
    }
    catch (Exception e) {
        log.error("RocketMQ Message hasn't been sent. Caused by " + e.getMessage());
        if (getSendFailureChannel() != null) {
            getSendFailureChannel().send(this.errorMessageStrategy
                    .buildErrorMessage(new MessagingException(message, e), null));
        }
        else {
            throw new MessagingException(message, e);
        }
    }

}

父类 AbstractMessageChannelBinder

通过 doBindProducer() 调用 createProducerMessageHandler() 返回实现了 MessageHandler 的对象

public final Binding<MessageChannel> doBindProducer(final String destination,
        MessageChannel outputChannel, final P producerProperties)
        throws BinderException {
    
    Assert.isInstanceOf(SubscribableChannel.class, outputChannel,
                "Binding is supported only for SubscribableChannel instances");
        final MessageHandler producerMessageHandler;
        final ProducerDestination producerDestination;
        try {
            producerDestination = this.provisioningProvider
                    .provisionProducerDestination(destination, producerProperties);
            SubscribableChannel errorChannel = producerProperties.isErrorChannelEnabled()
                    ? registerErrorInfrastructure(producerDestination) : null;
            producerMessageHandler = createProducerMessageHandler(producerDestination,
                    producerProperties, outputChannel, errorChannel);
            customizeProducerMessageHandler(producerMessageHandler, producerDestination.getName());
            if (producerMessageHandler instanceof InitializingBean) {
                ((InitializingBean) producerMessageHandler).afterPropertiesSet();
            }
        }
        catch (Exception e) {
            if (e instanceof BinderException) {
                throw (BinderException) e;
            }
            else if (e instanceof ProvisioningException) {
                throw (ProvisioningException) e;
            }
            else {
                throw new BinderException(
                        "Exception thrown while building outbound endpoint", e);
            }
        }
    
    // 省略代码
    
    return binding;
}

doBindProducer() 针对生产者

doBindConsumer() 针对消费者

调用 RocketMQTemplate 方法发送消息

syncSend() 同步发送消息

asyncSend() 异步发送消息

通过调用 MessageChannel 的 send() 调用了消息发送,间接调用了 AbstractMessageChannel (spring-intergration)的 send() 中

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring Cloud StreamSpring Cloud 生态系统中的一部分,它提供了一种简单且可扩展的方式来构建消息驱动的微服务应用程序。而 RocketMQ 是一款开源的分布式消息中间件,它具有高可靠、高吞吐量、高可扩展性等特点。在 Spring Cloud Stream 中,我们可以通过集成 RocketMQ 来实现消息驱动的微服务应用程序。 下面是 Spring Cloud Stream 集成 RocketMQ 的详细文档: 1. 添加依赖 首先,我们需要添加 Spring Cloud StreamRocketMQ 的相关依赖。在 pom.xml 文件中添加以下依赖: ``` <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-stream</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-stream-binder-rocketmq</artifactId> </dependency> <dependency> <groupId>org.apache.rocketmq</groupId> <artifactId>rocketmq-spring-boot-starter</artifactId> <version>2.2.0</version> </dependency> ``` 2. 配置 RocketMQ 在 application.properties 文件中添加 RocketMQ 的相关配置,例如: ``` spring.cloud.stream.rocketmq.binder.namesrv-addr=127.0.0.1:9876 spring.cloud.stream.rocketmq.binder.group=rocketmq-group rocketmq.name-server=127.0.0.1:9876 rocketmq.producer.group=rocketmq-producer-group rocketmq.consumer.group=rocketmq-consumer-group ``` 3. 定义消息通道 在 Spring Cloud Stream 中,消息是通过消息通道来传递的。我们需要定义输入通道和输出通道,例如: ``` public interface MyChannel { String INPUT = "my_input"; String OUTPUT = "my_output"; @Input(INPUT) SubscribableChannel input(); @Output(OUTPUT) MessageChannel output(); } ``` 4. 发送消息 我们可以通过注入 MessageChannel 来发送消息,例如: ``` @Autowired @Qualifier(MyChannel.OUTPUT) private MessageChannel myOutput; public void sendMessage(String message) { myOutput.send(MessageBuilder.withPayload(message).build()); } ``` 5. 接收消息 我们可以通过注入 SubscribableChannel 来接收消息,例如: ``` @StreamListener(MyChannel.INPUT) public void handleMessage(Message<String> message) { log.info("Received message: {}", message.getPayload()); } ``` 6. 集成 RocketMQ 消费者 我们也可以通过集成 RocketMQ 的消费者来接收消息,例如: ``` @Slf4j @Component @RocketMQMessageListener(consumerGroup = "${rocketmq.consumer.group}", topic = MyChannel.INPUT) public class MyRocketMQConsumer implements RocketMQListener<String> { @Override public void onMessage(String message) { log.info("Received message: {}", message); } } ``` 7. 集成 RocketMQ 生产者 我们也可以通过集成 RocketMQ 的生产者来发送消息,例如: ``` @Slf4j @Component public class MyRocketMQProducer { @Autowired private RocketMQTemplate rocketMQTemplate; public void sendMessage(String message) { rocketMQTemplate.convertAndSend(MyChannel.OUTPUT, message); } } ``` 以上就是 Spring Cloud Stream 集成 RocketMQ 的详细文档。通过这种方式,我们可以快速构建消息驱动的微服务应用程序,并且具有高可靠、高吞吐量、高可扩展性等特点。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值