在学习 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);
}
}
@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 进行自动配置
@Bean
public BinderTypeRegistry binderTypeRegistry(
ConfigurableApplicationContext configurableApplicationContext) {
Map binderTypes = new HashMap<>();
ClassLoader classLoader = configurableApplicationContext.getClassLoader();
try {
Enumeration 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 文件中的配置。
org.springframework.boot
spring-boot-starter-web
com.alibaba.cloud
spring-cloud-starter-stream-rocketmq
org.apache.rocketmq
rocketmq-spring-boot-starter
org.apache.rocketmq
rocketmq-spring-boot-starter
2.0.2
rocketmq-spring-boot-starter 引入了
org.apache.rocketmq
rocketmq-spring-boot
rocketmq:com.alibaba.cloud.stream.binder.rocketmq.config.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 相关配置赋值到对象中。
创建 RocketMQMessageHandler 对象,间接调用 RocketMQTemplate 的相关方法进行数据操作。
protected MessageHandler createProducerMessageHandler(ProducerDestination destination,
ExtendedProducerProperties 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 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 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() 中