Bootstrap

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() 中

;