From cbd64061cecc394a9467a7c98b4dd52c1f4c2061 Mon Sep 17 00:00:00 2001 From: zkzlx Date: Mon, 1 Feb 2021 11:23:10 +0800 Subject: [PATCH 1/6] Code refactoring and some new feature support --- pom.xml | 15 +- .../pom.xml | 7 +- .../binder/rocketmq/RocketMQBinderUtils.java | 89 -- .../RocketMQMessageChannelBinder.java | 295 ++---- .../RocketMQBinderHealthIndicator.java | 10 +- .../RocketMQListenerBindingContainer.java | 935 +++++++++--------- .../RocketMQInboundChannelAdapter.java | 176 ---- .../integration/RocketMQMessageHandler.java | 302 ------ .../integration/RocketMQMessageSource.java | 382 ------- .../rocketmq/metrics/Instrumentation.java | 21 + .../metrics/InstrumentationManager.java | 35 +- ...RocketMQBinderConfigurationProperties.java | 81 +- .../properties/RocketMQBindingProperties.java | 49 - .../RocketMQConsumerProperties.java | 429 ++++++-- .../RocketMQExtendedBindingProperties.java | 12 +- .../RocketMQProducerProperties.java | 201 ++-- .../PartitionMessageQueueSelector.java | 2 +- 17 files changed, 1111 insertions(+), 1930 deletions(-) delete mode 100644 spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/RocketMQBinderUtils.java delete mode 100644 spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/integration/RocketMQInboundChannelAdapter.java delete mode 100644 spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/integration/RocketMQMessageHandler.java delete mode 100644 spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/integration/RocketMQMessageSource.java delete mode 100644 spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/properties/RocketMQBindingProperties.java diff --git a/pom.xml b/pom.xml index 7f9f0f88b..3fd389aca 100644 --- a/pom.xml +++ b/pom.xml @@ -98,6 +98,7 @@ 4.0.1 + 4.6.1 2.0.2 @@ -258,10 +259,20 @@ + + + + + org.apache.rocketmq - rocketmq-spring-boot-starter - ${rocketmq.starter.version} + rocketmq-client + ${rocketmq.version} + + + org.apache.rocketmq + rocketmq-acl + ${rocketmq.version} diff --git a/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/pom.xml b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/pom.xml index ec44c9d7a..ca5c22391 100644 --- a/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/pom.xml +++ b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/pom.xml @@ -50,9 +50,12 @@ org.apache.rocketmq - rocketmq-spring-boot-starter + rocketmq-client + + + org.apache.rocketmq + rocketmq-acl - org.springframework.boot spring-boot-starter-test diff --git a/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/RocketMQBinderUtils.java b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/RocketMQBinderUtils.java deleted file mode 100644 index c7daff0ef..000000000 --- a/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/RocketMQBinderUtils.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright 2013-2018 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.alibaba.cloud.stream.binder.rocketmq; - -import java.util.Arrays; -import java.util.List; - -import com.alibaba.cloud.stream.binder.rocketmq.properties.RocketMQBinderConfigurationProperties; -import org.apache.rocketmq.spring.autoconfigure.RocketMQProperties; - -import org.springframework.util.CollectionUtils; -import org.springframework.util.StringUtils; - -/** - * @author Jim - */ -public final class RocketMQBinderUtils { - - private RocketMQBinderUtils() { - - } - - public static RocketMQBinderConfigurationProperties mergeProperties( - RocketMQBinderConfigurationProperties rocketBinderConfigurationProperties, - RocketMQProperties rocketMQProperties) { - RocketMQBinderConfigurationProperties result = new RocketMQBinderConfigurationProperties(); - if (StringUtils.isEmpty(rocketMQProperties.getNameServer())) { - result.setNameServer(rocketBinderConfigurationProperties.getNameServer()); - } - else { - result.setNameServer( - Arrays.asList(rocketMQProperties.getNameServer().split(";"))); - } - if (rocketMQProperties.getProducer() == null - || StringUtils.isEmpty(rocketMQProperties.getProducer().getAccessKey())) { - result.setAccessKey(rocketBinderConfigurationProperties.getAccessKey()); - } - else { - result.setAccessKey(rocketMQProperties.getProducer().getAccessKey()); - } - if (rocketMQProperties.getProducer() == null - || StringUtils.isEmpty(rocketMQProperties.getProducer().getSecretKey())) { - result.setSecretKey(rocketBinderConfigurationProperties.getSecretKey()); - } - else { - result.setSecretKey(rocketMQProperties.getProducer().getSecretKey()); - } - if (rocketMQProperties.getProducer() == null || StringUtils - .isEmpty(rocketMQProperties.getProducer().getCustomizedTraceTopic())) { - result.setCustomizedTraceTopic( - rocketBinderConfigurationProperties.getCustomizedTraceTopic()); - } - else { - result.setCustomizedTraceTopic( - rocketMQProperties.getProducer().getCustomizedTraceTopic()); - } - if (rocketMQProperties.getProducer() != null - && rocketMQProperties.getProducer().isEnableMsgTrace()) { - result.setEnableMsgTrace(Boolean.TRUE); - } - else { - result.setEnableMsgTrace( - rocketBinderConfigurationProperties.isEnableMsgTrace()); - } - return result; - } - - public static String getNameServerStr(List nameServerList) { - if (CollectionUtils.isEmpty(nameServerList)) { - return null; - } - return String.join(";", nameServerList); - } - -} diff --git a/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/RocketMQMessageChannelBinder.java b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/RocketMQMessageChannelBinder.java index e5a2e24b1..5683bff68 100644 --- a/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/RocketMQMessageChannelBinder.java +++ b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/RocketMQMessageChannelBinder.java @@ -1,11 +1,11 @@ /* - * Copyright 2013-2018 the original author or authors. + * Copyright (C) 2018 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -16,34 +16,18 @@ package com.alibaba.cloud.stream.binder.rocketmq; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; -import java.util.Set; - -import com.alibaba.cloud.stream.binder.rocketmq.consuming.RocketMQListenerBindingContainer; -import com.alibaba.cloud.stream.binder.rocketmq.integration.RocketMQInboundChannelAdapter; -import com.alibaba.cloud.stream.binder.rocketmq.integration.RocketMQMessageHandler; -import com.alibaba.cloud.stream.binder.rocketmq.integration.RocketMQMessageSource; -import com.alibaba.cloud.stream.binder.rocketmq.metrics.InstrumentationManager; +import com.alibaba.cloud.stream.binder.rocketmq.custom.RocketMQBeanContainerCache; +import com.alibaba.cloud.stream.binder.rocketmq.extend.ErrorAcknowledgeHandler; +import com.alibaba.cloud.stream.binder.rocketmq.integration.inbound.RocketMQInboundChannelAdapter; +import com.alibaba.cloud.stream.binder.rocketmq.integration.inbound.pull.DefaultErrorAcknowledgeHandler; +import com.alibaba.cloud.stream.binder.rocketmq.integration.inbound.pull.RocketMQMessageSource; +import com.alibaba.cloud.stream.binder.rocketmq.integration.outbound.RocketMQProducerMessageHandler; import com.alibaba.cloud.stream.binder.rocketmq.properties.RocketMQBinderConfigurationProperties; import com.alibaba.cloud.stream.binder.rocketmq.properties.RocketMQConsumerProperties; import com.alibaba.cloud.stream.binder.rocketmq.properties.RocketMQExtendedBindingProperties; import com.alibaba.cloud.stream.binder.rocketmq.properties.RocketMQProducerProperties; import com.alibaba.cloud.stream.binder.rocketmq.provisioning.RocketMQTopicProvisioner; -import com.alibaba.cloud.stream.binder.rocketmq.provisioning.selector.PartitionMessageQueueSelector; -import com.alibaba.cloud.stream.binder.rocketmq.support.JacksonRocketMQHeaderMapper; -import com.alibaba.cloud.stream.binder.rocketmq.support.RocketMQHeaderMapper; -import com.fasterxml.jackson.databind.ObjectMapper; -import org.apache.rocketmq.acl.common.AclClientRPCHook; -import org.apache.rocketmq.acl.common.SessionCredentials; -import org.apache.rocketmq.client.producer.DefaultMQProducer; -import org.apache.rocketmq.common.UtilAll; -import org.apache.rocketmq.remoting.RPCHook; -import org.apache.rocketmq.spring.autoconfigure.RocketMQProperties; -import org.apache.rocketmq.spring.core.RocketMQTemplate; -import org.apache.rocketmq.spring.support.RocketMQUtil; +import com.alibaba.cloud.stream.binder.rocketmq.utils.RocketMQUtils; import org.springframework.cloud.stream.binder.AbstractMessageChannelBinder; import org.springframework.cloud.stream.binder.BinderSpecificPropertiesProvider; @@ -55,15 +39,19 @@ import org.springframework.cloud.stream.provisioning.ConsumerDestination; import org.springframework.cloud.stream.provisioning.ProducerDestination; import org.springframework.integration.StaticMessageHeaderAccessor; import org.springframework.integration.acks.AcknowledgmentCallback; -import org.springframework.integration.acks.AcknowledgmentCallback.Status; import org.springframework.integration.channel.AbstractMessageChannel; import org.springframework.integration.core.MessageProducer; +import org.springframework.integration.support.DefaultErrorMessageStrategy; +import org.springframework.integration.support.ErrorMessageStrategy; import org.springframework.messaging.MessageChannel; import org.springframework.messaging.MessageHandler; import org.springframework.messaging.MessagingException; import org.springframework.util.StringUtils; /** + * A {@link org.springframework.cloud.stream.binder.Binder} that uses RocketMQ as the + * underlying middleware. + * * @author Jim */ public class RocketMQMessageChannelBinder extends @@ -71,120 +59,44 @@ public class RocketMQMessageChannelBinder extends implements ExtendedPropertiesBinder { - private RocketMQExtendedBindingProperties extendedBindingProperties = new RocketMQExtendedBindingProperties(); - - private final RocketMQBinderConfigurationProperties rocketBinderConfigurationProperties; - - private final RocketMQProperties rocketMQProperties; - - private final InstrumentationManager instrumentationManager; - - private Map topicInUse = new HashMap<>(); + private final RocketMQExtendedBindingProperties extendedBindingProperties; + private final RocketMQBinderConfigurationProperties binderConfigurationProperties; - public RocketMQMessageChannelBinder(RocketMQTopicProvisioner provisioningProvider, + public RocketMQMessageChannelBinder( + RocketMQBinderConfigurationProperties binderConfigurationProperties, RocketMQExtendedBindingProperties extendedBindingProperties, - RocketMQBinderConfigurationProperties rocketBinderConfigurationProperties, - RocketMQProperties rocketMQProperties, - InstrumentationManager instrumentationManager) { - super(null, provisioningProvider); + RocketMQTopicProvisioner provisioningProvider) { + super(new String[0], provisioningProvider); this.extendedBindingProperties = extendedBindingProperties; - this.rocketBinderConfigurationProperties = rocketBinderConfigurationProperties; - this.rocketMQProperties = rocketMQProperties; - this.instrumentationManager = instrumentationManager; + this.binderConfigurationProperties = binderConfigurationProperties; } @Override protected MessageHandler createProducerMessageHandler(ProducerDestination destination, - ExtendedProducerProperties producerProperties, + ExtendedProducerProperties extendedProducerProperties, MessageChannel channel, MessageChannel errorChannel) throws Exception { - if (producerProperties.getExtension().getEnabled()) { - - // if producerGroup is empty, using destination - String extendedProducerGroup = producerProperties.getExtension().getGroup(); - String producerGroup = StringUtils.isEmpty(extendedProducerGroup) - ? destination.getName() : extendedProducerGroup; - - RocketMQBinderConfigurationProperties mergedProperties = RocketMQBinderUtils - .mergeProperties(rocketBinderConfigurationProperties, - rocketMQProperties); - - RocketMQTemplate rocketMQTemplate; - if (producerProperties.getExtension().getTransactional()) { - Map rocketMQTemplates = getBeanFactory() - .getBeansOfType(RocketMQTemplate.class); - if (rocketMQTemplates.size() == 0) { - throw new IllegalStateException( - "there is no RocketMQTemplate in Spring BeanFactory"); - } - else if (rocketMQTemplates.size() > 1) { - throw new IllegalStateException( - "there is more than 1 RocketMQTemplates in Spring BeanFactory"); - } - rocketMQTemplate = rocketMQTemplates.values().iterator().next(); - } - else { - rocketMQTemplate = new RocketMQTemplate(); - rocketMQTemplate.setObjectMapper(this.getApplicationContext() - .getBeansOfType(ObjectMapper.class).values().iterator().next()); - DefaultMQProducer producer; - String ak = mergedProperties.getAccessKey(); - String sk = mergedProperties.getSecretKey(); - if (!StringUtils.isEmpty(ak) && !StringUtils.isEmpty(sk)) { - RPCHook rpcHook = new AclClientRPCHook( - new SessionCredentials(ak, sk)); - producer = new DefaultMQProducer(producerGroup, rpcHook, - mergedProperties.isEnableMsgTrace(), - mergedProperties.getCustomizedTraceTopic()); - producer.setVipChannelEnabled(false); - producer.setInstanceName(RocketMQUtil.getInstanceName(rpcHook, - destination.getName() + "|" + UtilAll.getPid())); - } - else { - producer = new DefaultMQProducer(producerGroup); - producer.setVipChannelEnabled( - producerProperties.getExtension().getVipChannelEnabled()); - } - producer.setNamesrvAddr(RocketMQBinderUtils - .getNameServerStr(mergedProperties.getNameServer())); - producer.setSendMsgTimeout( - producerProperties.getExtension().getSendMessageTimeout()); - producer.setRetryTimesWhenSendFailed( - producerProperties.getExtension().getRetryTimesWhenSendFailed()); - producer.setRetryTimesWhenSendAsyncFailed(producerProperties - .getExtension().getRetryTimesWhenSendAsyncFailed()); - producer.setCompressMsgBodyOverHowmuch(producerProperties.getExtension() - .getCompressMessageBodyThreshold()); - producer.setRetryAnotherBrokerWhenNotStoreOK( - producerProperties.getExtension().isRetryNextServer()); - producer.setMaxMessageSize( - producerProperties.getExtension().getMaxMessageSize()); - rocketMQTemplate.setProducer(producer); - if (producerProperties.isPartitioned()) { - rocketMQTemplate - .setMessageQueueSelector(new PartitionMessageQueueSelector()); - } - } - - 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 { + if (!extendedProducerProperties.getExtension().getEnabled()) { throw new RuntimeException("Binding for channel " + destination.getName() + " has been disabled, message can't be delivered"); } + RocketMQProducerProperties mqProducerProperties = RocketMQUtils + .mergeRocketMQProperties(binderConfigurationProperties, + extendedProducerProperties.getExtension()); + RocketMQProducerMessageHandler messageHandler = new RocketMQProducerMessageHandler( + destination, extendedProducerProperties, mqProducerProperties); + messageHandler.setApplicationContext(this.getApplicationContext()); + if (errorChannel != null) { + messageHandler.setSendFailureChannel(errorChannel); + } + MessageConverterConfigurer.PartitioningInterceptor partitioningInterceptor = ((AbstractMessageChannel) channel) + .getInterceptors().stream() + .filter(channelInterceptor -> channelInterceptor instanceof MessageConverterConfigurer.PartitioningInterceptor) + .map(channelInterceptor -> ((MessageConverterConfigurer.PartitioningInterceptor) channelInterceptor)) + .findFirst().orElse(null); + messageHandler.setPartitioningInterceptor(partitioningInterceptor); + messageHandler.setBeanFactory(this.getApplicationContext().getBeanFactory()); + messageHandler.setErrorMessageStrategy(this.getErrorMessageStrategy()); + return messageHandler; } @Override @@ -198,56 +110,43 @@ public class RocketMQMessageChannelBinder extends @Override protected MessageProducer createConsumerEndpoint(ConsumerDestination destination, String group, - ExtendedConsumerProperties consumerProperties) + ExtendedConsumerProperties extendedConsumerProperties) throws Exception { - if (group == null || "".equals(group)) { + // todo support anymous consumer + if (StringUtils.isEmpty(group)) { throw new RuntimeException( "'group must be configured for channel " + destination.getName()); } + RocketMQUtils.mergeRocketMQProperties(binderConfigurationProperties, + extendedConsumerProperties.getExtension()); + extendedConsumerProperties.getExtension().setGroup(group); - RocketMQListenerBindingContainer listenerContainer = new RocketMQListenerBindingContainer( - consumerProperties, rocketBinderConfigurationProperties, this); - listenerContainer.setConsumerGroup(group); - listenerContainer.setTopic(destination.getName()); - listenerContainer.setConsumeThreadMax(consumerProperties.getConcurrency()); - listenerContainer.setSuspendCurrentQueueTimeMillis( - consumerProperties.getExtension().getSuspendCurrentQueueTimeMillis()); - listenerContainer.setDelayLevelWhenNextConsume( - consumerProperties.getExtension().getDelayLevelWhenNextConsume()); - listenerContainer - .setNameServer(rocketBinderConfigurationProperties.getNameServer()); - listenerContainer.setHeaderMapper(createHeaderMapper(consumerProperties)); - - RocketMQInboundChannelAdapter rocketInboundChannelAdapter = new RocketMQInboundChannelAdapter( - listenerContainer, consumerProperties, instrumentationManager); - - topicInUse.put(destination.getName(), group); - + RocketMQInboundChannelAdapter inboundChannelAdapter = new RocketMQInboundChannelAdapter( + destination.getName(), extendedConsumerProperties); ErrorInfrastructure errorInfrastructure = registerErrorInfrastructure(destination, - group, consumerProperties); - if (consumerProperties.getMaxAttempts() > 1) { - rocketInboundChannelAdapter - .setRetryTemplate(buildRetryTemplate(consumerProperties)); - rocketInboundChannelAdapter - .setRecoveryCallback(errorInfrastructure.getRecoverer()); + group, extendedConsumerProperties); + if (extendedConsumerProperties.getMaxAttempts() > 1) { + inboundChannelAdapter + .setRetryTemplate(buildRetryTemplate(extendedConsumerProperties)); + inboundChannelAdapter.setRecoveryCallback(errorInfrastructure.getRecoverer()); } else { - rocketInboundChannelAdapter - .setErrorChannel(errorInfrastructure.getErrorChannel()); + inboundChannelAdapter.setErrorChannel(errorInfrastructure.getErrorChannel()); } - - return rocketInboundChannelAdapter; + return inboundChannelAdapter; } @Override protected PolledConsumerResources createPolledConsumerResources(String name, String group, ConsumerDestination destination, - ExtendedConsumerProperties consumerProperties) { - RocketMQMessageSource rocketMQMessageSource = new RocketMQMessageSource( - rocketBinderConfigurationProperties, consumerProperties, name, group); - return new PolledConsumerResources(rocketMQMessageSource, - registerErrorInfrastructure(destination, group, consumerProperties, - true)); + ExtendedConsumerProperties extendedConsumerProperties) { + RocketMQUtils.mergeRocketMQProperties(binderConfigurationProperties, + extendedConsumerProperties.getExtension()); + extendedConsumerProperties.getExtension().setGroup(group); + RocketMQMessageSource messageSource = new RocketMQMessageSource(name, + extendedConsumerProperties); + return new PolledConsumerResources(messageSource, registerErrorInfrastructure( + destination, group, extendedConsumerProperties, true)); } @Override @@ -261,67 +160,47 @@ public class RocketMQMessageChannelBinder extends ((MessagingException) message.getPayload()) .getFailedMessage()); if (ack != null) { - if (properties.getExtension().shouldRequeue()) { - ack.acknowledge(Status.REQUEUE); - } - else { - ack.acknowledge(Status.REJECT); - } + ErrorAcknowledgeHandler handler = RocketMQBeanContainerCache.getBean( + properties.getExtension().getPull().getErrAcknowledge(), + ErrorAcknowledgeHandler.class, + new DefaultErrorAcknowledgeHandler()); + ack.acknowledge( + handler.handler(((MessagingException) message.getPayload()) + .getFailedMessage())); } } }; } + /** + * Binders can return an {@link ErrorMessageStrategy} for building error messages; + * binder implementations typically might add extra headers to the error message. + * + * @return the implementation - may be null. + */ @Override - public RocketMQConsumerProperties getExtendedConsumerProperties(String channelName) { - return extendedBindingProperties.getExtendedConsumerProperties(channelName); + protected ErrorMessageStrategy getErrorMessageStrategy() { + // It can be extended to custom if necessary. + return new DefaultErrorMessageStrategy(); } @Override - public RocketMQProducerProperties getExtendedProducerProperties(String channelName) { - return extendedBindingProperties.getExtendedProducerProperties(channelName); + public RocketMQConsumerProperties getExtendedConsumerProperties(String channelName) { + return this.extendedBindingProperties.getExtendedConsumerProperties(channelName); } - public Map getTopicInUse() { - return topicInUse; + @Override + public RocketMQProducerProperties getExtendedProducerProperties(String channelName) { + return this.extendedBindingProperties.getExtendedProducerProperties(channelName); } @Override public String getDefaultsPrefix() { - return extendedBindingProperties.getDefaultsPrefix(); + return this.extendedBindingProperties.getDefaultsPrefix(); } @Override public Class getExtendedPropertiesEntryClass() { - return extendedBindingProperties.getExtendedPropertiesEntryClass(); + return this.extendedBindingProperties.getExtendedPropertiesEntryClass(); } - - public void setExtendedBindingProperties( - RocketMQExtendedBindingProperties extendedBindingProperties) { - this.extendedBindingProperties = extendedBindingProperties; - } - - private RocketMQHeaderMapper createHeaderMapper( - final ExtendedConsumerProperties extendedConsumerProperties) { - Set trustedPackages = extendedConsumerProperties.getExtension() - .getTrustedPackages(); - return createHeaderMapper(trustedPackages); - } - - private RocketMQHeaderMapper createHeaderMapper( - final ExtendedProducerProperties producerProperties) { - return createHeaderMapper(Collections.emptyList()); - } - - private RocketMQHeaderMapper createHeaderMapper(Collection trustedPackages) { - ObjectMapper objectMapper = this.getApplicationContext() - .getBeansOfType(ObjectMapper.class).values().iterator().next(); - JacksonRocketMQHeaderMapper headerMapper = new JacksonRocketMQHeaderMapper( - objectMapper); - if (!StringUtils.isEmpty(trustedPackages)) { - headerMapper.addTrustedPackages(trustedPackages); - } - return headerMapper; - } - } diff --git a/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/actuator/RocketMQBinderHealthIndicator.java b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/actuator/RocketMQBinderHealthIndicator.java index 1c49359ea..6e704250a 100644 --- a/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/actuator/RocketMQBinderHealthIndicator.java +++ b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/actuator/RocketMQBinderHealthIndicator.java @@ -19,7 +19,6 @@ package com.alibaba.cloud.stream.binder.rocketmq.actuator; import com.alibaba.cloud.stream.binder.rocketmq.metrics.Instrumentation; import com.alibaba.cloud.stream.binder.rocketmq.metrics.InstrumentationManager; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.actuate.health.AbstractHealthIndicator; import org.springframework.boot.actuate.health.Health; @@ -29,23 +28,20 @@ import org.springframework.boot.actuate.health.Health; */ public class RocketMQBinderHealthIndicator extends AbstractHealthIndicator { - @Autowired - private InstrumentationManager instrumentationManager; - @Override protected void doHealthCheck(Health.Builder builder) throws Exception { - if (instrumentationManager.getHealthInstrumentations().stream() + if (InstrumentationManager.getHealthInstrumentations().stream() .allMatch(Instrumentation::isUp)) { builder.up(); return; } - if (instrumentationManager.getHealthInstrumentations().stream() + if (InstrumentationManager.getHealthInstrumentations().stream() .allMatch(Instrumentation::isOutOfService)) { builder.outOfService(); return; } builder.down(); - instrumentationManager.getHealthInstrumentations().stream() + InstrumentationManager.getHealthInstrumentations().stream() .filter(instrumentation -> !instrumentation.isStarted()) .forEach(instrumentation1 -> builder .withException(instrumentation1.getStartException())); diff --git a/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/consuming/RocketMQListenerBindingContainer.java b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/consuming/RocketMQListenerBindingContainer.java index fb167c697..7bd875f33 100644 --- a/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/consuming/RocketMQListenerBindingContainer.java +++ b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/consuming/RocketMQListenerBindingContainer.java @@ -1,465 +1,470 @@ -/* - * Copyright 2013-2018 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.alibaba.cloud.stream.binder.rocketmq.consuming; - -import java.util.List; -import java.util.Objects; - -import com.alibaba.cloud.stream.binder.rocketmq.RocketMQBinderUtils; -import com.alibaba.cloud.stream.binder.rocketmq.RocketMQMessageChannelBinder; -import com.alibaba.cloud.stream.binder.rocketmq.properties.RocketMQBinderConfigurationProperties; -import com.alibaba.cloud.stream.binder.rocketmq.properties.RocketMQConsumerProperties; -import com.alibaba.cloud.stream.binder.rocketmq.support.RocketMQHeaderMapper; -import org.apache.rocketmq.acl.common.AclClientRPCHook; -import org.apache.rocketmq.acl.common.SessionCredentials; -import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer; -import org.apache.rocketmq.client.consumer.MessageSelector; -import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyContext; -import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyStatus; -import org.apache.rocketmq.client.consumer.listener.ConsumeOrderlyContext; -import org.apache.rocketmq.client.consumer.listener.ConsumeOrderlyStatus; -import org.apache.rocketmq.client.consumer.listener.MessageListenerConcurrently; -import org.apache.rocketmq.client.consumer.listener.MessageListenerOrderly; -import org.apache.rocketmq.client.consumer.rebalance.AllocateMessageQueueAveragely; -import org.apache.rocketmq.client.exception.MQClientException; -import org.apache.rocketmq.common.UtilAll; -import org.apache.rocketmq.common.message.MessageExt; -import org.apache.rocketmq.remoting.RPCHook; -import org.apache.rocketmq.spring.annotation.ConsumeMode; -import org.apache.rocketmq.spring.annotation.MessageModel; -import org.apache.rocketmq.spring.annotation.SelectorType; -import org.apache.rocketmq.spring.core.RocketMQListener; -import org.apache.rocketmq.spring.core.RocketMQPushConsumerLifecycleListener; -import org.apache.rocketmq.spring.support.RocketMQListenerContainer; -import org.apache.rocketmq.spring.support.RocketMQUtil; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import org.springframework.beans.factory.InitializingBean; -import org.springframework.cloud.stream.binder.ExtendedConsumerProperties; -import org.springframework.context.SmartLifecycle; -import org.springframework.integration.support.MessageBuilder; -import org.springframework.messaging.Message; -import org.springframework.util.Assert; -import org.springframework.util.StringUtils; - -import static com.alibaba.cloud.stream.binder.rocketmq.RocketMQBinderConstants.ROCKETMQ_RECONSUME_TIMES; - -/** - * A class that Listen on rocketmq message. - *

- * this class will delegate {@link RocketMQListener} to handle message - * - * @author Jim - * @author Xiejiashuai - * @see RocketMQListener - */ -public class RocketMQListenerBindingContainer - implements InitializingBean, RocketMQListenerContainer, SmartLifecycle { - - private final static Logger log = LoggerFactory - .getLogger(RocketMQListenerBindingContainer.class); - - private long suspendCurrentQueueTimeMillis = 1000; - - /** - * Message consume retry strategy
- * -1,no retry,put into DLQ directly
- * 0,broker control retry frequency
- * >0,client control retry frequency. - */ - private int delayLevelWhenNextConsume = 0; - - private List nameServer; - - private String consumerGroup; - - private String topic; - - private int consumeThreadMax = 64; - - private String charset = "UTF-8"; - - private RocketMQListener rocketMQListener; - - private RocketMQHeaderMapper headerMapper; - - private DefaultMQPushConsumer consumer; - - private boolean running; - - private final ExtendedConsumerProperties rocketMQConsumerProperties; - - private final RocketMQMessageChannelBinder rocketMQMessageChannelBinder; - - private final RocketMQBinderConfigurationProperties rocketBinderConfigurationProperties; - - // The following properties came from RocketMQConsumerProperties. - private ConsumeMode consumeMode; - - private SelectorType selectorType; - - private String selectorExpression; - - private MessageModel messageModel; - - public RocketMQListenerBindingContainer( - ExtendedConsumerProperties rocketMQConsumerProperties, - RocketMQBinderConfigurationProperties rocketBinderConfigurationProperties, - RocketMQMessageChannelBinder rocketMQMessageChannelBinder) { - this.rocketMQConsumerProperties = rocketMQConsumerProperties; - this.rocketBinderConfigurationProperties = rocketBinderConfigurationProperties; - this.rocketMQMessageChannelBinder = rocketMQMessageChannelBinder; - this.consumeMode = rocketMQConsumerProperties.getExtension().getOrderly() - ? ConsumeMode.ORDERLY : ConsumeMode.CONCURRENTLY; - if (StringUtils.isEmpty(rocketMQConsumerProperties.getExtension().getSql())) { - this.selectorType = SelectorType.TAG; - this.selectorExpression = rocketMQConsumerProperties.getExtension().getTags(); - } - else { - this.selectorType = SelectorType.SQL92; - this.selectorExpression = rocketMQConsumerProperties.getExtension().getSql(); - } - this.messageModel = rocketMQConsumerProperties.getExtension().getBroadcasting() - ? MessageModel.BROADCASTING : MessageModel.CLUSTERING; - } - - @Override - public void setupMessageListener(RocketMQListener rocketMQListener) { - this.rocketMQListener = rocketMQListener; - } - - @Override - public void destroy() throws Exception { - this.setRunning(false); - if (Objects.nonNull(consumer)) { - consumer.shutdown(); - } - log.info("container destroyed, {}", this.toString()); - } - - @Override - public void afterPropertiesSet() throws Exception { - initRocketMQPushConsumer(); - } - - @Override - public boolean isAutoStartup() { - return true; - } - - @Override - public void stop(Runnable callback) { - stop(); - callback.run(); - } - - @Override - public void start() { - if (this.isRunning()) { - throw new IllegalStateException( - "container already running. " + this.toString()); - } - - try { - consumer.start(); - } - catch (MQClientException e) { - throw new IllegalStateException("Failed to start RocketMQ push consumer", e); - } - this.setRunning(true); - - log.info("running container: {}", this.toString()); - } - - @Override - public void stop() { - if (this.isRunning()) { - if (Objects.nonNull(consumer)) { - consumer.shutdown(); - } - setRunning(false); - } - } - - @Override - public boolean isRunning() { - return running; - } - - private void setRunning(boolean running) { - this.running = running; - } - - @Override - public int getPhase() { - return Integer.MAX_VALUE; - } - - private void initRocketMQPushConsumer() throws MQClientException { - Assert.notNull(rocketMQListener, "Property 'rocketMQListener' is required"); - Assert.notNull(consumerGroup, "Property 'consumerGroup' is required"); - Assert.notNull(nameServer, "Property 'nameServer' is required"); - Assert.notNull(topic, "Property 'topic' is required"); - - String ak = rocketBinderConfigurationProperties.getAccessKey(); - String sk = rocketBinderConfigurationProperties.getSecretKey(); - if (!StringUtils.isEmpty(ak) && !StringUtils.isEmpty(sk)) { - RPCHook rpcHook = new AclClientRPCHook(new SessionCredentials(ak, sk)); - consumer = new DefaultMQPushConsumer(consumerGroup, rpcHook, - new AllocateMessageQueueAveragely(), - rocketBinderConfigurationProperties.isEnableMsgTrace(), - rocketBinderConfigurationProperties.getCustomizedTraceTopic()); - consumer.setInstanceName(RocketMQUtil.getInstanceName(rpcHook, - topic + "|" + UtilAll.getPid())); - consumer.setVipChannelEnabled(false); - } - else { - consumer = new DefaultMQPushConsumer(consumerGroup, - rocketBinderConfigurationProperties.isEnableMsgTrace(), - rocketBinderConfigurationProperties.getCustomizedTraceTopic()); - } - - consumer.setNamesrvAddr(RocketMQBinderUtils.getNameServerStr(nameServer)); - consumer.setConsumeThreadMax(rocketMQConsumerProperties.getConcurrency()); - consumer.setConsumeThreadMin(rocketMQConsumerProperties.getConcurrency()); - - switch (messageModel) { - case BROADCASTING: - consumer.setMessageModel( - org.apache.rocketmq.common.protocol.heartbeat.MessageModel.BROADCASTING); - break; - case CLUSTERING: - consumer.setMessageModel( - org.apache.rocketmq.common.protocol.heartbeat.MessageModel.CLUSTERING); - break; - default: - throw new IllegalArgumentException("Property 'messageModel' was wrong."); - } - - switch (selectorType) { - case TAG: - consumer.subscribe(topic, selectorExpression); - break; - case SQL92: - consumer.subscribe(topic, MessageSelector.bySql(selectorExpression)); - break; - default: - throw new IllegalArgumentException("Property 'selectorType' was wrong."); - } - - switch (consumeMode) { - case ORDERLY: - consumer.setMessageListener(new DefaultMessageListenerOrderly()); - break; - case CONCURRENTLY: - consumer.setMessageListener(new DefaultMessageListenerConcurrently()); - break; - default: - throw new IllegalArgumentException("Property 'consumeMode' was wrong."); - } - - if (rocketMQListener instanceof RocketMQPushConsumerLifecycleListener) { - ((RocketMQPushConsumerLifecycleListener) rocketMQListener) - .prepareStart(consumer); - } - - } - - @Override - public String toString() { - return "RocketMQListenerBindingContainer{" + "consumerGroup='" + consumerGroup - + '\'' + ", nameServer='" + nameServer + '\'' + ", topic='" + topic + '\'' - + ", consumeMode=" + consumeMode + ", selectorType=" + selectorType - + ", selectorExpression='" + selectorExpression + '\'' + ", messageModel=" - + messageModel + '}'; - } - - public long getSuspendCurrentQueueTimeMillis() { - return suspendCurrentQueueTimeMillis; - } - - public void setSuspendCurrentQueueTimeMillis(long suspendCurrentQueueTimeMillis) { - this.suspendCurrentQueueTimeMillis = suspendCurrentQueueTimeMillis; - } - - public int getDelayLevelWhenNextConsume() { - return delayLevelWhenNextConsume; - } - - public void setDelayLevelWhenNextConsume(int delayLevelWhenNextConsume) { - this.delayLevelWhenNextConsume = delayLevelWhenNextConsume; - } - - public List getNameServer() { - return nameServer; - } - - public void setNameServer(List nameServer) { - this.nameServer = nameServer; - } - - public String getConsumerGroup() { - return consumerGroup; - } - - public void setConsumerGroup(String consumerGroup) { - this.consumerGroup = consumerGroup; - } - - public String getTopic() { - return topic; - } - - public void setTopic(String topic) { - this.topic = topic; - } - - public int getConsumeThreadMax() { - return consumeThreadMax; - } - - public void setConsumeThreadMax(int consumeThreadMax) { - this.consumeThreadMax = consumeThreadMax; - } - - public String getCharset() { - return charset; - } - - public void setCharset(String charset) { - this.charset = charset; - } - - public RocketMQListener getRocketMQListener() { - return rocketMQListener; - } - - public void setRocketMQListener(RocketMQListener rocketMQListener) { - this.rocketMQListener = rocketMQListener; - } - - public DefaultMQPushConsumer getConsumer() { - return consumer; - } - - public void setConsumer(DefaultMQPushConsumer consumer) { - this.consumer = consumer; - } - - public ExtendedConsumerProperties getRocketMQConsumerProperties() { - return rocketMQConsumerProperties; - } - - public ConsumeMode getConsumeMode() { - return consumeMode; - } - - public SelectorType getSelectorType() { - return selectorType; - } - - public String getSelectorExpression() { - return selectorExpression; - } - - public MessageModel getMessageModel() { - return messageModel; - } - - public RocketMQHeaderMapper getHeaderMapper() { - return headerMapper; - } - - public void setHeaderMapper(RocketMQHeaderMapper headerMapper) { - this.headerMapper = headerMapper; - } - - /** - * Convert rocketmq {@link MessageExt} to Spring {@link Message}. - * @param messageExt the rocketmq message - * @return the converted Spring {@link Message} - */ - @SuppressWarnings("unchecked") - private Message convertToSpringMessage(MessageExt messageExt) { - - // add reconsume-times header to messageExt - int reconsumeTimes = messageExt.getReconsumeTimes(); - messageExt.putUserProperty(ROCKETMQ_RECONSUME_TIMES, - String.valueOf(reconsumeTimes)); - Message message = RocketMQUtil.convertToSpringMessage(messageExt); - return MessageBuilder.fromMessage(message) - .copyHeaders(headerMapper.toHeaders(messageExt.getProperties())).build(); - } - - public class DefaultMessageListenerConcurrently - implements MessageListenerConcurrently { - - @SuppressWarnings({ "unchecked", "Duplicates" }) - @Override - public ConsumeConcurrentlyStatus consumeMessage(List msgs, - ConsumeConcurrentlyContext context) { - for (MessageExt messageExt : msgs) { - log.debug("received msg: {}", messageExt); - try { - long now = System.currentTimeMillis(); - rocketMQListener.onMessage(convertToSpringMessage(messageExt)); - long costTime = System.currentTimeMillis() - now; - log.debug("consume {} message key:[{}] cost: {} ms", - messageExt.getMsgId(), messageExt.getKeys(), costTime); - } - catch (Exception e) { - log.warn("consume message failed. messageExt:{}", messageExt, e); - context.setDelayLevelWhenNextConsume(delayLevelWhenNextConsume); - return ConsumeConcurrentlyStatus.RECONSUME_LATER; - } - } - - return ConsumeConcurrentlyStatus.CONSUME_SUCCESS; - } - - } - - public class DefaultMessageListenerOrderly implements MessageListenerOrderly { - - @SuppressWarnings({ "unchecked", "Duplicates" }) - @Override - public ConsumeOrderlyStatus consumeMessage(List msgs, - ConsumeOrderlyContext context) { - for (MessageExt messageExt : msgs) { - log.debug("received msg: {}", messageExt); - try { - long now = System.currentTimeMillis(); - rocketMQListener.onMessage(convertToSpringMessage(messageExt)); - long costTime = System.currentTimeMillis() - now; - log.info("consume {} message key:[{}] cost: {} ms", - messageExt.getMsgId(), messageExt.getKeys(), costTime); - } - catch (Exception e) { - log.warn("consume message failed. messageExt:{}", messageExt, e); - context.setSuspendCurrentQueueTimeMillis( - suspendCurrentQueueTimeMillis); - return ConsumeOrderlyStatus.SUSPEND_CURRENT_QUEUE_A_MOMENT; - } - } - - return ConsumeOrderlyStatus.SUCCESS; - } - - } - -} +/// * +// * Copyright 2013-2018 the original author or authors. +// * +// * Licensed under the Apache License, Version 2.0 (the "License"); +// * you may not use this file except in compliance with the License. +// * You may obtain a copy of the License at +// * +// * https://www.apache.org/licenses/LICENSE-2.0 +// * +// * Unless required by applicable law or agreed to in writing, software +// * distributed under the License is distributed on an "AS IS" BASIS, +// * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// * See the License for the specific language governing permissions and +// * limitations under the License. +// */ +// +// package com.alibaba.cloud.stream.binder.rocketmq.consuming; +// +// import java.util.List; +// import java.util.Objects; +// +// import com.alibaba.cloud.stream.binder.rocketmq.RocketMQBinderUtils; +// import com.alibaba.cloud.stream.binder.rocketmq.RocketMQMessageChannelBinder; +// import +/// com.alibaba.cloud.stream.binder.rocketmq.properties.RocketMQBinderConfigurationProperties; +// import com.alibaba.cloud.stream.binder.rocketmq.properties.RocketMQConsumerProperties; +// import com.alibaba.cloud.stream.binder.rocketmq.support.RocketMQHeaderMapper; +// import org.apache.rocketmq.acl.common.AclClientRPCHook; +// import org.apache.rocketmq.acl.common.SessionCredentials; +// import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer; +// import org.apache.rocketmq.client.consumer.MessageSelector; +// import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyContext; +// import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyStatus; +// import org.apache.rocketmq.client.consumer.listener.ConsumeOrderlyContext; +// import org.apache.rocketmq.client.consumer.listener.ConsumeOrderlyStatus; +// import org.apache.rocketmq.client.consumer.listener.MessageListenerConcurrently; +// import org.apache.rocketmq.client.consumer.listener.MessageListenerOrderly; +// import org.apache.rocketmq.client.consumer.rebalance.AllocateMessageQueueAveragely; +// import org.apache.rocketmq.client.exception.MQClientException; +// import org.apache.rocketmq.common.UtilAll; +// import org.apache.rocketmq.common.message.MessageExt; +// import org.apache.rocketmq.remoting.RPCHook; +// import org.apache.rocketmq.spring.annotation.ConsumeMode; +// import org.apache.rocketmq.spring.annotation.MessageModel; +// import org.apache.rocketmq.spring.annotation.SelectorType; +// import org.apache.rocketmq.spring.core.RocketMQListener; +// import org.apache.rocketmq.spring.core.RocketMQPushConsumerLifecycleListener; +// import org.apache.rocketmq.spring.support.RocketMQListenerContainer; +// import org.apache.rocketmq.spring.support.RocketMQUtil; +// import org.slf4j.Logger; +// import org.slf4j.LoggerFactory; +// +// import org.springframework.beans.factory.InitializingBean; +// import org.springframework.cloud.stream.binder.ExtendedConsumerProperties; +// import org.springframework.context.SmartLifecycle; +// import org.springframework.integration.support.MessageBuilder; +// import org.springframework.messaging.Message; +// import org.springframework.util.Assert; +// import org.springframework.util.StringUtils; +// +// import static +/// com.alibaba.cloud.stream.binder.rocketmq.RocketMQBinderConstants.ROCKETMQ_RECONSUME_TIMES; +// +/// ** +// * A class that Listen on rocketmq message. +// *

+// * this class will delegate {@link RocketMQListener} to handle message +// * +// * @author Jim +// * @author Xiejiashuai +// * @see RocketMQListener +// */ +// public class RocketMQListenerBindingContainer +// implements InitializingBean, RocketMQListenerContainer, SmartLifecycle { +// +// private final static Logger log = LoggerFactory +// .getLogger(RocketMQListenerBindingContainer.class); +// +// private long suspendCurrentQueueTimeMillis = 1000; +// +// /** +// * Message consume retry strategy
+// * -1,no retry,put into DLQ directly
+// * 0,broker control retry frequency
+// * >0,client control retry frequency. +// */ +// private int delayLevelWhenNextConsume = 0; +// +// private List nameServer; +// +// private String consumerGroup; +// +// private String topic; +// +// private int consumeThreadMax = 64; +// +// private String charset = "UTF-8"; +// +// private RocketMQListener rocketMQListener; +// +// private RocketMQHeaderMapper headerMapper; +// +// private DefaultMQPushConsumer consumer; +// +// private boolean running; +// +// private final ExtendedConsumerProperties +/// rocketMQConsumerProperties; +// +// private final RocketMQMessageChannelBinder rocketMQMessageChannelBinder; +// +// private final RocketMQBinderConfigurationProperties +/// rocketBinderConfigurationProperties; +// +// // The following properties came from RocketMQConsumerProperties. +// private ConsumeMode consumeMode; +// +// private SelectorType selectorType; +// +// private String selectorExpression; +// +// private MessageModel messageModel; +// +// public RocketMQListenerBindingContainer( +// ExtendedConsumerProperties rocketMQConsumerProperties, +// RocketMQBinderConfigurationProperties rocketBinderConfigurationProperties, +// RocketMQMessageChannelBinder rocketMQMessageChannelBinder) { +// this.rocketMQConsumerProperties = rocketMQConsumerProperties; +// this.rocketBinderConfigurationProperties = rocketBinderConfigurationProperties; +// this.rocketMQMessageChannelBinder = rocketMQMessageChannelBinder; +// this.consumeMode = rocketMQConsumerProperties.getExtension().getOrderly() +// ? ConsumeMode.ORDERLY : ConsumeMode.CONCURRENTLY; +// if (StringUtils.isEmpty(rocketMQConsumerProperties.getExtension().getSql())) { +// this.selectorType = SelectorType.TAG; +// this.selectorExpression = rocketMQConsumerProperties.getExtension().getTags(); +// } +// else { +// this.selectorType = SelectorType.SQL92; +// this.selectorExpression = rocketMQConsumerProperties.getExtension().getSql(); +// } +// this.messageModel = rocketMQConsumerProperties.getExtension().getBroadcasting() +// ? MessageModel.BROADCASTING : MessageModel.CLUSTERING; +// } +// +// @Override +// public void setupMessageListener(RocketMQListener rocketMQListener) { +// this.rocketMQListener = rocketMQListener; +// } +// +// @Override +// public void destroy() throws Exception { +// this.setRunning(false); +// if (Objects.nonNull(consumer)) { +// consumer.shutdown(); +// } +// log.info("container destroyed, {}", this.toString()); +// } +// +// @Override +// public void afterPropertiesSet() throws Exception { +// initRocketMQPushConsumer(); +// } +// +// @Override +// public boolean isAutoStartup() { +// return true; +// } +// +// @Override +// public void stop(Runnable callback) { +// stop(); +// callback.run(); +// } +// +// @Override +// public void start() { +// if (this.isRunning()) { +// throw new IllegalStateException( +// "container already running. " + this.toString()); +// } +// +// try { +// consumer.start(); +// } +// catch (MQClientException e) { +// throw new IllegalStateException("Failed to start RocketMQ push consumer", e); +// } +// this.setRunning(true); +// +// log.info("running container: {}", this.toString()); +// } +// +// @Override +// public void stop() { +// if (this.isRunning()) { +// if (Objects.nonNull(consumer)) { +// consumer.shutdown(); +// } +// setRunning(false); +// } +// } +// +// @Override +// public boolean isRunning() { +// return running; +// } +// +// private void setRunning(boolean running) { +// this.running = running; +// } +// +// @Override +// public int getPhase() { +// return Integer.MAX_VALUE; +// } +// +// private void initRocketMQPushConsumer() throws MQClientException { +// Assert.notNull(rocketMQListener, "Property 'rocketMQListener' is required"); +// Assert.notNull(consumerGroup, "Property 'consumerGroup' is required"); +// Assert.notNull(nameServer, "Property 'nameServer' is required"); +// Assert.notNull(topic, "Property 'topic' is required"); +// +// String ak = rocketBinderConfigurationProperties.getAccessKey(); +// String sk = rocketBinderConfigurationProperties.getSecretKey(); +// if (!StringUtils.isEmpty(ak) && !StringUtils.isEmpty(sk)) { +// RPCHook rpcHook = new AclClientRPCHook(new SessionCredentials(ak, sk)); +// consumer = new DefaultMQPushConsumer(consumerGroup, rpcHook, +// new AllocateMessageQueueAveragely(), +// rocketBinderConfigurationProperties.isEnableMsgTrace(), +// rocketBinderConfigurationProperties.getCustomizedTraceTopic()); +// consumer.setInstanceName(RocketMQUtil.getInstanceName(rpcHook, +// topic + "|" + UtilAll.getPid())); +// consumer.setVipChannelEnabled(false); +// } +// else { +// consumer = new DefaultMQPushConsumer(consumerGroup, +// rocketBinderConfigurationProperties.isEnableMsgTrace(), +// rocketBinderConfigurationProperties.getCustomizedTraceTopic()); +// } +// +// consumer.setNamesrvAddr(RocketMQBinderUtils.getNameServerStr(nameServer)); +// consumer.setConsumeThreadMax(rocketMQConsumerProperties.getConcurrency()); +// consumer.setConsumeThreadMin(rocketMQConsumerProperties.getConcurrency()); +// +// switch (messageModel) { +// case BROADCASTING: +// consumer.setMessageModel( +// org.apache.rocketmq.common.protocol.heartbeat.MessageModel.BROADCASTING); +// break; +// case CLUSTERING: +// consumer.setMessageModel( +// org.apache.rocketmq.common.protocol.heartbeat.MessageModel.CLUSTERING); +// break; +// default: +// throw new IllegalArgumentException("Property 'messageModel' was wrong."); +// } +// +// switch (selectorType) { +// case TAG: +// consumer.subscribe(topic, selectorExpression); +// break; +// case SQL92: +// consumer.subscribe(topic, MessageSelector.bySql(selectorExpression)); +// break; +// default: +// throw new IllegalArgumentException("Property 'selectorType' was wrong."); +// } +// +// switch (consumeMode) { +// case ORDERLY: +// consumer.setMessageListener(new DefaultMessageListenerOrderly()); +// break; +// case CONCURRENTLY: +// consumer.setMessageListener(new DefaultMessageListenerConcurrently()); +// break; +// default: +// throw new IllegalArgumentException("Property 'consumeMode' was wrong."); +// } +// +// if (rocketMQListener instanceof RocketMQPushConsumerLifecycleListener) { +// ((RocketMQPushConsumerLifecycleListener) rocketMQListener) +// .prepareStart(consumer); +// } +// +// } +// +// @Override +// public String toString() { +// return "RocketMQListenerBindingContainer{" + "consumerGroup='" + consumerGroup +// + '\'' + ", nameServer='" + nameServer + '\'' + ", topic='" + topic + '\'' +// + ", consumeMode=" + consumeMode + ", selectorType=" + selectorType +// + ", selectorExpression='" + selectorExpression + '\'' + ", messageModel=" +// + messageModel + '}'; +// } +// +// public long getSuspendCurrentQueueTimeMillis() { +// return suspendCurrentQueueTimeMillis; +// } +// +// public void setSuspendCurrentQueueTimeMillis(long suspendCurrentQueueTimeMillis) { +// this.suspendCurrentQueueTimeMillis = suspendCurrentQueueTimeMillis; +// } +// +// public int getDelayLevelWhenNextConsume() { +// return delayLevelWhenNextConsume; +// } +// +// public void setDelayLevelWhenNextConsume(int delayLevelWhenNextConsume) { +// this.delayLevelWhenNextConsume = delayLevelWhenNextConsume; +// } +// +// public List getNameServer() { +// return nameServer; +// } +// +// public void setNameServer(List nameServer) { +// this.nameServer = nameServer; +// } +// +// public String getConsumerGroup() { +// return consumerGroup; +// } +// +// public void setConsumerGroup(String consumerGroup) { +// this.consumerGroup = consumerGroup; +// } +// +// public String getTopic() { +// return topic; +// } +// +// public void setTopic(String topic) { +// this.topic = topic; +// } +// +// public int getConsumeThreadMax() { +// return consumeThreadMax; +// } +// +// public void setConsumeThreadMax(int consumeThreadMax) { +// this.consumeThreadMax = consumeThreadMax; +// } +// +// public String getCharset() { +// return charset; +// } +// +// public void setCharset(String charset) { +// this.charset = charset; +// } +// +// public RocketMQListener getRocketMQListener() { +// return rocketMQListener; +// } +// +// public void setRocketMQListener(RocketMQListener rocketMQListener) { +// this.rocketMQListener = rocketMQListener; +// } +// +// public DefaultMQPushConsumer getConsumer() { +// return consumer; +// } +// +// public void setConsumer(DefaultMQPushConsumer consumer) { +// this.consumer = consumer; +// } +// +// public ExtendedConsumerProperties +/// getRocketMQConsumerProperties() { +// return rocketMQConsumerProperties; +// } +// +// public ConsumeMode getConsumeMode() { +// return consumeMode; +// } +// +// public SelectorType getSelectorType() { +// return selectorType; +// } +// +// public String getSelectorExpression() { +// return selectorExpression; +// } +// +// public MessageModel getMessageModel() { +// return messageModel; +// } +// +// public RocketMQHeaderMapper getHeaderMapper() { +// return headerMapper; +// } +// +// public void setHeaderMapper(RocketMQHeaderMapper headerMapper) { +// this.headerMapper = headerMapper; +// } +// +// /** +// * Convert rocketmq {@link MessageExt} to Spring {@link Message}. +// * @param messageExt the rocketmq message +// * @return the converted Spring {@link Message} +// */ +// @SuppressWarnings("unchecked") +// private Message convertToSpringMessage(MessageExt messageExt) { +// +// // add reconsume-times header to messageExt +// int reconsumeTimes = messageExt.getReconsumeTimes(); +// messageExt.putUserProperty(ROCKETMQ_RECONSUME_TIMES, +// String.valueOf(reconsumeTimes)); +// Message message = RocketMQUtil.convertToSpringMessage(messageExt); +// return MessageBuilder.fromMessage(message) +// .copyHeaders(headerMapper.toHeaders(messageExt.getProperties())).build(); +// } +// +// public class DefaultMessageListenerConcurrently +// implements MessageListenerConcurrently { +// +// @SuppressWarnings({ "unchecked", "Duplicates" }) +// @Override +// public ConsumeConcurrentlyStatus consumeMessage(List msgs, +// ConsumeConcurrentlyContext context) { +// for (MessageExt messageExt : msgs) { +// log.debug("received msg: {}", messageExt); +// try { +// long now = System.currentTimeMillis(); +// rocketMQListener.onMessage(convertToSpringMessage(messageExt)); +// long costTime = System.currentTimeMillis() - now; +// log.debug("consume {} message key:[{}] cost: {} ms", +// messageExt.getMsgId(), messageExt.getKeys(), costTime); +// } +// catch (Exception e) { +// log.warn("consume message failed. messageExt:{}", messageExt, e); +// context.setDelayLevelWhenNextConsume(delayLevelWhenNextConsume); +// return ConsumeConcurrentlyStatus.RECONSUME_LATER; +// } +// } +// +// return ConsumeConcurrentlyStatus.CONSUME_SUCCESS; +// } +// +// } +// +// public class DefaultMessageListenerOrderly implements MessageListenerOrderly { +// +// @SuppressWarnings({ "unchecked", "Duplicates" }) +// @Override +// public ConsumeOrderlyStatus consumeMessage(List msgs, +// ConsumeOrderlyContext context) { +// for (MessageExt messageExt : msgs) { +// log.debug("received msg: {}", messageExt); +// try { +// long now = System.currentTimeMillis(); +// rocketMQListener.onMessage(convertToSpringMessage(messageExt)); +// long costTime = System.currentTimeMillis() - now; +// log.info("consume {} message key:[{}] cost: {} ms", +// messageExt.getMsgId(), messageExt.getKeys(), costTime); +// } +// catch (Exception e) { +// log.warn("consume message failed. messageExt:{}", messageExt, e); +// context.setSuspendCurrentQueueTimeMillis( +// suspendCurrentQueueTimeMillis); +// return ConsumeOrderlyStatus.SUSPEND_CURRENT_QUEUE_A_MOMENT; +// } +// } +// +// return ConsumeOrderlyStatus.SUCCESS; +// } +// +// } +// +// } diff --git a/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/integration/RocketMQInboundChannelAdapter.java b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/integration/RocketMQInboundChannelAdapter.java deleted file mode 100644 index a3b680419..000000000 --- a/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/integration/RocketMQInboundChannelAdapter.java +++ /dev/null @@ -1,176 +0,0 @@ -/* - * Copyright 2013-2018 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.alibaba.cloud.stream.binder.rocketmq.integration; - -import com.alibaba.cloud.stream.binder.rocketmq.consuming.RocketMQListenerBindingContainer; -import com.alibaba.cloud.stream.binder.rocketmq.metrics.Instrumentation; -import com.alibaba.cloud.stream.binder.rocketmq.metrics.InstrumentationManager; -import com.alibaba.cloud.stream.binder.rocketmq.properties.RocketMQConsumerProperties; -import org.apache.rocketmq.spring.core.RocketMQListener; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import org.springframework.cloud.stream.binder.ExtendedConsumerProperties; -import org.springframework.integration.endpoint.MessageProducerSupport; -import org.springframework.integration.support.MessageBuilder; -import org.springframework.messaging.Message; -import org.springframework.messaging.MessagingException; -import org.springframework.retry.RecoveryCallback; -import org.springframework.retry.RetryCallback; -import org.springframework.retry.RetryContext; -import org.springframework.retry.RetryListener; -import org.springframework.retry.support.RetryTemplate; -import org.springframework.util.Assert; - -/** - * @author Jim - */ -public class RocketMQInboundChannelAdapter extends MessageProducerSupport { - - private static final Logger log = LoggerFactory - .getLogger(RocketMQInboundChannelAdapter.class); - - private RetryTemplate retryTemplate; - - private RecoveryCallback recoveryCallback; - - private RocketMQListenerBindingContainer rocketMQListenerContainer; - - private final ExtendedConsumerProperties consumerProperties; - - private final InstrumentationManager instrumentationManager; - - public RocketMQInboundChannelAdapter( - RocketMQListenerBindingContainer rocketMQListenerContainer, - ExtendedConsumerProperties consumerProperties, - InstrumentationManager instrumentationManager) { - this.rocketMQListenerContainer = rocketMQListenerContainer; - this.consumerProperties = consumerProperties; - this.instrumentationManager = instrumentationManager; - } - - @Override - protected void onInit() { - if (consumerProperties == null - || !consumerProperties.getExtension().getEnabled()) { - return; - } - super.onInit(); - if (this.retryTemplate != null) { - Assert.state(getErrorChannel() == null, - "Cannot have an 'errorChannel' property when a 'RetryTemplate' is " - + "provided; use an 'ErrorMessageSendingRecoverer' in the 'recoveryCallback' property to " - + "send an error message when retries are exhausted"); - } - - BindingRocketMQListener listener = new BindingRocketMQListener(); - rocketMQListenerContainer.setRocketMQListener(listener); - - if (retryTemplate != null) { - this.retryTemplate.registerListener(listener); - } - - try { - rocketMQListenerContainer.afterPropertiesSet(); - - } - catch (Exception e) { - log.error("rocketMQListenerContainer init error: " + e.getMessage(), e); - throw new IllegalArgumentException( - "rocketMQListenerContainer init error: " + e.getMessage(), e); - } - - instrumentationManager.addHealthInstrumentation( - new Instrumentation(rocketMQListenerContainer.getTopic() - + rocketMQListenerContainer.getConsumerGroup())); - } - - @Override - protected void doStart() { - if (consumerProperties == null - || !consumerProperties.getExtension().getEnabled()) { - return; - } - try { - rocketMQListenerContainer.start(); - instrumentationManager - .getHealthInstrumentation(rocketMQListenerContainer.getTopic() - + rocketMQListenerContainer.getConsumerGroup()) - .markStartedSuccessfully(); - } - catch (Exception e) { - instrumentationManager - .getHealthInstrumentation(rocketMQListenerContainer.getTopic() - + rocketMQListenerContainer.getConsumerGroup()) - .markStartFailed(e); - log.error("RocketMQTemplate startup failed, Caused by " + e.getMessage()); - throw new MessagingException(MessageBuilder.withPayload( - "RocketMQTemplate startup failed, Caused by " + e.getMessage()) - .build(), e); - } - } - - @Override - protected void doStop() { - rocketMQListenerContainer.stop(); - } - - public void setRetryTemplate(RetryTemplate retryTemplate) { - this.retryTemplate = retryTemplate; - } - - public void setRecoveryCallback(RecoveryCallback recoveryCallback) { - this.recoveryCallback = recoveryCallback; - } - - protected class BindingRocketMQListener - implements RocketMQListener, RetryListener { - - @Override - public void onMessage(Message message) { - boolean enableRetry = RocketMQInboundChannelAdapter.this.retryTemplate != null; - if (enableRetry) { - RocketMQInboundChannelAdapter.this.retryTemplate.execute(context -> { - RocketMQInboundChannelAdapter.this.sendMessage(message); - return null; - }, (RecoveryCallback) RocketMQInboundChannelAdapter.this.recoveryCallback); - } - else { - RocketMQInboundChannelAdapter.this.sendMessage(message); - } - } - - @Override - public boolean open(RetryContext context, - RetryCallback callback) { - return true; - } - - @Override - public void close(RetryContext context, - RetryCallback callback, Throwable throwable) { - } - - @Override - public void onError(RetryContext context, - RetryCallback callback, Throwable throwable) { - - } - - } - -} diff --git a/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/integration/RocketMQMessageHandler.java b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/integration/RocketMQMessageHandler.java deleted file mode 100644 index 2bf3fa627..000000000 --- a/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/integration/RocketMQMessageHandler.java +++ /dev/null @@ -1,302 +0,0 @@ -/* - * Copyright 2013-2018 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.alibaba.cloud.stream.binder.rocketmq.integration; - -import java.util.List; -import java.util.Map; -import java.util.Optional; - -import com.alibaba.cloud.stream.binder.rocketmq.RocketMQBinderConstants; -import com.alibaba.cloud.stream.binder.rocketmq.metrics.Instrumentation; -import com.alibaba.cloud.stream.binder.rocketmq.metrics.InstrumentationManager; -import com.alibaba.cloud.stream.binder.rocketmq.properties.RocketMQProducerProperties; -import com.alibaba.cloud.stream.binder.rocketmq.support.RocketMQHeaderMapper; -import org.apache.rocketmq.client.exception.MQClientException; -import org.apache.rocketmq.client.producer.SendCallback; -import org.apache.rocketmq.client.producer.SendResult; -import org.apache.rocketmq.client.producer.SendStatus; -import org.apache.rocketmq.common.message.MessageConst; -import org.apache.rocketmq.common.message.MessageQueue; -import org.apache.rocketmq.spring.core.RocketMQTemplate; -import org.apache.rocketmq.spring.support.RocketMQHeaders; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import org.springframework.cloud.stream.binder.BinderHeaders; -import org.springframework.cloud.stream.binder.ExtendedProducerProperties; -import org.springframework.cloud.stream.binding.MessageConverterConfigurer; -import org.springframework.context.Lifecycle; -import org.springframework.integration.handler.AbstractMessageHandler; -import org.springframework.integration.support.DefaultErrorMessageStrategy; -import org.springframework.integration.support.ErrorMessageStrategy; -import org.springframework.integration.support.MessageBuilder; -import org.springframework.messaging.Message; -import org.springframework.messaging.MessageChannel; -import org.springframework.messaging.MessagingException; -import org.springframework.messaging.support.ErrorMessage; -import org.springframework.util.Assert; -import org.springframework.util.StringUtils; - -/** - * @author Jim - */ -public class RocketMQMessageHandler extends AbstractMessageHandler implements Lifecycle { - - private final static Logger log = LoggerFactory - .getLogger(RocketMQMessageHandler.class); - - private ErrorMessageStrategy errorMessageStrategy = new DefaultErrorMessageStrategy(); - - private MessageChannel sendFailureChannel; - - private final RocketMQTemplate rocketMQTemplate; - - private RocketMQHeaderMapper headerMapper; - - private final Boolean transactional; - - private final String destination; - - private final String groupName; - - private final InstrumentationManager instrumentationManager; - - private boolean sync = false; - - private volatile boolean running = false; - - private ExtendedProducerProperties producerProperties; - - private MessageConverterConfigurer.PartitioningInterceptor partitioningInterceptor; - - public RocketMQMessageHandler(RocketMQTemplate rocketMQTemplate, String destination, - String groupName, Boolean transactional, - InstrumentationManager instrumentationManager, - ExtendedProducerProperties producerProperties, - MessageConverterConfigurer.PartitioningInterceptor partitioningInterceptor) { - this.rocketMQTemplate = rocketMQTemplate; - this.destination = destination; - this.groupName = groupName; - this.transactional = transactional; - this.instrumentationManager = instrumentationManager; - this.producerProperties = producerProperties; - this.partitioningInterceptor = partitioningInterceptor; - } - - @Override - public void start() { - if (!transactional) { - instrumentationManager - .addHealthInstrumentation(new Instrumentation(destination)); - try { - rocketMQTemplate.afterPropertiesSet(); - instrumentationManager.getHealthInstrumentation(destination) - .markStartedSuccessfully(); - } - catch (Exception e) { - instrumentationManager.getHealthInstrumentation(destination) - .markStartFailed(e); - log.error("RocketMQTemplate startup failed, Caused by " + e.getMessage()); - throw new MessagingException(MessageBuilder.withPayload( - "RocketMQTemplate startup failed, Caused by " + e.getMessage()) - .build(), e); - } - } - if (producerProperties.isPartitioned()) { - try { - List messageQueues = rocketMQTemplate.getProducer() - .fetchPublishMessageQueues(destination); - if (producerProperties.getPartitionCount() != messageQueues.size()) { - logger.info(String.format( - "The partition count of topic '%s' will change from '%s' to '%s'", - destination, producerProperties.getPartitionCount(), - messageQueues.size())); - producerProperties.setPartitionCount(messageQueues.size()); - partitioningInterceptor - .setPartitionCount(producerProperties.getPartitionCount()); - } - } - catch (MQClientException e) { - logger.error("fetch publish message queues fail", e); - } - } - running = true; - } - - @Override - public void stop() { - if (!transactional) { - rocketMQTemplate.destroy(); - } - running = false; - } - - @Override - public boolean isRunning() { - return running; - } - - @Override - 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); - } - } - - } - - /** - * Set the failure channel. After a send failure, an {@link ErrorMessage} will be sent - * to this channel with a payload of a {@link MessagingException} with the failed - * message and cause. - * @param sendFailureChannel the failure channel. - * @since 0.2.2 - */ - public void setSendFailureChannel(MessageChannel sendFailureChannel) { - this.sendFailureChannel = sendFailureChannel; - } - - /** - * Set the error message strategy implementation to use when sending error messages - * after send failures. Cannot be null. - * @param errorMessageStrategy the implementation. - * @since 0.2.2 - */ - public void setErrorMessageStrategy(ErrorMessageStrategy errorMessageStrategy) { - Assert.notNull(errorMessageStrategy, "'errorMessageStrategy' cannot be null"); - this.errorMessageStrategy = errorMessageStrategy; - } - - public MessageChannel getSendFailureChannel() { - return sendFailureChannel; - } - - public void setSync(boolean sync) { - this.sync = sync; - } - - public RocketMQHeaderMapper getHeaderMapper() { - return headerMapper; - } - - public void setHeaderMapper(RocketMQHeaderMapper headerMapper) { - this.headerMapper = headerMapper; - } - -} diff --git a/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/integration/RocketMQMessageSource.java b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/integration/RocketMQMessageSource.java deleted file mode 100644 index dd95864e0..000000000 --- a/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/integration/RocketMQMessageSource.java +++ /dev/null @@ -1,382 +0,0 @@ -/* - * Copyright 2013-2018 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.alibaba.cloud.stream.binder.rocketmq.integration; - -import java.util.List; -import java.util.Set; - -import com.alibaba.cloud.stream.binder.rocketmq.RocketMQBinderUtils; -import com.alibaba.cloud.stream.binder.rocketmq.consuming.RocketMQMessageQueueChooser; -import com.alibaba.cloud.stream.binder.rocketmq.properties.RocketMQBinderConfigurationProperties; -import com.alibaba.cloud.stream.binder.rocketmq.properties.RocketMQConsumerProperties; -import org.apache.rocketmq.client.consumer.DefaultMQPullConsumer; -import org.apache.rocketmq.client.consumer.MessageQueueListener; -import org.apache.rocketmq.client.consumer.MessageSelector; -import org.apache.rocketmq.client.consumer.PullResult; -import org.apache.rocketmq.client.consumer.PullStatus; -import org.apache.rocketmq.client.exception.MQClientException; -import org.apache.rocketmq.common.message.MessageExt; -import org.apache.rocketmq.common.message.MessageQueue; -import org.apache.rocketmq.common.protocol.heartbeat.MessageModel; -import org.apache.rocketmq.spring.support.RocketMQUtil; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import org.springframework.beans.factory.DisposableBean; -import org.springframework.cloud.stream.binder.ExtendedConsumerProperties; -import org.springframework.context.Lifecycle; -import org.springframework.integration.IntegrationMessageHeaderAccessor; -import org.springframework.integration.acks.AcknowledgmentCallback; -import org.springframework.integration.acks.AcknowledgmentCallbackFactory; -import org.springframework.integration.endpoint.AbstractMessageSource; -import org.springframework.integration.support.MessageBuilder; -import org.springframework.messaging.Message; -import org.springframework.util.Assert; -import org.springframework.util.StringUtils; - -/** - * @author Jim - */ -public class RocketMQMessageSource extends AbstractMessageSource - implements DisposableBean, Lifecycle { - - private final static Logger log = LoggerFactory - .getLogger(RocketMQMessageSource.class); - - private final RocketMQCallbackFactory ackCallbackFactory; - - private final RocketMQBinderConfigurationProperties rocketMQBinderConfigurationProperties; - - private final ExtendedConsumerProperties rocketMQConsumerProperties; - - private final String topic; - - private final String group; - - private final Object consumerMonitor = new Object(); - - private DefaultMQPullConsumer consumer; - - private boolean running; - - private MessageSelector messageSelector; - - private RocketMQMessageQueueChooser messageQueueChooser = new RocketMQMessageQueueChooser(); - - public RocketMQMessageSource( - RocketMQBinderConfigurationProperties rocketMQBinderConfigurationProperties, - ExtendedConsumerProperties rocketMQConsumerProperties, - String topic, String group) { - this(new RocketMQCallbackFactory(), rocketMQBinderConfigurationProperties, - rocketMQConsumerProperties, topic, group); - } - - public RocketMQMessageSource(RocketMQCallbackFactory ackCallbackFactory, - RocketMQBinderConfigurationProperties rocketMQBinderConfigurationProperties, - ExtendedConsumerProperties rocketMQConsumerProperties, - String topic, String group) { - this.ackCallbackFactory = ackCallbackFactory; - this.rocketMQBinderConfigurationProperties = rocketMQBinderConfigurationProperties; - this.rocketMQConsumerProperties = rocketMQConsumerProperties; - this.topic = topic; - this.group = group; - } - - @Override - public synchronized void start() { - if (this.isRunning()) { - throw new IllegalStateException( - "pull consumer already running. " + this.toString()); - } - try { - consumer = new DefaultMQPullConsumer(group); - consumer.setNamesrvAddr(RocketMQBinderUtils.getNameServerStr( - rocketMQBinderConfigurationProperties.getNameServer())); - consumer.setConsumerPullTimeoutMillis( - rocketMQConsumerProperties.getExtension().getPullTimeout()); - consumer.setMessageModel(MessageModel.CLUSTERING); - - String tags = rocketMQConsumerProperties.getExtension().getTags(); - String sql = rocketMQConsumerProperties.getExtension().getSql(); - - if (!StringUtils.isEmpty(tags) && !StringUtils.isEmpty(sql)) { - messageSelector = MessageSelector.byTag(tags); - } - else if (!StringUtils.isEmpty(tags)) { - messageSelector = MessageSelector.byTag(tags); - } - else if (!StringUtils.isEmpty(sql)) { - messageSelector = MessageSelector.bySql(sql); - } - - consumer.registerMessageQueueListener(topic, new MessageQueueListener() { - @Override - public void messageQueueChanged(String topic, Set mqAll, - Set mqDivided) { - log.info( - "messageQueueChanged, topic='{}', mqAll=`{}`, mqDivided=`{}`", - topic, mqAll, mqDivided); - switch (consumer.getMessageModel()) { - case BROADCASTING: - RocketMQMessageSource.this.resetMessageQueues(mqAll); - break; - case CLUSTERING: - RocketMQMessageSource.this.resetMessageQueues(mqDivided); - break; - default: - break; - } - } - }); - consumer.start(); - } - catch (MQClientException e) { - log.error("DefaultMQPullConsumer startup error: " + e.getMessage(), e); - } - this.setRunning(true); - } - - @Override - public synchronized void stop() { - if (this.isRunning()) { - this.setRunning(false); - consumer.shutdown(); - } - } - - @Override - public synchronized boolean isRunning() { - return running; - } - - @Override - protected synchronized Object doReceive() { - if (messageQueueChooser.getMessageQueues() == null - || messageQueueChooser.getMessageQueues().size() == 0) { - return null; - } - try { - int count = 0; - while (count < messageQueueChooser.getMessageQueues().size()) { - MessageQueue messageQueue; - synchronized (this.consumerMonitor) { - messageQueue = messageQueueChooser.choose(); - messageQueueChooser.increment(); - } - - long offset = consumer.fetchConsumeOffset(messageQueue, - rocketMQConsumerProperties.getExtension().isFromStore()); - - log.debug("topic='{}', group='{}', messageQueue='{}', offset now='{}'", - this.topic, this.group, messageQueue, offset); - - PullResult pullResult; - if (messageSelector != null) { - pullResult = consumer.pull(messageQueue, messageSelector, offset, 1); - } - else { - pullResult = consumer.pull(messageQueue, (String) null, offset, 1); - } - - if (pullResult.getPullStatus() == PullStatus.FOUND) { - List messageExtList = pullResult.getMsgFoundList(); - - Message message = RocketMQUtil - .convertToSpringMessage(messageExtList.get(0)); - - AcknowledgmentCallback ackCallback = this.ackCallbackFactory - .createCallback(new RocketMQAckInfo(messageQueue, pullResult, - consumer, offset)); - - Message messageResult = MessageBuilder.fromMessage(message).setHeader( - IntegrationMessageHeaderAccessor.ACKNOWLEDGMENT_CALLBACK, - ackCallback).build(); - return messageResult; - } - else { - log.debug("messageQueue='{}' PullResult='{}' with topic `{}`", - messageQueueChooser.getMessageQueues(), - pullResult.getPullStatus(), topic); - } - count++; - } - } - catch (Exception e) { - log.error("Consumer pull error: " + e.getMessage(), e); - } - return null; - } - - @Override - public String getComponentType() { - return "rocketmq:message-source"; - } - - public synchronized void setRunning(boolean running) { - this.running = running; - } - - public synchronized void resetMessageQueues(Set queueSet) { - log.info("resetMessageQueues, topic='{}', messageQueue=`{}`", topic, queueSet); - synchronized (this.consumerMonitor) { - this.messageQueueChooser.reset(queueSet); - } - } - - public static class RocketMQCallbackFactory - implements AcknowledgmentCallbackFactory { - - @Override - public AcknowledgmentCallback createCallback(RocketMQAckInfo info) { - return new RocketMQAckCallback(info); - } - - } - - public static class RocketMQAckCallback implements AcknowledgmentCallback { - - private final RocketMQAckInfo ackInfo; - - private boolean acknowledged; - - private boolean autoAckEnabled = true; - - public RocketMQAckCallback(RocketMQAckInfo ackInfo) { - this.ackInfo = ackInfo; - } - - protected void setAcknowledged(boolean acknowledged) { - this.acknowledged = acknowledged; - } - - @Override - public boolean isAcknowledged() { - return this.acknowledged; - } - - @Override - public void noAutoAck() { - this.autoAckEnabled = false; - } - - @Override - public boolean isAutoAck() { - return this.autoAckEnabled; - } - - @Override - public void acknowledge(Status status) { - Assert.notNull(status, "'status' cannot be null"); - if (this.acknowledged) { - throw new IllegalStateException("Already acknowledged"); - } - log.debug("acknowledge(" + status.name() + ") for " + this); - synchronized (this.ackInfo.getConsumerMonitor()) { - try { - switch (status) { - case ACCEPT: - case REJECT: - ackInfo.getConsumer().updateConsumeOffset( - ackInfo.getMessageQueue(), - ackInfo.getPullResult().getNextBeginOffset()); - log.debug("messageQueue='{}' offset update to `{}`", - ackInfo.getMessageQueue(), String.valueOf( - ackInfo.getPullResult().getNextBeginOffset())); - break; - case REQUEUE: - // decrease index and update offset of messageQueue of ackInfo - int oldIndex = ackInfo.getMessageQueueChooser().requeue(); - ackInfo.getConsumer().updateConsumeOffset( - ackInfo.getMessageQueue(), ackInfo.getOldOffset()); - log.debug( - "messageQueue='{}' offset requeue to index:`{}`, oldOffset:'{}'", - ackInfo.getMessageQueue(), oldIndex, - ackInfo.getOldOffset()); - break; - default: - break; - } - } - catch (MQClientException e) { - log.error("acknowledge error: " + e.getErrorMessage(), e); - } - finally { - this.acknowledged = true; - } - } - } - - @Override - public String toString() { - return "RocketMQAckCallback{" + "ackInfo=" + ackInfo + ", acknowledged=" - + acknowledged + ", autoAckEnabled=" + autoAckEnabled + '}'; - } - - } - - public class RocketMQAckInfo { - - private final MessageQueue messageQueue; - - private final PullResult pullResult; - - private final DefaultMQPullConsumer consumer; - - private final long oldOffset; - - public RocketMQAckInfo(MessageQueue messageQueue, PullResult pullResult, - DefaultMQPullConsumer consumer, long oldOffset) { - this.messageQueue = messageQueue; - this.pullResult = pullResult; - this.consumer = consumer; - this.oldOffset = oldOffset; - } - - public MessageQueue getMessageQueue() { - return messageQueue; - } - - public PullResult getPullResult() { - return pullResult; - } - - public DefaultMQPullConsumer getConsumer() { - return consumer; - } - - public RocketMQMessageQueueChooser getMessageQueueChooser() { - return RocketMQMessageSource.this.messageQueueChooser; - } - - public long getOldOffset() { - return oldOffset; - } - - public Object getConsumerMonitor() { - return RocketMQMessageSource.this.consumerMonitor; - } - - @Override - public String toString() { - return "RocketMQAckInfo{" + "messageQueue=" + messageQueue + ", pullResult=" - + pullResult + ", consumer=" + consumer + ", oldOffset=" + oldOffset - + '}'; - } - - } - -} diff --git a/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/metrics/Instrumentation.java b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/metrics/Instrumentation.java index 080bebf90..397e62854 100644 --- a/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/metrics/Instrumentation.java +++ b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/metrics/Instrumentation.java @@ -16,8 +16,11 @@ package com.alibaba.cloud.stream.binder.rocketmq.metrics; +import java.util.Objects; import java.util.concurrent.atomic.AtomicBoolean; +import org.springframework.context.Lifecycle; + /** * @author Timur Valiev * @author Jim @@ -25,6 +28,7 @@ import java.util.concurrent.atomic.AtomicBoolean; public class Instrumentation { private final String name; + private Lifecycle actuator; protected final AtomicBoolean started = new AtomicBoolean(false); @@ -34,6 +38,19 @@ public class Instrumentation { this.name = name; } + public Instrumentation(String name, Lifecycle actuator) { + this.name = name; + this.actuator = actuator; + } + + public Lifecycle getActuator() { + return actuator; + } + + public void setActuator(Lifecycle actuator) { + this.actuator = actuator; + } + public boolean isDown() { return startException != null; } @@ -67,4 +84,8 @@ public class Instrumentation { return startException; } + @Override + public int hashCode() { + return Objects.hash(getName(), getActuator()); + } } diff --git a/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/metrics/InstrumentationManager.java b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/metrics/InstrumentationManager.java index 8b4939585..de6e1e794 100644 --- a/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/metrics/InstrumentationManager.java +++ b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/metrics/InstrumentationManager.java @@ -16,37 +16,34 @@ package com.alibaba.cloud.stream.binder.rocketmq.metrics; +import java.util.Collection; import java.util.HashMap; import java.util.Map; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; -import java.util.stream.Collectors; /** * @author Timur Valiev * @author Jim */ -public class InstrumentationManager { +public final class InstrumentationManager { - private final Map runtime = new ConcurrentHashMap<>(); + private static final Map HEALTH_INSTRUMENTATIONS = new HashMap<>(); - private final Map healthInstrumentations = new HashMap<>(); - - public Set getHealthInstrumentations() { - return healthInstrumentations.entrySet().stream().map(Map.Entry::getValue) - .collect(Collectors.toSet()); - } - - public void addHealthInstrumentation(Instrumentation instrumentation) { - healthInstrumentations.put(instrumentation.getName(), instrumentation); + public static Collection getHealthInstrumentations() { + return HEALTH_INSTRUMENTATIONS.values(); } - public Instrumentation getHealthInstrumentation(String key) { - return healthInstrumentations.get(key); - } + public static void addHealthInstrumentation(Instrumentation instrumentation) { + if (null != instrumentation) { + HEALTH_INSTRUMENTATIONS.computeIfPresent(instrumentation.hashCode(), + (k, v) -> { + if (instrumentation.getActuator() != null) { + instrumentation.getActuator().stop(); + } + throw new IllegalArgumentException( + "The current actuator exists, please confirm if there is a repeat operation!!!"); + }); + } - public Map getRuntime() { - return runtime; } } diff --git a/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/properties/RocketMQBinderConfigurationProperties.java b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/properties/RocketMQBinderConfigurationProperties.java index 3a9dcb403..fd5e77919 100644 --- a/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/properties/RocketMQBinderConfigurationProperties.java +++ b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/properties/RocketMQBinderConfigurationProperties.java @@ -1,11 +1,11 @@ /* - * Copyright 2013-2018 the original author or authors. + * Copyright (C) 2018 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -16,86 +16,13 @@ package com.alibaba.cloud.stream.binder.rocketmq.properties; -import java.util.Arrays; -import java.util.List; - -import com.alibaba.cloud.stream.binder.rocketmq.RocketMQBinderConstants; -import org.apache.rocketmq.common.MixAll; - import org.springframework.boot.context.properties.ConfigurationProperties; /** - * @author Timur Valiev + * binding rocketMq properties. * @author Jim */ @ConfigurationProperties(prefix = "spring.cloud.stream.rocketmq.binder") -public class RocketMQBinderConfigurationProperties { - - /** - * The name server list for rocketMQ. - */ - private List nameServer = Arrays - .asList(RocketMQBinderConstants.DEFAULT_NAME_SERVER); - - /** - * The property of "access-key". - */ - private String accessKey; - - /** - * The property of "secret-key". - */ - private String secretKey; - - /** - * Switch flag instance for message trace. - */ - private boolean enableMsgTrace = true; - - /** - * The name value of message trace topic.If you don't config,you can use the default - * trace topic name. - */ - private String customizedTraceTopic = MixAll.RMQ_SYS_TRACE_TOPIC; - - public List getNameServer() { - return nameServer; - } - - public void setNameServer(List nameServer) { - this.nameServer = nameServer; - } - - public String getAccessKey() { - return accessKey; - } - - public void setAccessKey(String accessKey) { - this.accessKey = accessKey; - } - - public String getSecretKey() { - return secretKey; - } - - public void setSecretKey(String secretKey) { - this.secretKey = secretKey; - } - - public boolean isEnableMsgTrace() { - return enableMsgTrace; - } - - public void setEnableMsgTrace(boolean enableMsgTrace) { - this.enableMsgTrace = enableMsgTrace; - } - - public String getCustomizedTraceTopic() { - return customizedTraceTopic; - } - - public void setCustomizedTraceTopic(String customizedTraceTopic) { - this.customizedTraceTopic = customizedTraceTopic; - } +public class RocketMQBinderConfigurationProperties extends RocketMQCommonProperties { } diff --git a/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/properties/RocketMQBindingProperties.java b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/properties/RocketMQBindingProperties.java deleted file mode 100644 index 814ae1018..000000000 --- a/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/properties/RocketMQBindingProperties.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2013-2018 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.alibaba.cloud.stream.binder.rocketmq.properties; - -import org.springframework.cloud.stream.binder.BinderSpecificPropertiesProvider; - -/** - * @author Timur Valiev - * @author Jim - */ -public class RocketMQBindingProperties implements BinderSpecificPropertiesProvider { - - private RocketMQConsumerProperties consumer = new RocketMQConsumerProperties(); - - private RocketMQProducerProperties producer = new RocketMQProducerProperties(); - - @Override - public RocketMQConsumerProperties getConsumer() { - return consumer; - } - - public void setConsumer(RocketMQConsumerProperties consumer) { - this.consumer = consumer; - } - - @Override - public RocketMQProducerProperties getProducer() { - return producer; - } - - public void setProducer(RocketMQProducerProperties producer) { - this.producer = producer; - } - -} diff --git a/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/properties/RocketMQConsumerProperties.java b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/properties/RocketMQConsumerProperties.java index 9c059ec56..1a889f6d7 100644 --- a/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/properties/RocketMQConsumerProperties.java +++ b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/properties/RocketMQConsumerProperties.java @@ -1,11 +1,11 @@ /* - * Copyright 2013-2018 the original author or authors. + * Copyright (C) 2018 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -16,153 +16,436 @@ package com.alibaba.cloud.stream.binder.rocketmq.properties; -import java.util.Set; +import java.io.Serializable; -import com.alibaba.cloud.stream.binder.rocketmq.support.JacksonRocketMQHeaderMapper; -import org.apache.rocketmq.client.consumer.MQPushConsumer; -import org.apache.rocketmq.client.consumer.MessageSelector; import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyContext; +import org.apache.rocketmq.client.consumer.listener.ConsumeOrderlyContext; import org.apache.rocketmq.client.consumer.listener.MessageListenerConcurrently; import org.apache.rocketmq.client.consumer.listener.MessageListenerOrderly; +import org.apache.rocketmq.client.impl.consumer.ConsumeMessageConcurrentlyService; +import org.apache.rocketmq.client.impl.consumer.ConsumeMessageOrderlyService; +import org.apache.rocketmq.common.UtilAll; +import org.apache.rocketmq.common.consumer.ConsumeFromWhere; import org.apache.rocketmq.common.protocol.heartbeat.MessageModel; /** - * @author Timur Valiev + * Extended consumer properties for RocketMQ binder. + * * @author Jim */ -public class RocketMQConsumerProperties { +public class RocketMQConsumerProperties extends RocketMQCommonProperties { /** - * using '||' to split tag {@link MQPushConsumer#subscribe(String, String)}. + * Message model defines the way how messages are delivered to each consumer clients. + *

+ * + * This field defaults to clustering. */ - private String tags; + private String messageModel = MessageModel.CLUSTERING.getModeCN(); /** - * {@link MQPushConsumer#subscribe(String, MessageSelector)} - * {@link MessageSelector#bySql(String)}. + * Queue allocation algorithm specifying how message queues are allocated to each + * consumer clients. */ - private String sql; + private String allocateMessageQueueStrategy; /** - * {@link MessageModel#BROADCASTING}. + * The expressions include tags or SQL,as follow: + *

+ * tag: {@code tag1||tag2||tag3 }; sql: {@code 'color'='blue' AND 'price'>100 } . + *

+ * Determines whether there are specific characters "{@code ||}" in the expression to + * determine how the message is filtered,tags or SQL. */ - private Boolean broadcasting = false; + private String subscription; /** - * if orderly is true, using {@link MessageListenerOrderly} else if orderly if false, - * using {@link MessageListenerConcurrently}. + * Delay some time when exception occur */ - private Boolean orderly = false; + private long pullTimeDelayMillsWhenException = 1000; /** - * for concurrently listener. message consume retry strategy. see - * {@link ConsumeConcurrentlyContext#delayLevelWhenNextConsume}. -1 means dlq(or - * discard, see {@link this#shouldRequeue}), others means requeue. + * Consuming point on consumer booting. + *

+ * + * There are three consuming points: + *
    + *
  • CONSUME_FROM_LAST_OFFSET: consumer clients pick up where it + * stopped previously. If it were a newly booting up consumer client, according aging + * of the consumer group, there are two cases: + *
      + *
    1. if the consumer group is created so recently that the earliest message being + * subscribed has yet expired, which means the consumer group represents a lately + * launched business, consuming will start from the very beginning;
    2. + *
    3. if the earliest message being subscribed has expired, consuming will start from + * the latest messages, meaning messages born prior to the booting timestamp would be + * ignored.
    4. + *
    + *
  • + *
  • CONSUME_FROM_FIRST_OFFSET: Consumer client will start from + * earliest messages available.
  • + *
  • CONSUME_FROM_TIMESTAMP: Consumer client will start from specified + * timestamp, which means messages born prior to {@link #consumeTimestamp} will be + * ignored
  • + *
+ */ + private ConsumeFromWhere consumeFromWhere = ConsumeFromWhere.CONSUME_FROM_LAST_OFFSET; + /** + * Backtracking consumption time with second precision. Time format is + * 20131223171201
+ * Implying Seventeen twelve and 01 seconds on December 23, 2013 year
+ * Default backtracking consumption time Half an hour ago. */ - private int delayLevelWhenNextConsume = 0; + private String consumeTimestamp = UtilAll + .timeMillisToHumanString3(System.currentTimeMillis() - (1000 * 60 * 30)); /** - * for orderly listener. next retry delay time. + * Flow control threshold on queue level, each message queue will cache at most 1000 + * messages by default, Consider the {@link #pullBatchSize}, the instantaneous value + * may exceed the limit */ - private long suspendCurrentQueueTimeMillis = 1000; + private int pullThresholdForQueue = 1000; + /** + * Limit the cached message size on queue level, each message queue will cache at most + * 100 MiB messages by default, Consider the {@link #pullBatchSize}, the instantaneous + * value may exceed the limit + * + *

+ * The size of a message only measured by message body, so it's not accurate + */ + private int pullThresholdSizeForQueue = 100; - private Boolean enabled = true; + /** + * Maximum number of messages pulled each time. + */ + private int pullBatchSize = 10; /** - * {@link JacksonRocketMQHeaderMapper#addTrustedPackages(String...)}. + * Consume max span offset.it has no effect on sequential consumption. */ - private Set trustedPackages; + private int consumeMaxSpan = 2000; - // ------------ For Pull Consumer ------------ + private Push push = new Push(); + private Pull pull = new Pull(); - private long pullTimeout = 10 * 1000; + public String getMessageModel() { + return messageModel; + } + + public RocketMQConsumerProperties setMessageModel(String messageModel) { + this.messageModel = messageModel; + return this; + } - private boolean fromStore; + public String getAllocateMessageQueueStrategy() { + return allocateMessageQueueStrategy; + } - // ------------ For Pull Consumer ------------ + public void setAllocateMessageQueueStrategy(String allocateMessageQueueStrategy) { + this.allocateMessageQueueStrategy = allocateMessageQueueStrategy; + } + + public String getSubscription() { + return subscription; + } - public String getTags() { - return tags; + public void setSubscription(String subscription) { + this.subscription = subscription; } - public void setTags(String tags) { - this.tags = tags; + public Push getPush() { + return push; } - public String getSql() { - return sql; + public void setPush(Push push) { + this.push = push; } - public void setSql(String sql) { - this.sql = sql; + public long getPullTimeDelayMillsWhenException() { + return pullTimeDelayMillsWhenException; } - public Boolean getOrderly() { - return orderly; + public RocketMQConsumerProperties setPullTimeDelayMillsWhenException( + long pullTimeDelayMillsWhenException) { + this.pullTimeDelayMillsWhenException = pullTimeDelayMillsWhenException; + return this; } - public void setOrderly(Boolean orderly) { - this.orderly = orderly; + public ConsumeFromWhere getConsumeFromWhere() { + return consumeFromWhere; } - public Boolean getEnabled() { - return enabled; + public RocketMQConsumerProperties setConsumeFromWhere( + ConsumeFromWhere consumeFromWhere) { + this.consumeFromWhere = consumeFromWhere; + return this; } - public void setEnabled(Boolean enabled) { - this.enabled = enabled; + public String getConsumeTimestamp() { + return consumeTimestamp; } - public Boolean getBroadcasting() { - return broadcasting; + public RocketMQConsumerProperties setConsumeTimestamp(String consumeTimestamp) { + this.consumeTimestamp = consumeTimestamp; + return this; } - public void setBroadcasting(Boolean broadcasting) { - this.broadcasting = broadcasting; + public int getPullThresholdForQueue() { + return pullThresholdForQueue; } - public int getDelayLevelWhenNextConsume() { - return delayLevelWhenNextConsume; + public RocketMQConsumerProperties setPullThresholdForQueue( + int pullThresholdForQueue) { + this.pullThresholdForQueue = pullThresholdForQueue; + return this; } - public void setDelayLevelWhenNextConsume(int delayLevelWhenNextConsume) { - this.delayLevelWhenNextConsume = delayLevelWhenNextConsume; + public int getPullThresholdSizeForQueue() { + return pullThresholdSizeForQueue; } - public long getSuspendCurrentQueueTimeMillis() { - return suspendCurrentQueueTimeMillis; + public RocketMQConsumerProperties setPullThresholdSizeForQueue( + int pullThresholdSizeForQueue) { + this.pullThresholdSizeForQueue = pullThresholdSizeForQueue; + return this; } - public void setSuspendCurrentQueueTimeMillis(long suspendCurrentQueueTimeMillis) { - this.suspendCurrentQueueTimeMillis = suspendCurrentQueueTimeMillis; + public int getPullBatchSize() { + return pullBatchSize; } - public long getPullTimeout() { - return pullTimeout; + public RocketMQConsumerProperties setPullBatchSize(int pullBatchSize) { + this.pullBatchSize = pullBatchSize; + return this; } - public void setPullTimeout(long pullTimeout) { - this.pullTimeout = pullTimeout; + public Pull getPull() { + return pull; } - public boolean isFromStore() { - return fromStore; + public RocketMQConsumerProperties setPull(Pull pull) { + this.pull = pull; + return this; } - public void setFromStore(boolean fromStore) { - this.fromStore = fromStore; + public int getConsumeMaxSpan() { + return consumeMaxSpan; } - public boolean shouldRequeue() { - return delayLevelWhenNextConsume != -1; + public RocketMQConsumerProperties setConsumeMaxSpan(int consumeMaxSpan) { + this.consumeMaxSpan = consumeMaxSpan; + return this; } - public Set getTrustedPackages() { - return trustedPackages; + public static class Push implements Serializable { + private static final long serialVersionUID = -7398468554978817630L; + + /** + * if orderly is true, using {@link MessageListenerOrderly} else if orderly if + * false, using {@link MessageListenerConcurrently}. + */ + private boolean orderly = false; + /** + * Suspending pulling time for cases requiring slow pulling like flow-control + * scenario. see{@link ConsumeMessageOrderlyService#processConsumeResult}. + * see{@link ConsumeOrderlyContext#getSuspendCurrentQueueTimeMillis}. + */ + private int suspendCurrentQueueTimeMillis = 1000; + + /** + * https://github.com/alibaba/spring-cloud-alibaba/issues/1866 Max re-consume + * times. -1 means 16 times. + *

+ * If messages are re-consumed more than {@link #maxReconsumeTimes} before + * success, it's be directed to a deletion queue waiting. + */ + private int maxReconsumeTimes; + + /** + * for concurrently listener. message consume retry strategy. -1 means dlq(or + * discard. see {@link ConsumeMessageConcurrentlyService#processConsumeResult}. + * see {@link ConsumeConcurrentlyContext#getDelayLevelWhenNextConsume}. + */ + private int delayLevelWhenNextConsume = 0; + + /** + * Flow control threshold on topic level, default value is -1(Unlimited) + *

+ * The value of {@code pullThresholdForQueue} will be overwrote and calculated + * based on {@code pullThresholdForTopic} if it is't unlimited + *

+ * For example, if the value of pullThresholdForTopic is 1000 and 10 message + * queues are assigned to this consumer, then pullThresholdForQueue will be set to + * 100. + */ + private int pullThresholdForTopic = -1; + + /** + * Limit the cached message size on topic level, default value is -1 + * MiB(Unlimited) + *

+ * The value of {@code pullThresholdSizeForQueue} will be overwrote and calculated + * based on {@code pullThresholdSizeForTopic} if it is't unlimited + *

+ * For example, if the value of pullThresholdSizeForTopic is 1000 MiB and 10 + * message queues are assigned to this consumer, then pullThresholdSizeForQueue + * will be set to 100 MiB + */ + private int pullThresholdSizeForTopic = -1; + + /** + * Message pull Interval + */ + private long pullInterval = 0; + + /** + * Batch consumption size + */ + private int consumeMessageBatchMaxSize = 1; + + public boolean getOrderly() { + return orderly; + } + + public void setOrderly(boolean orderly) { + this.orderly = orderly; + } + + public int getSuspendCurrentQueueTimeMillis() { + return suspendCurrentQueueTimeMillis; + } + + public void setSuspendCurrentQueueTimeMillis(int suspendCurrentQueueTimeMillis) { + this.suspendCurrentQueueTimeMillis = suspendCurrentQueueTimeMillis; + } + + public int getMaxReconsumeTimes() { + return maxReconsumeTimes; + } + + public void setMaxReconsumeTimes(int maxReconsumeTimes) { + this.maxReconsumeTimes = maxReconsumeTimes; + } + + public int getDelayLevelWhenNextConsume() { + return delayLevelWhenNextConsume; + } + + public void setDelayLevelWhenNextConsume(int delayLevelWhenNextConsume) { + this.delayLevelWhenNextConsume = delayLevelWhenNextConsume; + } + + public int getPullThresholdForTopic() { + return pullThresholdForTopic; + } + + public void setPullThresholdForTopic(int pullThresholdForTopic) { + this.pullThresholdForTopic = pullThresholdForTopic; + } + + public int getPullThresholdSizeForTopic() { + return pullThresholdSizeForTopic; + } + + public void setPullThresholdSizeForTopic(int pullThresholdSizeForTopic) { + this.pullThresholdSizeForTopic = pullThresholdSizeForTopic; + } + + public long getPullInterval() { + return pullInterval; + } + + public void setPullInterval(long pullInterval) { + this.pullInterval = pullInterval; + } + + public int getConsumeMessageBatchMaxSize() { + return consumeMessageBatchMaxSize; + } + + public void setConsumeMessageBatchMaxSize(int consumeMessageBatchMaxSize) { + this.consumeMessageBatchMaxSize = consumeMessageBatchMaxSize; + } } - public void setTrustedPackages(Set trustedPackages) { - this.trustedPackages = trustedPackages; + public static class Pull implements Serializable { + /** + * The poll timeout in milliseconds + */ + private long pollTimeoutMillis = 1000 * 5; + /** + * Pull thread number + */ + private int pullThreadNums = 20; + + /** + * Interval time in in milliseconds for checking changes in topic metadata. + */ + private long topicMetadataCheckIntervalMillis = 30 * 1000; + + /** + * Long polling mode, the Consumer connection timeout(must greater than + * brokerSuspendMaxTimeMillis), it is not recommended to modify + */ + private long consumerTimeoutMillisWhenSuspend = 1000 * 30; + + /** + * Ack state handling, including receive, reject, and retry, when a consumption + * exception occurs. see {@link } + */ + private String errAcknowledge; + + private long pullThresholdForAll = 1000L; + + public long getPollTimeoutMillis() { + return pollTimeoutMillis; + } + + public void setPollTimeoutMillis(long pollTimeoutMillis) { + this.pollTimeoutMillis = pollTimeoutMillis; + } + + public int getPullThreadNums() { + return pullThreadNums; + } + + public void setPullThreadNums(int pullThreadNums) { + this.pullThreadNums = pullThreadNums; + } + + public long getTopicMetadataCheckIntervalMillis() { + return topicMetadataCheckIntervalMillis; + } + + public void setTopicMetadataCheckIntervalMillis( + long topicMetadataCheckIntervalMillis) { + this.topicMetadataCheckIntervalMillis = topicMetadataCheckIntervalMillis; + } + + public long getConsumerTimeoutMillisWhenSuspend() { + return consumerTimeoutMillisWhenSuspend; + } + + public void setConsumerTimeoutMillisWhenSuspend( + long consumerTimeoutMillisWhenSuspend) { + this.consumerTimeoutMillisWhenSuspend = consumerTimeoutMillisWhenSuspend; + } + + public String getErrAcknowledge() { + return errAcknowledge; + } + + public void setErrAcknowledge(String errAcknowledge) { + this.errAcknowledge = errAcknowledge; + } + + public long getPullThresholdForAll() { + return pullThresholdForAll; + } + + public void setPullThresholdForAll(long pullThresholdForAll) { + this.pullThresholdForAll = pullThresholdForAll; + } } } diff --git a/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/properties/RocketMQExtendedBindingProperties.java b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/properties/RocketMQExtendedBindingProperties.java index 890d22500..5fc34ed08 100644 --- a/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/properties/RocketMQExtendedBindingProperties.java +++ b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/properties/RocketMQExtendedBindingProperties.java @@ -1,11 +1,11 @@ /* - * Copyright 2013-2018 the original author or authors. + * Copyright (C) 2018 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -21,12 +21,14 @@ import org.springframework.cloud.stream.binder.AbstractExtendedBindingProperties import org.springframework.cloud.stream.binder.BinderSpecificPropertiesProvider; /** - * @author Timur Valiev + * rocketMQ specific extended binding properties class that extends from + * {@link AbstractExtendedBindingProperties}. + * * @author Jim */ @ConfigurationProperties("spring.cloud.stream.rocketmq") public class RocketMQExtendedBindingProperties extends - AbstractExtendedBindingProperties { + AbstractExtendedBindingProperties { private static final String DEFAULTS_PREFIX = "spring.cloud.stream.rocketmq.default"; @@ -37,7 +39,7 @@ public class RocketMQExtendedBindingProperties extends @Override public Class getExtendedPropertiesEntryClass() { - return RocketMQBindingProperties.class; + return RocketMQSpecificPropertiesProvider.class; } } diff --git a/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/properties/RocketMQProducerProperties.java b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/properties/RocketMQProducerProperties.java index ab2a92a3a..8f73cf93f 100644 --- a/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/properties/RocketMQProducerProperties.java +++ b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/properties/RocketMQProducerProperties.java @@ -1,11 +1,11 @@ /* - * Copyright 2013-2018 the original author or authors. + * Copyright (C) 2018 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -16,55 +16,39 @@ package com.alibaba.cloud.stream.binder.rocketmq.properties; -import org.apache.rocketmq.client.producer.DefaultMQProducer; - /** - * @author Timur Valiev + * Extended producer properties for RocketMQ binder. + * * @author Jim */ -public class RocketMQProducerProperties { - - private Boolean enabled = true; +public class RocketMQProducerProperties extends RocketMQCommonProperties { /** - * Name of producer. + * Timeout for sending messages. */ - private String group; - - /** - * Maximum allowed message size in bytes {@link DefaultMQProducer#maxMessageSize}. - */ - private Integer maxMessageSize = 1024 * 1024 * 4; - - private Boolean transactional = false; - - private Boolean sync = false; - - private Boolean vipChannelEnabled = true; - - /** - * Millis of send message timeout. - */ - private int sendMessageTimeout = 3000; + private int sendMsgTimeout = 3000; /** * Compress message body threshold, namely, message body larger than 4k will be * compressed on default. */ - private int compressMessageBodyThreshold = 1024 * 4; + private int compressMsgBodyThreshold = 1024 * 4; /** * Maximum number of retry to perform internally before claiming sending failure in - * synchronous mode. This may potentially cause message duplication which is up to - * application developers to resolve. + * synchronous mode. + *

+ * + * This may potentially cause message duplication which is up to application + * developers to resolve. */ private int retryTimesWhenSendFailed = 2; /** - *

* Maximum number of retry to perform internally before claiming sending failure in * asynchronous mode. *

+ * * This may potentially cause message duplication which is up to application * developers to resolve. */ @@ -73,94 +57,165 @@ public class RocketMQProducerProperties { /** * Indicate whether to retry another broker on sending failure internally. */ - private boolean retryNextServer = false; + private boolean retryAnotherBroker = false; - public String getGroup() { - return group; + /** + * Maximum allowed message size in bytes. + */ + private int maxMessageSize = 1024 * 1024 * 4; + + private String producerType = ProducerType.Normal.name(); + + private String sendType = SendType.Sync.name(); + + private String sendCallBack; + + private String transactionListener; + + private String messageQueueSelector; + + private String errorMessageStrategy; + + private String sendFailureChannel; + + private String checkForbiddenHook; + + private String sendMessageHook; + + public int getSendMsgTimeout() { + return sendMsgTimeout; + } + + public void setSendMsgTimeout(int sendMsgTimeout) { + this.sendMsgTimeout = sendMsgTimeout; } - public void setGroup(String group) { - this.group = group; + public int getCompressMsgBodyThreshold() { + return compressMsgBodyThreshold; } - public Boolean getEnabled() { - return enabled; + public void setCompressMsgBodyThreshold(int compressMsgBodyThreshold) { + this.compressMsgBodyThreshold = compressMsgBodyThreshold; } - public void setEnabled(Boolean enabled) { - this.enabled = enabled; + public int getRetryTimesWhenSendFailed() { + return retryTimesWhenSendFailed; } - public Integer getMaxMessageSize() { + public void setRetryTimesWhenSendFailed(int retryTimesWhenSendFailed) { + this.retryTimesWhenSendFailed = retryTimesWhenSendFailed; + } + + public int getRetryTimesWhenSendAsyncFailed() { + return retryTimesWhenSendAsyncFailed; + } + + public void setRetryTimesWhenSendAsyncFailed(int retryTimesWhenSendAsyncFailed) { + this.retryTimesWhenSendAsyncFailed = retryTimesWhenSendAsyncFailed; + } + + public boolean getRetryAnotherBroker() { + return retryAnotherBroker; + } + + public void setRetryAnotherBroker(boolean retryAnotherBroker) { + this.retryAnotherBroker = retryAnotherBroker; + } + + public int getMaxMessageSize() { return maxMessageSize; } - public void setMaxMessageSize(Integer maxMessageSize) { + public void setMaxMessageSize(int maxMessageSize) { this.maxMessageSize = maxMessageSize; } - public Boolean getTransactional() { - return transactional; + public String getProducerType() { + return producerType; } - public void setTransactional(Boolean transactional) { - this.transactional = transactional; + public void setProducerType(String producerType) { + this.producerType = producerType; } - public Boolean getSync() { - return sync; + public String getSendType() { + return sendType; } - public void setSync(Boolean sync) { - this.sync = sync; + public void setSendType(String sendType) { + this.sendType = sendType; } - public Boolean getVipChannelEnabled() { - return vipChannelEnabled; + public String getSendCallBack() { + return sendCallBack; } - public void setVipChannelEnabled(Boolean vipChannelEnabled) { - this.vipChannelEnabled = vipChannelEnabled; + public void setSendCallBack(String sendCallBack) { + this.sendCallBack = sendCallBack; } - public int getSendMessageTimeout() { - return sendMessageTimeout; + public String getTransactionListener() { + return transactionListener; } - public void setSendMessageTimeout(int sendMessageTimeout) { - this.sendMessageTimeout = sendMessageTimeout; + public void setTransactionListener(String transactionListener) { + this.transactionListener = transactionListener; } - public int getCompressMessageBodyThreshold() { - return compressMessageBodyThreshold; + public String getMessageQueueSelector() { + return messageQueueSelector; } - public void setCompressMessageBodyThreshold(int compressMessageBodyThreshold) { - this.compressMessageBodyThreshold = compressMessageBodyThreshold; + public void setMessageQueueSelector(String messageQueueSelector) { + this.messageQueueSelector = messageQueueSelector; } - public int getRetryTimesWhenSendFailed() { - return retryTimesWhenSendFailed; + public String getErrorMessageStrategy() { + return errorMessageStrategy; } - public void setRetryTimesWhenSendFailed(int retryTimesWhenSendFailed) { - this.retryTimesWhenSendFailed = retryTimesWhenSendFailed; + public void setErrorMessageStrategy(String errorMessageStrategy) { + this.errorMessageStrategy = errorMessageStrategy; } - public int getRetryTimesWhenSendAsyncFailed() { - return retryTimesWhenSendAsyncFailed; + public String getSendFailureChannel() { + return sendFailureChannel; } - public void setRetryTimesWhenSendAsyncFailed(int retryTimesWhenSendAsyncFailed) { - this.retryTimesWhenSendAsyncFailed = retryTimesWhenSendAsyncFailed; + public void setSendFailureChannel(String sendFailureChannel) { + this.sendFailureChannel = sendFailureChannel; + } + + public String getCheckForbiddenHook() { + return checkForbiddenHook; } - public boolean isRetryNextServer() { - return retryNextServer; + public void setCheckForbiddenHook(String checkForbiddenHook) { + this.checkForbiddenHook = checkForbiddenHook; } - public void setRetryNextServer(boolean retryNextServer) { - this.retryNextServer = retryNextServer; + public String getSendMessageHook() { + return sendMessageHook; + } + + public void setSendMessageHook(String sendMessageHook) { + this.sendMessageHook = sendMessageHook; + } + + public enum ProducerType { + Normal, Trans; + + public boolean equalsName(String name) { + return this.name().equalsIgnoreCase(name); + } + } + + public enum SendType { + OneWay, Async, Sync,; + + public boolean equalsName(String name) { + return this.name().equalsIgnoreCase(name); + } } } diff --git a/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/provisioning/selector/PartitionMessageQueueSelector.java b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/provisioning/selector/PartitionMessageQueueSelector.java index 694dcdc96..0580fe859 100644 --- a/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/provisioning/selector/PartitionMessageQueueSelector.java +++ b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/provisioning/selector/PartitionMessageQueueSelector.java @@ -36,7 +36,7 @@ public class PartitionMessageQueueSelector implements MessageQueueSelector { @Override public MessageQueue select(List mqs, Message msg, Object arg) { - Integer partition = 0; + int partition = 0; try { partition = Math.abs( Integer.parseInt(msg.getProperty(BinderHeaders.PARTITION_HEADER))); From a6e01c998417669fcd4d4b053db454d37725fe7a Mon Sep 17 00:00:00 2001 From: zkzlx Date: Mon, 1 Feb 2021 11:24:25 +0800 Subject: [PATCH 2/6] Code refactoring and some new feature support --- ...gHandlerMappingsProviderConfiguration.java | 45 +++ .../RocketMQBinderAutoConfiguration.java | 81 +++++ .../rocketmq/contants/RocketMQConst.java | 90 ++++++ .../convert/RocketMQMessageConverter.java | 84 +++++ .../custom/RocketMQBeanContainerCache.java | 75 +++++ .../RocketMQConfigBeanPostProcessor.java | 43 +++ .../extend/ErrorAcknowledgeHandler.java | 35 +++ .../inbound/RocketMQConsumerFactory.java | 156 ++++++++++ .../RocketMQInboundChannelAdapter.java | 228 ++++++++++++++ .../pull/DefaultErrorAcknowledgeHandler.java | 43 +++ .../inbound/pull/RocketMQAckCallback.java | 112 +++++++ .../inbound/pull/RocketMQMessageSource.java | 161 ++++++++++ .../outbound/RocketMQProduceFactory.java | 131 ++++++++ .../RocketMQProducerMessageHandler.java | 286 ++++++++++++++++++ .../properties/RocketMQCommonProperties.java | 201 ++++++++++++ .../RocketMQSpecificPropertiesProvider.java | 66 ++++ .../RocketMQMessageConverterSupport.java | 185 +++++++++++ .../binder/rocketmq/utils/RocketMQUtils.java | 98 ++++++ 18 files changed, 2120 insertions(+) create mode 100644 spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/autoconfigurate/ExtendedBindingHandlerMappingsProviderConfiguration.java create mode 100644 spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/autoconfigurate/RocketMQBinderAutoConfiguration.java create mode 100644 spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/contants/RocketMQConst.java create mode 100644 spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/convert/RocketMQMessageConverter.java create mode 100644 spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/custom/RocketMQBeanContainerCache.java create mode 100644 spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/custom/RocketMQConfigBeanPostProcessor.java create mode 100644 spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/extend/ErrorAcknowledgeHandler.java create mode 100644 spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/integration/inbound/RocketMQConsumerFactory.java create mode 100644 spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/integration/inbound/RocketMQInboundChannelAdapter.java create mode 100644 spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/integration/inbound/pull/DefaultErrorAcknowledgeHandler.java create mode 100644 spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/integration/inbound/pull/RocketMQAckCallback.java create mode 100644 spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/integration/inbound/pull/RocketMQMessageSource.java create mode 100644 spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/integration/outbound/RocketMQProduceFactory.java create mode 100644 spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/integration/outbound/RocketMQProducerMessageHandler.java create mode 100644 spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/properties/RocketMQCommonProperties.java create mode 100644 spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/properties/RocketMQSpecificPropertiesProvider.java create mode 100644 spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/support/RocketMQMessageConverterSupport.java create mode 100644 spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/utils/RocketMQUtils.java diff --git a/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/autoconfigurate/ExtendedBindingHandlerMappingsProviderConfiguration.java b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/autoconfigurate/ExtendedBindingHandlerMappingsProviderConfiguration.java new file mode 100644 index 000000000..eb6e6ce52 --- /dev/null +++ b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/autoconfigurate/ExtendedBindingHandlerMappingsProviderConfiguration.java @@ -0,0 +1,45 @@ +/* + * Copyright 2013-2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.alibaba.cloud.stream.binder.rocketmq.autoconfigurate; + +import java.util.HashMap; +import java.util.Map; + +import org.springframework.boot.context.properties.source.ConfigurationPropertyName; +import org.springframework.cloud.stream.config.BindingHandlerAdvise.MappingsProvider; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class ExtendedBindingHandlerMappingsProviderConfiguration { + + @Bean + public MappingsProvider rocketExtendedPropertiesDefaultMappingsProvider() { + return () -> { + Map mappings = new HashMap<>(); + mappings.put( + ConfigurationPropertyName.of("spring.cloud.stream.rocketmq.bindings"), + ConfigurationPropertyName.of("spring.cloud.stream.rocketmq.default")); + mappings.put( + ConfigurationPropertyName.of("spring.cloud.stream.rocketmq.streams"), + ConfigurationPropertyName + .of("spring.cloud.stream.rocketmq.streams.default")); + return mappings; + }; + } + +} diff --git a/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/autoconfigurate/RocketMQBinderAutoConfiguration.java b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/autoconfigurate/RocketMQBinderAutoConfiguration.java new file mode 100644 index 000000000..abcb9b961 --- /dev/null +++ b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/autoconfigurate/RocketMQBinderAutoConfiguration.java @@ -0,0 +1,81 @@ +/* + * Copyright 2013-2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.alibaba.cloud.stream.binder.rocketmq.autoconfigurate; + +import com.alibaba.cloud.stream.binder.rocketmq.RocketMQMessageChannelBinder; +import com.alibaba.cloud.stream.binder.rocketmq.actuator.RocketMQBinderHealthIndicator; +import com.alibaba.cloud.stream.binder.rocketmq.convert.RocketMQMessageConverter; +import com.alibaba.cloud.stream.binder.rocketmq.custom.RocketMQConfigBeanPostProcessor; +import com.alibaba.cloud.stream.binder.rocketmq.properties.RocketMQBinderConfigurationProperties; +import com.alibaba.cloud.stream.binder.rocketmq.properties.RocketMQExtendedBindingProperties; +import com.alibaba.cloud.stream.binder.rocketmq.provisioning.RocketMQTopicProvisioner; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.actuate.autoconfigure.health.ConditionalOnEnabledHealthIndicator; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.messaging.converter.CompositeMessageConverter; + +/** + * issue:https://github.com/alibaba/spring-cloud-alibaba/issues/1681 + * @author Timur Valiev + * @author Jim + */ +@Configuration(proxyBeanMethods = false) +@EnableConfigurationProperties({ RocketMQExtendedBindingProperties.class, + RocketMQBinderConfigurationProperties.class }) +public class RocketMQBinderAutoConfiguration { + + @Autowired + private RocketMQExtendedBindingProperties extendedBindingProperties; + @Autowired + private RocketMQBinderConfigurationProperties rocketBinderConfigurationProperties; + + @Bean + public RocketMQConfigBeanPostProcessor rocketMQConfigBeanPostProcessor() { + return new RocketMQConfigBeanPostProcessor(); + } + + @Bean(RocketMQMessageConverter.DEFAULT_NAME) + @ConditionalOnMissingBean(name = { RocketMQMessageConverter.DEFAULT_NAME }) + public CompositeMessageConverter rocketMQMessageConverter() { + return new RocketMQMessageConverter().getMessageConverter(); + } + + @Bean + @ConditionalOnEnabledHealthIndicator("rocketmq") + @ConditionalOnClass(name = "org.springframework.boot.actuate.health.HealthIndicator") + public RocketMQBinderHealthIndicator rocketMQBinderHealthIndicator() { + return new RocketMQBinderHealthIndicator(); + } + + @Bean + public RocketMQTopicProvisioner rocketMQTopicProvisioner() { + return new RocketMQTopicProvisioner(); + } + + @Bean + public RocketMQMessageChannelBinder rocketMQMessageChannelBinder( + RocketMQTopicProvisioner provisioningProvider) { + return new RocketMQMessageChannelBinder(rocketBinderConfigurationProperties, + extendedBindingProperties, provisioningProvider); + } + +} diff --git a/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/contants/RocketMQConst.java b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/contants/RocketMQConst.java new file mode 100644 index 000000000..e83a6a172 --- /dev/null +++ b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/contants/RocketMQConst.java @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.alibaba.cloud.stream.binder.rocketmq.contants; + +import org.apache.rocketmq.common.message.MessageConst; + +import static org.apache.rocketmq.spring.support.RocketMQHeaders.PREFIX; + +/** + * @author zkzlx + */ +public class RocketMQConst extends MessageConst { + + /** + * Header key for RocketMQ Transactional Args. + */ + public static final String ROCKET_TRANSACTIONAL_ARG = "TRANSACTIONAL_ARG"; + + /** + * Default NameServer value. + */ + public static final String DEFAULT_NAME_SERVER = "127.0.0.1:9876"; + + /** + * Default group for SCS RocketMQ Binder. + */ + public static final String DEFAULT_GROUP = PREFIX + "binder_default_group_name"; + + /** + * RocketMQ re-consume times. + */ + public static final String ROCKETMQ_RECONSUME_TIMES = PREFIX + "RECONSUME_TIMES"; + + public static final String USER_TRANSACTIONAL_ARGS = "TRANSACTIONAL_ARGS"; + + /** + * It is mainly provided for conversion between rocketMq-message and Spring-message, + * and parameters are passed through HEADERS. + */ + public static class Headers { + public static final String KEYS = MessageConst.PROPERTY_KEYS; + public static final String TAGS = MessageConst.PROPERTY_TAGS; + public static final String TOPIC = "MQ_TOPIC"; + /** + * The ID of the message. + */ + public static final String MESSAGE_ID = "MQ_MESSAGE_ID"; + /** + * The timestamp that the message producer invokes the message sending API. + */ + public static final String BORN_TIMESTAMP = "MQ_BORN_TIMESTAMP"; + /** + * The IP and port number of the message producer + */ + public static final String BORN_HOST = "MQ_BORN_HOST"; + + /** + * Message flag, MQ is not processed and is available for use by applications. + */ + public static final String FLAG = "MQ_FLAG"; + /** + * Message consumption queue ID + */ + public static final String QUEUE_ID = "MQ_QUEUE_ID"; + /** + * Message system Flag, such as whether or not to compress, whether or not to + * transactional messages. + */ + public static final String SYS_FLAG = "MQ_SYS_FLAG"; + /** + * The transaction ID of the transaction message. + */ + public static final String TRANSACTION_ID = "MQ_TRANSACTION_ID"; + } + +} diff --git a/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/convert/RocketMQMessageConverter.java b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/convert/RocketMQMessageConverter.java new file mode 100644 index 000000000..58f17c6ef --- /dev/null +++ b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/convert/RocketMQMessageConverter.java @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.alibaba.cloud.stream.binder.rocketmq.convert; + +import java.util.ArrayList; +import java.util.List; + +import org.springframework.messaging.converter.ByteArrayMessageConverter; +import org.springframework.messaging.converter.CompositeMessageConverter; +import org.springframework.messaging.converter.MappingJackson2MessageConverter; +import org.springframework.messaging.converter.MessageConverter; +import org.springframework.messaging.converter.StringMessageConverter; +import org.springframework.util.ClassUtils; + +/** + * The default message converter of rocketMq,its bean name is {@link #DEFAULT_NAME} + * @author zkzlx + */ +public class RocketMQMessageConverter { + + public static final String DEFAULT_NAME = "rocketMQMessageConverter"; + + private static final boolean JACKSON_PRESENT; + private static final boolean FASTJSON_PRESENT; + + static { + ClassLoader classLoader = RocketMQMessageConverter.class.getClassLoader(); + JACKSON_PRESENT = ClassUtils + .isPresent("com.fasterxml.jackson.databind.ObjectMapper", classLoader) + && ClassUtils.isPresent("com.fasterxml.jackson.core.JsonGenerator", + classLoader); + FASTJSON_PRESENT = ClassUtils.isPresent("com.alibaba.fastjson.JSON", classLoader) + && ClassUtils.isPresent( + "com.alibaba.fastjson.support.config.FastJsonConfig", + classLoader); + } + + private CompositeMessageConverter messageConverter; + + public RocketMQMessageConverter() { + List messageConverters = new ArrayList<>(); + ByteArrayMessageConverter byteArrayMessageConverter = new ByteArrayMessageConverter(); + byteArrayMessageConverter.setContentTypeResolver(null); + messageConverters.add(byteArrayMessageConverter); + messageConverters.add(new StringMessageConverter()); + if (JACKSON_PRESENT) { + messageConverters.add(new MappingJackson2MessageConverter()); + } + if (FASTJSON_PRESENT) { + try { + messageConverters.add((MessageConverter) ClassUtils.forName( + "com.alibaba.fastjson.support.spring.messaging.MappingFastJsonMessageConverter", + ClassUtils.getDefaultClassLoader()).newInstance()); + } + catch (ClassNotFoundException | IllegalAccessException + | InstantiationException ignored) { + // ignore this exception + } + } + messageConverter = new CompositeMessageConverter(messageConverters); + } + + public CompositeMessageConverter getMessageConverter() { + return messageConverter; + } + + public void setMessageConverter(CompositeMessageConverter messageConverter) { + this.messageConverter = messageConverter; + } +} \ No newline at end of file diff --git a/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/custom/RocketMQBeanContainerCache.java b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/custom/RocketMQBeanContainerCache.java new file mode 100644 index 000000000..9afc94821 --- /dev/null +++ b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/custom/RocketMQBeanContainerCache.java @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.alibaba.cloud.stream.binder.rocketmq.custom; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import com.alibaba.cloud.stream.binder.rocketmq.extend.ErrorAcknowledgeHandler; +import org.apache.rocketmq.client.consumer.AllocateMessageQueueStrategy; +import org.apache.rocketmq.client.consumer.listener.MessageListener; +import org.apache.rocketmq.client.hook.CheckForbiddenHook; +import org.apache.rocketmq.client.hook.SendMessageHook; +import org.apache.rocketmq.client.producer.MessageQueueSelector; +import org.apache.rocketmq.client.producer.SendCallback; +import org.apache.rocketmq.client.producer.TransactionListener; + +import org.springframework.messaging.converter.CompositeMessageConverter; +import org.springframework.util.StringUtils; + +/** + * Gets the beans configured in the configuration file + * + * @author junboXiang + */ +public final class RocketMQBeanContainerCache { + + private static final Class[] CLASSES = new Class[] { + CompositeMessageConverter.class, AllocateMessageQueueStrategy.class, + MessageQueueSelector.class, MessageListener.class, TransactionListener.class, + SendCallback.class, CheckForbiddenHook.class, SendMessageHook.class, + ErrorAcknowledgeHandler.class }; + + private static final Map BEANS_CACHE = new ConcurrentHashMap<>(); + + static void putBean(String beanName, Object beanObj) { + BEANS_CACHE.put(beanName, beanObj); + } + + static Class[] getClassAry() { + return CLASSES; + } + + public static T getBean(String beanName, Class clazz) { + return getBean(beanName, clazz, null); + } + + public static T getBean(String beanName, Class clazz, T defaultObj) { + if (StringUtils.isEmpty(beanName)) { + return defaultObj; + } + Object obj = BEANS_CACHE.get(beanName); + if (null == obj) { + return defaultObj; + } + if (clazz.isAssignableFrom(obj.getClass())) { + return (T) obj; + } + return defaultObj; + } + +} diff --git a/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/custom/RocketMQConfigBeanPostProcessor.java b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/custom/RocketMQConfigBeanPostProcessor.java new file mode 100644 index 000000000..30bd64328 --- /dev/null +++ b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/custom/RocketMQConfigBeanPostProcessor.java @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.alibaba.cloud.stream.binder.rocketmq.custom; + +import java.util.stream.Stream; + +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.config.BeanPostProcessor; + +/** + * find RocketMQ bean by annotations + * + * @author junboXiang + * + */ +public class RocketMQConfigBeanPostProcessor implements BeanPostProcessor { + + @Override + public Object postProcessAfterInitialization(Object bean, String beanName) + throws BeansException { + Stream.of(RocketMQBeanContainerCache.getClassAry()).forEach(clazz -> { + if (clazz.isAssignableFrom(bean.getClass())) { + RocketMQBeanContainerCache.putBean(beanName, bean); + } + }); + return bean; + } + +} diff --git a/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/extend/ErrorAcknowledgeHandler.java b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/extend/ErrorAcknowledgeHandler.java new file mode 100644 index 000000000..fcf6de804 --- /dev/null +++ b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/extend/ErrorAcknowledgeHandler.java @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.alibaba.cloud.stream.binder.rocketmq.extend; + +import org.springframework.integration.acks.AcknowledgmentCallback.Status; +import org.springframework.messaging.Message; + +/** + * @author zkzlx + */ +public interface ErrorAcknowledgeHandler { + + /** + * Ack state handling, including receive, reject, and retry, when a consumption + * exception occurs. + * @param message + * @return see {@link Status} + */ + Status handler(Message message); + +} diff --git a/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/integration/inbound/RocketMQConsumerFactory.java b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/integration/inbound/RocketMQConsumerFactory.java new file mode 100644 index 000000000..876249581 --- /dev/null +++ b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/integration/inbound/RocketMQConsumerFactory.java @@ -0,0 +1,156 @@ +/* + * Copyright 2013-2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.alibaba.cloud.stream.binder.rocketmq.integration.inbound; + +import com.alibaba.cloud.stream.binder.rocketmq.custom.RocketMQBeanContainerCache; +import com.alibaba.cloud.stream.binder.rocketmq.properties.RocketMQConsumerProperties; +import com.alibaba.cloud.stream.binder.rocketmq.utils.RocketMQUtils; +import org.apache.rocketmq.acl.common.AclClientRPCHook; +import org.apache.rocketmq.acl.common.SessionCredentials; +import org.apache.rocketmq.client.consumer.AllocateMessageQueueStrategy; +import org.apache.rocketmq.client.consumer.DefaultLitePullConsumer; +import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer; +import org.apache.rocketmq.client.consumer.rebalance.AllocateMessageQueueAveragely; +import org.apache.rocketmq.common.protocol.heartbeat.MessageModel; +import org.apache.rocketmq.remoting.RPCHook; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.springframework.cloud.stream.binder.ExtendedConsumerProperties; +import org.springframework.util.Assert; +import org.springframework.util.StringUtils; + +/** + * Extended function related to producer . eg:initial + * + * @author zkzlx + */ +public final class RocketMQConsumerFactory { + + private final static Logger log = LoggerFactory + .getLogger(RocketMQConsumerFactory.class); + + public static DefaultMQPushConsumer initPushConsumer( + ExtendedConsumerProperties extendedConsumerProperties) { + RocketMQConsumerProperties consumerProperties = extendedConsumerProperties + .getExtension(); + Assert.notNull(consumerProperties.getGroup(), + "Property 'group' is required - consumerGroup"); + Assert.notNull(consumerProperties.getNameServer(), + "Property 'nameServer' is required"); + AllocateMessageQueueStrategy allocateMessageQueueStrategy = RocketMQBeanContainerCache + .getBean(consumerProperties.getAllocateMessageQueueStrategy(), + AllocateMessageQueueStrategy.class, + new AllocateMessageQueueAveragely()); + RPCHook rpcHook = null; + if (!StringUtils.isEmpty(consumerProperties.getAccessKey()) + && !StringUtils.isEmpty(consumerProperties.getSecretKey())) { + rpcHook = new AclClientRPCHook( + new SessionCredentials(consumerProperties.getAccessKey(), + consumerProperties.getSecretKey())); + } + DefaultMQPushConsumer consumer = new DefaultMQPushConsumer( + consumerProperties.getGroup(), rpcHook, allocateMessageQueueStrategy, + consumerProperties.getEnableMsgTrace(), + consumerProperties.getCustomizedTraceTopic()); + consumer.setVipChannelEnabled( + null == rpcHook && consumerProperties.getVipChannelEnabled()); + consumer.setInstanceName( + RocketMQUtils.getInstanceName(rpcHook, consumerProperties.getGroup())); + consumer.setNamespace(consumerProperties.getNamespace()); + consumer.setNamesrvAddr(consumerProperties.getNameServer()); + consumer.setMessageModel(getMessageModel(consumerProperties.getMessageModel())); + consumer.setUseTLS(consumerProperties.getUseTLS()); + consumer.setPullTimeDelayMillsWhenException( + consumerProperties.getPullTimeDelayMillsWhenException()); + consumer.setPullBatchSize(consumerProperties.getPullBatchSize()); + consumer.setConsumeFromWhere(consumerProperties.getConsumeFromWhere()); + consumer.setHeartbeatBrokerInterval( + consumerProperties.getHeartbeatBrokerInterval()); + consumer.setPersistConsumerOffsetInterval( + consumerProperties.getPersistConsumerOffsetInterval()); + consumer.setPullInterval(consumerProperties.getPush().getPullInterval()); + consumer.setConsumeThreadMin(extendedConsumerProperties.getConcurrency()); + consumer.setConsumeThreadMax(extendedConsumerProperties.getConcurrency()); + return consumer; + } + + /** + * todo Compatible with versions less than 4.6 ? + * @return + */ + public static DefaultLitePullConsumer initPullConsumer( + ExtendedConsumerProperties extendedConsumerProperties) { + RocketMQConsumerProperties consumerProperties = extendedConsumerProperties + .getExtension(); + Assert.notNull(consumerProperties.getGroup(), + "Property 'group' is required - consumerGroup"); + Assert.notNull(consumerProperties.getNameServer(), + "Property 'nameServer' is required"); + AllocateMessageQueueStrategy allocateMessageQueueStrategy = RocketMQBeanContainerCache + .getBean(consumerProperties.getAllocateMessageQueueStrategy(), + AllocateMessageQueueStrategy.class, + new AllocateMessageQueueAveragely()); + + RPCHook rpcHook = null; + if (!StringUtils.isEmpty(consumerProperties.getAccessKey()) + && !StringUtils.isEmpty(consumerProperties.getSecretKey())) { + rpcHook = new AclClientRPCHook( + new SessionCredentials(consumerProperties.getAccessKey(), + consumerProperties.getSecretKey())); + } + + DefaultLitePullConsumer consumer = new DefaultLitePullConsumer( + consumerProperties.getNamespace(), consumerProperties.getGroup(), + rpcHook); + consumer.setVipChannelEnabled( + null == rpcHook && consumerProperties.getVipChannelEnabled()); + consumer.setInstanceName( + RocketMQUtils.getInstanceName(rpcHook, consumerProperties.getGroup())); + consumer.setAllocateMessageQueueStrategy(allocateMessageQueueStrategy); + consumer.setNamesrvAddr(consumerProperties.getNameServer()); + consumer.setMessageModel(getMessageModel(consumerProperties.getMessageModel())); + consumer.setUseTLS(consumerProperties.getUseTLS()); + consumer.setPullTimeDelayMillsWhenException( + consumerProperties.getPullTimeDelayMillsWhenException()); + consumer.setConsumerTimeoutMillisWhenSuspend( + consumerProperties.getPull().getConsumerTimeoutMillisWhenSuspend()); + consumer.setPullBatchSize(consumerProperties.getPullBatchSize()); + consumer.setConsumeFromWhere(consumerProperties.getConsumeFromWhere()); + consumer.setHeartbeatBrokerInterval( + consumerProperties.getHeartbeatBrokerInterval()); + consumer.setPersistConsumerOffsetInterval( + consumerProperties.getPersistConsumerOffsetInterval()); + consumer.setPollTimeoutMillis( + consumerProperties.getPull().getPollTimeoutMillis()); + consumer.setPullThreadNums(extendedConsumerProperties.getConcurrency()); + // The internal queues are cached by a maximum of 1000 + consumer.setPullThresholdForAll(extendedConsumerProperties.getExtension() + .getPull().getPullThresholdForAll()); + return consumer; + } + + private static MessageModel getMessageModel(String messageModel) { + for (MessageModel model : MessageModel.values()) { + if (model.getModeCN().equalsIgnoreCase(messageModel)) { + return model; + } + } + return MessageModel.CLUSTERING; + } + +} diff --git a/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/integration/inbound/RocketMQInboundChannelAdapter.java b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/integration/inbound/RocketMQInboundChannelAdapter.java new file mode 100644 index 000000000..d0aec5523 --- /dev/null +++ b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/integration/inbound/RocketMQInboundChannelAdapter.java @@ -0,0 +1,228 @@ +/* + * Copyright 2013-2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.alibaba.cloud.stream.binder.rocketmq.integration.inbound; + +import java.util.List; +import java.util.function.Supplier; + +import com.alibaba.cloud.stream.binder.rocketmq.metrics.Instrumentation; +import com.alibaba.cloud.stream.binder.rocketmq.metrics.InstrumentationManager; +import com.alibaba.cloud.stream.binder.rocketmq.properties.RocketMQConsumerProperties; +import com.alibaba.cloud.stream.binder.rocketmq.support.RocketMQMessageConverterSupport; +import com.alibaba.cloud.stream.binder.rocketmq.utils.RocketMQUtils; +import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer; +import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyStatus; +import org.apache.rocketmq.client.consumer.listener.ConsumeOrderlyStatus; +import org.apache.rocketmq.client.consumer.listener.MessageListenerConcurrently; +import org.apache.rocketmq.client.consumer.listener.MessageListenerOrderly; +import org.apache.rocketmq.common.message.MessageExt; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.springframework.cloud.stream.binder.ExtendedConsumerProperties; +import org.springframework.integration.context.OrderlyShutdownCapable; +import org.springframework.integration.endpoint.MessageProducerSupport; +import org.springframework.integration.support.MessageBuilder; +import org.springframework.messaging.Message; +import org.springframework.messaging.MessagingException; +import org.springframework.retry.RecoveryCallback; +import org.springframework.retry.RetryCallback; +import org.springframework.retry.RetryContext; +import org.springframework.retry.RetryListener; +import org.springframework.retry.support.RetryTemplate; +import org.springframework.util.Assert; +import org.springframework.util.CollectionUtils; + +/** + * TODO Describe what it does + * @author Jim + */ +public class RocketMQInboundChannelAdapter extends MessageProducerSupport + implements OrderlyShutdownCapable { + + private static final Logger log = LoggerFactory + .getLogger(RocketMQInboundChannelAdapter.class); + + private RetryTemplate retryTemplate; + private RecoveryCallback recoveryCallback; + private DefaultMQPushConsumer pushConsumer; + + private final String topic; + private final ExtendedConsumerProperties extendedConsumerProperties; + + public RocketMQInboundChannelAdapter(String topic, + ExtendedConsumerProperties extendedConsumerProperties) { + this.topic = topic; + this.extendedConsumerProperties = extendedConsumerProperties; + } + + @Override + protected void onInit() { + if (extendedConsumerProperties.getExtension() == null + || !extendedConsumerProperties.getExtension().getEnabled()) { + return; + } + Instrumentation instrumentation = new Instrumentation(topic, this); + try { + super.onInit(); + if (this.retryTemplate != null) { + Assert.state(getErrorChannel() == null, + "Cannot have an 'errorChannel' property when a 'RetryTemplate' is " + + "provided; use an 'ErrorMessageSendingRecoverer' in the 'recoveryCallback' property to " + + "send an error message when retries are exhausted"); + this.retryTemplate.registerListener(new RetryListener() { + @Override + public boolean open(RetryContext context, + RetryCallback callback) { + return true; + } + + @Override + public void close(RetryContext context, + RetryCallback callback, Throwable throwable) { + } + + @Override + public void onError(RetryContext context, + RetryCallback callback, Throwable throwable) { + } + }); + } + pushConsumer = RocketMQConsumerFactory + .initPushConsumer(extendedConsumerProperties); + // prepare register consumer message listener,the next step is to be + // compatible with a custom MessageListener. + if (extendedConsumerProperties.getExtension().getPush().getOrderly()) { + pushConsumer.registerMessageListener((MessageListenerOrderly) (msgs, + context) -> RocketMQInboundChannelAdapter.this + .consumeMessage(msgs, () -> { + context.setSuspendCurrentQueueTimeMillis( + extendedConsumerProperties.getExtension() + .getPush() + .getSuspendCurrentQueueTimeMillis()); + return ConsumeOrderlyStatus.SUSPEND_CURRENT_QUEUE_A_MOMENT; + }, () -> ConsumeOrderlyStatus.SUCCESS)); + } + else { + pushConsumer.registerMessageListener((MessageListenerConcurrently) (msgs, + context) -> RocketMQInboundChannelAdapter.this + .consumeMessage(msgs, () -> { + context.setDelayLevelWhenNextConsume( + extendedConsumerProperties.getExtension() + .getPush() + .getDelayLevelWhenNextConsume()); + return ConsumeConcurrentlyStatus.RECONSUME_LATER; + }, () -> ConsumeConcurrentlyStatus.CONSUME_SUCCESS)); + } + instrumentation.markStartedSuccessfully(); + } + catch (Exception e) { + instrumentation.markStartFailed(e); + log.error("DefaultMQPushConsumer init failed, Caused by " + e.getMessage()); + throw new MessagingException(MessageBuilder.withPayload( + "DefaultMQPushConsumer init failed, Caused by " + e.getMessage()) + .build(), e); + } + finally { + InstrumentationManager.addHealthInstrumentation(instrumentation); + } + } + + /** + * The actual execution of a user-defined input consumption service method. + * @param messageExtList rocket mq message list + * @param failSupplier {@link ConsumeConcurrentlyStatus} or + * {@link ConsumeOrderlyStatus} + * @param sucSupplier {@link ConsumeConcurrentlyStatus} or + * {@link ConsumeOrderlyStatus} + * @param + * @return + */ + private R consumeMessage(List messageExtList, + Supplier failSupplier, Supplier sucSupplier) { + if (CollectionUtils.isEmpty(messageExtList)) { + throw new MessagingException( + "DefaultMQPushConsumer consuming failed, Caused by messageExtList is empty"); + } + for (MessageExt messageExt : messageExtList) { + try { + Message message = RocketMQMessageConverterSupport + .convertMessage2Spring(messageExt); + if (this.retryTemplate != null) { + this.retryTemplate.execute(context -> { + this.sendMessage(message); + return message; + }, this.recoveryCallback); + } + else { + this.sendMessage(message); + } + } + catch (Exception e) { + log.warn("consume message failed. messageExt:{}", messageExt, e); + return failSupplier.get(); + } + } + return sucSupplier.get(); + } + + @Override + protected void doStart() { + if (extendedConsumerProperties.getExtension() == null + || !extendedConsumerProperties.getExtension().getEnabled()) { + return; + } + try { + pushConsumer.subscribe(topic, RocketMQUtils.getMessageSelector( + extendedConsumerProperties.getExtension().getSubscription())); + pushConsumer.start(); + } + catch (Exception e) { + log.error("DefaultMQPushConsumer init failed, Caused by " + e.getMessage()); + throw new MessagingException(MessageBuilder.withPayload( + "DefaultMQPushConsumer init failed, Caused by " + e.getMessage()) + .build(), e); + } + } + + @Override + protected void doStop() { + if (pushConsumer != null) { + pushConsumer.shutdown(); + } + } + + public void setRetryTemplate(RetryTemplate retryTemplate) { + this.retryTemplate = retryTemplate; + } + + public void setRecoveryCallback(RecoveryCallback recoveryCallback) { + this.recoveryCallback = recoveryCallback; + } + + @Override + public int beforeShutdown() { + this.stop(); + return 0; + } + + @Override + public int afterShutdown() { + return 0; + } + +} diff --git a/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/integration/inbound/pull/DefaultErrorAcknowledgeHandler.java b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/integration/inbound/pull/DefaultErrorAcknowledgeHandler.java new file mode 100644 index 000000000..3296a128e --- /dev/null +++ b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/integration/inbound/pull/DefaultErrorAcknowledgeHandler.java @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.alibaba.cloud.stream.binder.rocketmq.integration.inbound.pull; + +import com.alibaba.cloud.stream.binder.rocketmq.extend.ErrorAcknowledgeHandler; + +import org.springframework.integration.acks.AcknowledgmentCallback.Status; +import org.springframework.messaging.Message; + +/** + * By default, if consumption fails, the corresponding MessageQueue will always be + * retried, that is, the consumption of other messages in the MessageQueue will be + * blocked. + * + * @author zkzlx + */ +public class DefaultErrorAcknowledgeHandler implements ErrorAcknowledgeHandler { + /** + * Ack state handling, including receive, reject, and retry, when a consumption + * exception occurs. + * + * @param message + * @return see {@link Status} + */ + @Override + public Status handler(Message message) { + return Status.REQUEUE; + } +} diff --git a/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/integration/inbound/pull/RocketMQAckCallback.java b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/integration/inbound/pull/RocketMQAckCallback.java new file mode 100644 index 000000000..f617dd097 --- /dev/null +++ b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/integration/inbound/pull/RocketMQAckCallback.java @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.alibaba.cloud.stream.binder.rocketmq.integration.inbound.pull; + +import org.apache.rocketmq.client.consumer.DefaultLitePullConsumer; +import org.apache.rocketmq.client.exception.MQClientException; +import org.apache.rocketmq.client.impl.consumer.AssignedMessageQueue; +import org.apache.rocketmq.client.impl.consumer.ProcessQueue; +import org.apache.rocketmq.common.message.MessageExt; +import org.apache.rocketmq.common.message.MessageQueue; +import org.apache.rocketmq.common.protocol.heartbeat.MessageModel; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.springframework.integration.acks.AcknowledgmentCallback; +import org.springframework.util.Assert; + +/** + * A pollable {@link org.springframework.integration.core.MessageSource} for RocketMQ. + * @author zkzlx + */ +public class RocketMQAckCallback implements AcknowledgmentCallback { + private final static Logger log = LoggerFactory.getLogger(RocketMQAckCallback.class); + + private boolean acknowledged; + private boolean autoAckEnabled = true; + private MessageExt messageExt; + private AssignedMessageQueue assignedMessageQueue; + private DefaultLitePullConsumer consumer; + private final MessageQueue messageQueue; + + public RocketMQAckCallback(DefaultLitePullConsumer consumer, + AssignedMessageQueue assignedMessageQueue, MessageQueue messageQueue, + MessageExt messageExt) { + this.messageExt = messageExt; + this.consumer = consumer; + this.assignedMessageQueue = assignedMessageQueue; + this.messageQueue = messageQueue; + } + + @Override + public boolean isAcknowledged() { + return this.acknowledged; + } + + @Override + public void noAutoAck() { + this.autoAckEnabled = false; + } + + @Override + public boolean isAutoAck() { + return this.autoAckEnabled; + } + + @Override + public void acknowledge(Status status) { + Assert.notNull(status, "'status' cannot be null"); + if (this.acknowledged) { + throw new IllegalStateException("Already acknowledged"); + } + synchronized (messageQueue) { + try { + long offset = messageExt.getQueueOffset(); + switch (status) { + case REJECT: + case ACCEPT: + long consumerOffset = assignedMessageQueue + .getConsumerOffset(messageQueue); + if (consumerOffset != -1) { + ProcessQueue processQueue = assignedMessageQueue + .getProcessQueue(messageQueue); + if (processQueue != null && !processQueue.isDropped()) { + consumer.getOffsetStore().updateOffset(messageQueue, + consumerOffset, false); + } + } + if (consumer.getMessageModel() == MessageModel.BROADCASTING) { + consumer.getOffsetStore().persist(messageQueue); + } + break; + case REQUEUE: + consumer.seek(messageQueue, offset); + break; + default: + break; + } + } + catch (MQClientException e) { + throw new IllegalStateException(e); + } + finally { + this.acknowledged = true; + } + } + } + +} \ No newline at end of file diff --git a/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/integration/inbound/pull/RocketMQMessageSource.java b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/integration/inbound/pull/RocketMQMessageSource.java new file mode 100644 index 000000000..2ca91384b --- /dev/null +++ b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/integration/inbound/pull/RocketMQMessageSource.java @@ -0,0 +1,161 @@ +/* + * Copyright 2013-2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.alibaba.cloud.stream.binder.rocketmq.integration.inbound.pull; + +import java.lang.reflect.Field; +import java.util.List; + +import com.alibaba.cloud.stream.binder.rocketmq.integration.inbound.RocketMQConsumerFactory; +import com.alibaba.cloud.stream.binder.rocketmq.metrics.Instrumentation; +import com.alibaba.cloud.stream.binder.rocketmq.metrics.InstrumentationManager; +import com.alibaba.cloud.stream.binder.rocketmq.properties.RocketMQConsumerProperties; +import com.alibaba.cloud.stream.binder.rocketmq.support.RocketMQMessageConverterSupport; +import com.alibaba.cloud.stream.binder.rocketmq.utils.RocketMQUtils; +import org.apache.rocketmq.client.consumer.DefaultLitePullConsumer; +import org.apache.rocketmq.client.consumer.MessageSelector; +import org.apache.rocketmq.client.exception.MQClientException; +import org.apache.rocketmq.client.impl.consumer.AssignedMessageQueue; +import org.apache.rocketmq.client.impl.consumer.DefaultLitePullConsumerImpl; +import org.apache.rocketmq.common.message.MessageExt; +import org.apache.rocketmq.common.message.MessageQueue; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.springframework.beans.factory.DisposableBean; +import org.springframework.cloud.stream.binder.ExtendedConsumerProperties; +import org.springframework.context.Lifecycle; +import org.springframework.integration.IntegrationMessageHeaderAccessor; +import org.springframework.integration.endpoint.AbstractMessageSource; +import org.springframework.integration.support.MessageBuilder; +import org.springframework.messaging.Message; +import org.springframework.util.CollectionUtils; +import org.springframework.util.ReflectionUtils; + +/** + * @author Jim + */ +public class RocketMQMessageSource extends AbstractMessageSource + implements DisposableBean, Lifecycle { + + private final static Logger log = LoggerFactory + .getLogger(RocketMQMessageSource.class); + + private DefaultLitePullConsumer consumer; + private AssignedMessageQueue assignedMessageQueue; + private volatile boolean running; + + private final String topic; + private final MessageSelector messageSelector; + private final ExtendedConsumerProperties extendedConsumerProperties; + + public RocketMQMessageSource(String name, + ExtendedConsumerProperties extendedConsumerProperties) { + this.topic = name; + this.messageSelector = RocketMQUtils.getMessageSelector( + extendedConsumerProperties.getExtension().getSubscription()); + this.extendedConsumerProperties = extendedConsumerProperties; + + } + + @Override + public synchronized void start() { + Instrumentation instrumentation = new Instrumentation(topic, this); + try { + if (this.isRunning()) { + throw new IllegalStateException( + "pull consumer already running. " + this.toString()); + } + this.consumer = RocketMQConsumerFactory + .initPullConsumer(extendedConsumerProperties); + // This parameter must be 1, otherwise doReceive cannot be handled singly. + this.consumer.setPullBatchSize(1); + this.consumer.subscribe(topic, messageSelector); + this.consumer.setAutoCommit(false); + this.assignedMessageQueue = acquireAssignedMessageQueue(this.consumer); + this.consumer.start(); + instrumentation.markStartedSuccessfully(); + } + catch (MQClientException e) { + instrumentation.markStartFailed(e); + log.error("DefaultMQPullConsumer startup error: " + e.getMessage(), e); + } + finally { + InstrumentationManager.addHealthInstrumentation(instrumentation); + } + this.running = true; + } + + private AssignedMessageQueue acquireAssignedMessageQueue( + DefaultLitePullConsumer consumer) { + Field field = ReflectionUtils.findField(DefaultLitePullConsumer.class, + "defaultLitePullConsumerImpl"); + assert field != null; + field.setAccessible(true); + DefaultLitePullConsumerImpl defaultLitePullConsumerImpl = (DefaultLitePullConsumerImpl) ReflectionUtils + .getField(field, consumer); + + field = ReflectionUtils.findField(DefaultLitePullConsumerImpl.class, + "assignedMessageQueue"); + assert field != null; + field.setAccessible(true); + return (AssignedMessageQueue) ReflectionUtils.getField(field, + defaultLitePullConsumerImpl); + } + + @Override + public synchronized void stop() { + if (this.isRunning() && null != consumer) { + consumer.unsubscribe(topic); + consumer.shutdown(); + this.running = false; + } + } + + @Override + public synchronized boolean isRunning() { + return running; + } + + @Override + protected synchronized Object doReceive() { + List messageExtList = consumer.poll(); + if (CollectionUtils.isEmpty(messageExtList) || messageExtList.size() > 1) { + return null; + } + MessageExt messageExt = messageExtList.get(0); + MessageQueue messageQueue = null; + for (MessageQueue queue : assignedMessageQueue.getAssignedMessageQueues()) { + if (queue.getQueueId() == messageExt.getQueueId()) { + messageQueue = queue; + break; + } + } + Message message = RocketMQMessageConverterSupport + .convertMessage2Spring(messageExtList.get(0)); + return MessageBuilder.fromMessage(message) + .setHeader(IntegrationMessageHeaderAccessor.ACKNOWLEDGMENT_CALLBACK, + new RocketMQAckCallback(this.consumer, assignedMessageQueue, + messageQueue, messageExt)) + .build(); + } + + @Override + public String getComponentType() { + return "rocketmq:message-source"; + } + +} diff --git a/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/integration/outbound/RocketMQProduceFactory.java b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/integration/outbound/RocketMQProduceFactory.java new file mode 100644 index 000000000..7017ba46e --- /dev/null +++ b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/integration/outbound/RocketMQProduceFactory.java @@ -0,0 +1,131 @@ +/* + * Copyright 2013-2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.alibaba.cloud.stream.binder.rocketmq.integration.outbound; + +import java.lang.reflect.Field; + +import com.alibaba.cloud.stream.binder.rocketmq.custom.RocketMQBeanContainerCache; +import com.alibaba.cloud.stream.binder.rocketmq.properties.RocketMQProducerProperties; +import com.alibaba.cloud.stream.binder.rocketmq.utils.RocketMQUtils; +import org.apache.rocketmq.acl.common.AclClientRPCHook; +import org.apache.rocketmq.acl.common.SessionCredentials; +import org.apache.rocketmq.client.hook.CheckForbiddenHook; +import org.apache.rocketmq.client.hook.SendMessageHook; +import org.apache.rocketmq.client.producer.DefaultMQProducer; +import org.apache.rocketmq.client.producer.TransactionMQProducer; +import org.apache.rocketmq.client.trace.AsyncTraceDispatcher; +import org.apache.rocketmq.client.trace.TraceDispatcher; +import org.apache.rocketmq.client.trace.hook.SendMessageTraceHookImpl; +import org.apache.rocketmq.common.UtilAll; +import org.apache.rocketmq.remoting.RPCHook; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.springframework.util.Assert; +import org.springframework.util.StringUtils; + +/** + * Extended function related to producer . eg:initial + * + * @author zkzlx + */ +public final class RocketMQProduceFactory { + + private final static Logger log = LoggerFactory + .getLogger(RocketMQProduceFactory.class); + + /** + * init for the producer,including convert producer params. + * @return + */ + public static DefaultMQProducer initRocketMQProducer(String topic, + RocketMQProducerProperties producerProperties) { + Assert.notNull(producerProperties.getGroup(), + "Property 'group' is required - producerGroup"); + Assert.notNull(producerProperties.getNameServer(), + "Property 'nameServer' is required"); + + RPCHook rpcHook = null; + if (!StringUtils.isEmpty(producerProperties.getAccessKey()) + && !StringUtils.isEmpty(producerProperties.getSecretKey())) { + rpcHook = new AclClientRPCHook( + new SessionCredentials(producerProperties.getAccessKey(), + producerProperties.getSecretKey())); + } + DefaultMQProducer producer; + if (RocketMQProducerProperties.ProducerType.Trans + .equalsName(producerProperties.getProducerType())) { + producer = new TransactionMQProducer(producerProperties.getNamespace(), + producerProperties.getGroup(), rpcHook); + if (producerProperties.getEnableMsgTrace()) { + try { + AsyncTraceDispatcher dispatcher = new AsyncTraceDispatcher( + producerProperties.getGroup(), TraceDispatcher.Type.PRODUCE, + producerProperties.getCustomizedTraceTopic(), rpcHook); + dispatcher.setHostProducer(producer.getDefaultMQProducerImpl()); + Field field = DefaultMQProducer.class + .getDeclaredField("traceDispatcher"); + field.setAccessible(true); + field.set(producer, dispatcher); + producer.getDefaultMQProducerImpl().registerSendMessageHook( + new SendMessageTraceHookImpl(dispatcher)); + } + catch (Throwable e) { + log.error( + "system mq-trace hook init failed ,maybe can't send msg trace data"); + } + } + } + else { + producer = new DefaultMQProducer(producerProperties.getNamespace(), + producerProperties.getGroup(), rpcHook, + producerProperties.getEnableMsgTrace(), + producerProperties.getCustomizedTraceTopic()); + } + + producer.setVipChannelEnabled( + null == rpcHook && producerProperties.getVipChannelEnabled()); + producer.setInstanceName( + RocketMQUtils.getInstanceName(rpcHook, topic + "|" + UtilAll.getPid())); + producer.setNamesrvAddr(producerProperties.getNameServer()); + producer.setSendMsgTimeout(producerProperties.getSendMsgTimeout()); + producer.setRetryTimesWhenSendFailed( + producerProperties.getRetryTimesWhenSendFailed()); + producer.setRetryTimesWhenSendAsyncFailed( + producerProperties.getRetryTimesWhenSendAsyncFailed()); + producer.setCompressMsgBodyOverHowmuch( + producerProperties.getCompressMsgBodyThreshold()); + producer.setRetryAnotherBrokerWhenNotStoreOK( + producerProperties.getRetryAnotherBroker()); + producer.setMaxMessageSize(producerProperties.getMaxMessageSize()); + producer.setUseTLS(producerProperties.getUseTLS()); + CheckForbiddenHook checkForbiddenHook = RocketMQBeanContainerCache.getBean( + producerProperties.getCheckForbiddenHook(), CheckForbiddenHook.class); + if (null != checkForbiddenHook) { + producer.getDefaultMQProducerImpl() + .registerCheckForbiddenHook(checkForbiddenHook); + } + SendMessageHook sendMessageHook = RocketMQBeanContainerCache + .getBean(producerProperties.getSendMessageHook(), SendMessageHook.class); + if (null != sendMessageHook) { + producer.getDefaultMQProducerImpl().registerSendMessageHook(sendMessageHook); + } + + return producer; + } + +} diff --git a/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/integration/outbound/RocketMQProducerMessageHandler.java b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/integration/outbound/RocketMQProducerMessageHandler.java new file mode 100644 index 000000000..66b58f797 --- /dev/null +++ b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/integration/outbound/RocketMQProducerMessageHandler.java @@ -0,0 +1,286 @@ +/* + * Copyright (C) 2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.alibaba.cloud.stream.binder.rocketmq.integration.outbound; + +import java.util.List; + +import com.alibaba.cloud.stream.binder.rocketmq.contants.RocketMQConst; +import com.alibaba.cloud.stream.binder.rocketmq.custom.RocketMQBeanContainerCache; +import com.alibaba.cloud.stream.binder.rocketmq.metrics.Instrumentation; +import com.alibaba.cloud.stream.binder.rocketmq.metrics.InstrumentationManager; +import com.alibaba.cloud.stream.binder.rocketmq.properties.RocketMQProducerProperties; +import com.alibaba.cloud.stream.binder.rocketmq.provisioning.selector.PartitionMessageQueueSelector; +import com.alibaba.cloud.stream.binder.rocketmq.support.RocketMQMessageConverterSupport; +import org.apache.rocketmq.client.exception.MQBrokerException; +import org.apache.rocketmq.client.exception.MQClientException; +import org.apache.rocketmq.client.producer.DefaultMQProducer; +import org.apache.rocketmq.client.producer.MessageQueueSelector; +import org.apache.rocketmq.client.producer.SendCallback; +import org.apache.rocketmq.client.producer.SendResult; +import org.apache.rocketmq.client.producer.SendStatus; +import org.apache.rocketmq.client.producer.TransactionListener; +import org.apache.rocketmq.client.producer.TransactionMQProducer; +import org.apache.rocketmq.common.message.MessageQueue; +import org.apache.rocketmq.remoting.exception.RemotingException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.springframework.cloud.stream.binder.ExtendedProducerProperties; +import org.springframework.cloud.stream.binding.MessageConverterConfigurer; +import org.springframework.cloud.stream.binding.MessageConverterConfigurer.PartitioningInterceptor; +import org.springframework.cloud.stream.provisioning.ProducerDestination; +import org.springframework.context.Lifecycle; +import org.springframework.integration.handler.AbstractMessageHandler; +import org.springframework.integration.support.ErrorMessageStrategy; +import org.springframework.integration.support.ErrorMessageUtils; +import org.springframework.messaging.Message; +import org.springframework.messaging.MessageChannel; +import org.springframework.messaging.MessagingException; + +/** + * @author Jim + */ +public class RocketMQProducerMessageHandler extends AbstractMessageHandler + implements Lifecycle { + + private final static Logger log = LoggerFactory + .getLogger(RocketMQProducerMessageHandler.class); + + private volatile boolean running = false; + private volatile boolean isTrans = false; + + private ErrorMessageStrategy errorMessageStrategy; + private MessageChannel sendFailureChannel; + private MessageConverterConfigurer.PartitioningInterceptor partitioningInterceptor; + private DefaultMQProducer defaultMQProducer; + private MessageQueueSelector messageQueueSelector; + + private final ProducerDestination destination; + private final ExtendedProducerProperties extendedProducerProperties; + private final RocketMQProducerProperties mqProducerProperties; + + public RocketMQProducerMessageHandler(ProducerDestination destination, + ExtendedProducerProperties extendedProducerProperties, + RocketMQProducerProperties mqProducerProperties) { + this.destination = destination; + this.extendedProducerProperties = extendedProducerProperties; + this.mqProducerProperties = mqProducerProperties; + } + + @Override + protected void onInit() { + if (null == mqProducerProperties || !mqProducerProperties.getEnabled()) { + return; + } + super.onInit(); + this.defaultMQProducer = RocketMQProduceFactory + .initRocketMQProducer(destination.getName(), mqProducerProperties); + this.isTrans = defaultMQProducer instanceof TransactionMQProducer; + // Use the default if the partition is on and no customization is available. + this.messageQueueSelector = RocketMQBeanContainerCache.getBean( + mqProducerProperties.getMessageQueueSelector(), + MessageQueueSelector.class, + extendedProducerProperties.isPartitioned() + ? new PartitionMessageQueueSelector() + : null); + } + + @Override + public void start() { + Instrumentation instrumentation = new Instrumentation(destination.getName(), + this); + try { + defaultMQProducer.start(); + // TransactionMQProducer does not currently support custom + // MessageQueueSelector. + if (!isTrans && extendedProducerProperties.isPartitioned()) { + List messageQueues = defaultMQProducer + .fetchPublishMessageQueues(destination.getName()); + if (extendedProducerProperties.getPartitionCount() != messageQueues + .size()) { + logger.info(String.format( + "The partition count of topic '%s' will change from '%s' to '%s'", + destination.getName(), + extendedProducerProperties.getPartitionCount(), + messageQueues.size())); + extendedProducerProperties.setPartitionCount(messageQueues.size()); + // may be npe! + partitioningInterceptor.setPartitionCount( + extendedProducerProperties.getPartitionCount()); + } + } + running = true; + instrumentation.markStartedSuccessfully(); + } + catch (MQClientException | NullPointerException e) { + instrumentation.markStartFailed(e); + log.error("The defaultMQProducer startup failure !!!", e); + } + finally { + InstrumentationManager.addHealthInstrumentation(instrumentation); + } + } + + @Override + public void stop() { + if (running && null != defaultMQProducer) { + defaultMQProducer.shutdown(); + } + running = false; + } + + @Override + public boolean isRunning() { + return running; + } + + @Override + protected void handleMessageInternal(Message message) { + try { + org.apache.rocketmq.common.message.Message mqMessage = RocketMQMessageConverterSupport + .convertMessage2MQ(destination.getName(), message); + SendResult sendResult; + if (defaultMQProducer instanceof TransactionMQProducer) { + TransactionListener transactionListener = RocketMQBeanContainerCache + .getBean(mqProducerProperties.getTransactionListener(), + TransactionListener.class); + if (transactionListener == null) { + throw new MessagingException( + "TransactionMQProducer must have a TransactionMQProducer !!! "); + } + ((TransactionMQProducer) defaultMQProducer) + .setTransactionListener(transactionListener); + log.info("send transaction message :" + mqMessage); + sendResult = defaultMQProducer.sendMessageInTransaction(mqMessage, + message.getHeaders().get(RocketMQConst.USER_TRANSACTIONAL_ARGS)); + } + else { + log.info("send message :" + mqMessage); + sendResult = this.send(mqMessage, this.messageQueueSelector, + message.getHeaders(), message); + } + if (sendResult == null + || !SendStatus.SEND_OK.equals(sendResult.getSendStatus())) { + log.error("message send fail.SendStatus is not OK "); + this.doFail(message, new MessagingException( + "message send fail.SendStatus is not OK.")); + } + } + catch (Exception e) { + log.error("RocketMQ Message hasn't been sent. Caused by " + e.getMessage(), + e); + this.doFail(message, e); + } + } + + private SendResult send(org.apache.rocketmq.common.message.Message mqMessage, + MessageQueueSelector selector, Object args, Message message) + throws RemotingException, MQClientException, InterruptedException, + MQBrokerException { + SendResult sendResult = new SendResult(); + sendResult.setSendStatus(SendStatus.SEND_OK); + if (RocketMQProducerProperties.SendType.OneWay + .equalsName(mqProducerProperties.getSendType())) { + if (null != selector) { + defaultMQProducer.sendOneway(mqMessage, selector, args); + } + else { + defaultMQProducer.sendOneway(mqMessage); + } + return sendResult; + } + if (RocketMQProducerProperties.SendType.Sync + .equalsName(mqProducerProperties.getSendType())) { + if (null != selector) { + return defaultMQProducer.send(mqMessage, selector, args); + } + return defaultMQProducer.send(mqMessage); + } + if (RocketMQProducerProperties.SendType.Async + .equalsName(mqProducerProperties.getSendType())) { + if (null != selector) { + defaultMQProducer.send(mqMessage, selector, args, + this.getSendCallback(message)); + } + else { + defaultMQProducer.send(mqMessage, this.getSendCallback(message)); + } + return sendResult; + } + throw new MessagingException( + "message hasn't been sent,cause by : the SendType must be in this values[OneWay, Async, Sync]"); + } + + /** + * https://github.com/alibaba/spring-cloud-alibaba/issues/1408 + * @param message + * @return + */ + private SendCallback getSendCallback(Message message) { + SendCallback sendCallback = RocketMQBeanContainerCache + .getBean(mqProducerProperties.getSendCallBack(), SendCallback.class); + if (null == sendCallback) { + sendCallback = new SendCallback() { + @Override + public void onSuccess(SendResult sendResult) { + } + + @Override + public void onException(Throwable e) { + RocketMQProducerMessageHandler.this.doFail(message, e); + } + }; + } + return sendCallback; + } + + private void doFail(Message message, Throwable e) { + if (getSendFailureChannel() != null) { + getSendFailureChannel().send(getErrorMessageStrategy().buildErrorMessage(e, + ErrorMessageUtils.getAttributeAccessor(message, message))); + } + else { + throw new MessagingException(message, e); + } + } + + public MessageChannel getSendFailureChannel() { + return sendFailureChannel; + } + + public void setSendFailureChannel(MessageChannel sendFailureChannel) { + this.sendFailureChannel = sendFailureChannel; + } + + public ErrorMessageStrategy getErrorMessageStrategy() { + return errorMessageStrategy; + } + + public void setErrorMessageStrategy(ErrorMessageStrategy errorMessageStrategy) { + this.errorMessageStrategy = errorMessageStrategy; + } + + public PartitioningInterceptor getPartitioningInterceptor() { + return partitioningInterceptor; + } + + public RocketMQProducerMessageHandler setPartitioningInterceptor( + PartitioningInterceptor partitioningInterceptor) { + this.partitioningInterceptor = partitioningInterceptor; + return this; + } +} diff --git a/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/properties/RocketMQCommonProperties.java b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/properties/RocketMQCommonProperties.java new file mode 100644 index 000000000..00e7d30dd --- /dev/null +++ b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/properties/RocketMQCommonProperties.java @@ -0,0 +1,201 @@ +/* + * Copyright (C) 2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.alibaba.cloud.stream.binder.rocketmq.properties; + +import java.io.Serializable; + +import org.apache.rocketmq.client.AccessChannel; +import org.apache.rocketmq.client.impl.factory.MQClientInstance; +import org.apache.rocketmq.remoting.netty.TlsSystemConfig; + +/** + * @author zkzlx + */ +public class RocketMQCommonProperties implements Serializable { + private static final long serialVersionUID = -6724870154343284715L; + + private boolean enabled = true; + + private String nameServer; + + /** + * The property of "access-key". + */ + private String accessKey; + + /** + * The property of "secret-key". + */ + private String secretKey; + /** + * Consumers of the same role is required to have exactly same subscriptions and + * consumerGroup to correctly achieve load balance. It's required and needs to be + * globally unique. + *

+ * Producer group conceptually aggregates all producer instances of exactly same role, + * which is particularly important when transactional messages are involved. + *

+ *

+ * For non-transactional messages, it does not matter as long as it's unique per + * process. + *

+ *

+ * See here for further + * discussion. + */ + private String group; + + private String namespace; + private String accessChannel = AccessChannel.LOCAL.name(); + /** + * Pulling topic information interval from the named server. + * see{@link MQClientInstance#startScheduledTask()},eg:ScheduledTask + * updateTopicRouteInfoFromNameServer. + */ + private int pollNameServerInterval = 1000 * 30; + /** + * Heartbeat interval in microseconds with message broker. + * see{@link MQClientInstance#startScheduledTask()},eg:ScheduledTask + * sendHeartbeatToAllBroker . + */ + private int heartbeatBrokerInterval = 1000 * 30; + /** + * Offset persistent interval for consumer. + * see{@link MQClientInstance#startScheduledTask()},eg:ScheduledTask + * sendHeartbeatToAllBroker . + */ + private int persistConsumerOffsetInterval = 1000 * 5; + + private boolean vipChannelEnabled = false; + + private boolean useTLS = TlsSystemConfig.tlsEnable; + + private boolean enableMsgTrace = true; + private String customizedTraceTopic; + + public boolean getEnabled() { + return enabled; + } + + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + + public String getNameServer() { + return nameServer; + } + + public void setNameServer(String nameServer) { + this.nameServer = nameServer; + } + + public String getAccessKey() { + return accessKey; + } + + public void setAccessKey(String accessKey) { + this.accessKey = accessKey; + } + + public String getSecretKey() { + return secretKey; + } + + public void setSecretKey(String secretKey) { + this.secretKey = secretKey; + } + + public String getGroup() { + return group; + } + + public void setGroup(String group) { + this.group = group; + } + + public String getNamespace() { + return namespace; + } + + public void setNamespace(String namespace) { + this.namespace = namespace; + } + + public String getAccessChannel() { + return accessChannel; + } + + public void setAccessChannel(String accessChannel) { + this.accessChannel = accessChannel; + } + + public int getPollNameServerInterval() { + return pollNameServerInterval; + } + + public void setPollNameServerInterval(int pollNameServerInterval) { + this.pollNameServerInterval = pollNameServerInterval; + } + + public int getHeartbeatBrokerInterval() { + return heartbeatBrokerInterval; + } + + public void setHeartbeatBrokerInterval(int heartbeatBrokerInterval) { + this.heartbeatBrokerInterval = heartbeatBrokerInterval; + } + + public int getPersistConsumerOffsetInterval() { + return persistConsumerOffsetInterval; + } + + public void setPersistConsumerOffsetInterval(int persistConsumerOffsetInterval) { + this.persistConsumerOffsetInterval = persistConsumerOffsetInterval; + } + + public boolean getVipChannelEnabled() { + return vipChannelEnabled; + } + + public void setVipChannelEnabled(boolean vipChannelEnabled) { + this.vipChannelEnabled = vipChannelEnabled; + } + + public boolean getUseTLS() { + return useTLS; + } + + public void setUseTLS(boolean useTLS) { + this.useTLS = useTLS; + } + + public boolean getEnableMsgTrace() { + return enableMsgTrace; + } + + public void setEnableMsgTrace(boolean enableMsgTrace) { + this.enableMsgTrace = enableMsgTrace; + } + + public String getCustomizedTraceTopic() { + return customizedTraceTopic; + } + + public void setCustomizedTraceTopic(String customizedTraceTopic) { + this.customizedTraceTopic = customizedTraceTopic; + } +} diff --git a/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/properties/RocketMQSpecificPropertiesProvider.java b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/properties/RocketMQSpecificPropertiesProvider.java new file mode 100644 index 000000000..99a1a36fb --- /dev/null +++ b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/properties/RocketMQSpecificPropertiesProvider.java @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.alibaba.cloud.stream.binder.rocketmq.properties; + +import org.springframework.cloud.stream.binder.BinderSpecificPropertiesProvider; + +/** + * Container object for RocketMQ specific extended producer and consumer binding + * properties. + * + * @author Jim + */ +public class RocketMQSpecificPropertiesProvider + implements BinderSpecificPropertiesProvider { + + /** + * Consumer specific binding properties. @see {@link RocketMQConsumerProperties}. + */ + private RocketMQConsumerProperties consumer = new RocketMQConsumerProperties(); + + /** + * Producer specific binding properties. @see {@link RocketMQProducerProperties}. + */ + private RocketMQProducerProperties producer = new RocketMQProducerProperties(); + + /** + * @return {@link RocketMQConsumerProperties} Consumer specific binding + * properties. @see {@link RocketMQConsumerProperties}. + */ + @Override + public RocketMQConsumerProperties getConsumer() { + return this.consumer; + } + + public void setConsumer(RocketMQConsumerProperties consumer) { + this.consumer = consumer; + } + + /** + * @return {@link RocketMQProducerProperties} Producer specific binding + * properties. @see {@link RocketMQProducerProperties}. + */ + @Override + public RocketMQProducerProperties getProducer() { + return this.producer; + } + + public void setProducer(RocketMQProducerProperties producer) { + this.producer = producer; + } + +} diff --git a/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/support/RocketMQMessageConverterSupport.java b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/support/RocketMQMessageConverterSupport.java new file mode 100644 index 000000000..d4b62e5fa --- /dev/null +++ b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/support/RocketMQMessageConverterSupport.java @@ -0,0 +1,185 @@ +/* + * Copyright (C) 2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.alibaba.cloud.stream.binder.rocketmq.support; + +import java.nio.charset.Charset; +import java.util.Map; +import java.util.Objects; + +import com.alibaba.cloud.stream.binder.rocketmq.contants.RocketMQConst; +import com.alibaba.cloud.stream.binder.rocketmq.contants.RocketMQConst.Headers; +import com.alibaba.cloud.stream.binder.rocketmq.convert.RocketMQMessageConverter; +import com.alibaba.cloud.stream.binder.rocketmq.custom.RocketMQBeanContainerCache; +import org.apache.rocketmq.common.message.MessageConst; +import org.apache.rocketmq.common.message.MessageExt; + +import org.springframework.messaging.Message; +import org.springframework.messaging.MessageHeaders; +import org.springframework.messaging.converter.CompositeMessageConverter; +import org.springframework.messaging.support.MessageBuilder; +import org.springframework.util.CollectionUtils; +import org.springframework.util.MimeTypeUtils; +import org.springframework.util.StringUtils; + +/** + * + * @author zkzlx + */ +public class RocketMQMessageConverterSupport { + + private static final CompositeMessageConverter MESSAGE_CONVERTER = RocketMQBeanContainerCache + .getBean(RocketMQMessageConverter.DEFAULT_NAME, + CompositeMessageConverter.class, + new RocketMQMessageConverter().getMessageConverter()); + + public static Message convertMessage2Spring(MessageExt message) { + MessageBuilder messageBuilder = MessageBuilder.withPayload(message.getBody()) + .setHeader(toRocketHeaderKey(Headers.KEYS), message.getKeys()) + .setHeader(toRocketHeaderKey(Headers.TAGS), message.getTags()) + .setHeader(toRocketHeaderKey(Headers.TOPIC), message.getTopic()) + .setHeader(toRocketHeaderKey(Headers.MESSAGE_ID), message.getMsgId()) + .setHeader(toRocketHeaderKey(Headers.BORN_TIMESTAMP), + message.getBornTimestamp()) + .setHeader(toRocketHeaderKey(Headers.BORN_HOST), + message.getBornHostString()) + .setHeader(toRocketHeaderKey(Headers.FLAG), message.getFlag()) + .setHeader(toRocketHeaderKey(Headers.QUEUE_ID), message.getQueueId()) + .setHeader(toRocketHeaderKey(Headers.SYS_FLAG), message.getSysFlag()) + .setHeader(toRocketHeaderKey(Headers.TRANSACTION_ID), + message.getTransactionId()); + addUserProperties(message.getProperties(), messageBuilder); + return messageBuilder.build(); + } + + public static String toRocketHeaderKey(String rawKey) { + return "ROCKET_" + rawKey; + } + + private static void addUserProperties(Map properties, + MessageBuilder messageBuilder) { + if (!CollectionUtils.isEmpty(properties)) { + properties.forEach((key, val) -> { + if (!MessageConst.STRING_HASH_SET.contains(key) + && !MessageHeaders.ID.equals(key) + && !MessageHeaders.TIMESTAMP.equals(key)) { + messageBuilder.setHeader(key, val); + } + }); + } + } + + public static org.apache.rocketmq.common.message.Message convertMessage2MQ( + String destination, Message source) { + Message message = MESSAGE_CONVERTER.toMessage(source.getPayload(), + source.getHeaders()); + assert message != null; + MessageBuilder builder = MessageBuilder.fromMessage(message); + builder.setHeaderIfAbsent(MessageHeaders.CONTENT_TYPE, MimeTypeUtils.TEXT_PLAIN); + message = builder.build(); + return doConvert(destination, message); + } + + private static org.apache.rocketmq.common.message.Message doConvert(String topic, + Message message) { + Charset charset = Charset.defaultCharset(); + Object payloadObj = message.getPayload(); + byte[] payloads; + try { + if (payloadObj instanceof String) { + payloads = ((String) payloadObj).getBytes(charset); + } + else if (payloadObj instanceof byte[]) { + payloads = (byte[]) message.getPayload(); + } + else { + String jsonObj = (String) MESSAGE_CONVERTER.fromMessage(message, + payloadObj.getClass()); + if (null == jsonObj) { + throw new RuntimeException(String.format( + "empty after conversion [messageConverter:%s,payloadClass:%s,payloadObj:%s]", + MESSAGE_CONVERTER.getClass(), payloadObj.getClass(), + payloadObj)); + } + payloads = jsonObj.getBytes(charset); + } + } + catch (Exception e) { + throw new RuntimeException("convert to RocketMQ message failed.", e); + } + return getAndWrapMessage(topic, message.getHeaders(), payloads); + } + + private static org.apache.rocketmq.common.message.Message getAndWrapMessage( + String topic, MessageHeaders headers, byte[] payloads) { + if (topic == null || topic.length() < 1) { + return null; + } + if (payloads == null || payloads.length < 1) { + return null; + } + org.apache.rocketmq.common.message.Message rocketMsg = new org.apache.rocketmq.common.message.Message( + topic, payloads); + if (Objects.nonNull(headers) && !headers.isEmpty()) { + Object tag = headers.getOrDefault(Headers.TAGS, + headers.get(toRocketHeaderKey(Headers.TAGS))); + if (!StringUtils.isEmpty(tag)) { + rocketMsg.setTags(String.valueOf(tag)); + } + + Object keys = headers.getOrDefault(Headers.KEYS, + headers.get(toRocketHeaderKey(Headers.KEYS))); + if (!StringUtils.isEmpty(keys)) { + rocketMsg.setKeys(keys.toString()); + } + Object flagObj = headers.getOrDefault(Headers.FLAG, + headers.get(toRocketHeaderKey(Headers.FLAG))); + int flag = 0; + int delayLevel = 0; + try { + flagObj = flagObj == null ? 0 : flagObj; + Object delayLevelObj = headers.getOrDefault( + RocketMQConst.PROPERTY_DELAY_TIME_LEVEL, + headers.get(toRocketHeaderKey( + RocketMQConst.PROPERTY_DELAY_TIME_LEVEL))); + delayLevelObj = delayLevelObj == null ? 0 : delayLevelObj; + delayLevel = Integer.parseInt(String.valueOf(delayLevelObj)); + flag = Integer.parseInt(String.valueOf(flagObj)); + } + catch (Exception ignored) { + } + if (delayLevel > 0) { + rocketMsg.setDelayTimeLevel(delayLevel); + } + rocketMsg.setFlag(flag); + Object waitStoreMsgOkObj = headers + .getOrDefault(RocketMQConst.PROPERTY_WAIT_STORE_MSG_OK, "true"); + rocketMsg.setWaitStoreMsgOK( + Boolean.parseBoolean(String.valueOf(waitStoreMsgOkObj))); + headers.entrySet().stream() + .filter(entry -> !Objects.equals(entry.getKey(), Headers.FLAG)) + .forEach(entry -> { + if (!MessageConst.STRING_HASH_SET.contains(entry.getKey())) { + rocketMsg.putUserProperty(entry.getKey(), + String.valueOf(entry.getValue())); + } + }); + + } + return rocketMsg; + } + +} diff --git a/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/utils/RocketMQUtils.java b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/utils/RocketMQUtils.java new file mode 100644 index 000000000..3f7898422 --- /dev/null +++ b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/utils/RocketMQUtils.java @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.alibaba.cloud.stream.binder.rocketmq.utils; + +import com.alibaba.cloud.stream.binder.rocketmq.properties.RocketMQBinderConfigurationProperties; +import com.alibaba.cloud.stream.binder.rocketmq.properties.RocketMQCommonProperties; +import org.apache.rocketmq.acl.common.AclClientRPCHook; +import org.apache.rocketmq.acl.common.SessionCredentials; +import org.apache.rocketmq.client.consumer.MessageSelector; +import org.apache.rocketmq.common.UtilAll; +import org.apache.rocketmq.remoting.RPCHook; + +import org.springframework.util.StringUtils; + +/** + * TODO Describe what it does + * + * @author Jim + */ +public class RocketMQUtils { + + public static T mergeRocketMQProperties( + RocketMQBinderConfigurationProperties binderConfigurationProperties, + T mqProperties) { + if (null == binderConfigurationProperties || mqProperties == null) { + return mqProperties; + } + if (StringUtils.isEmpty(mqProperties.getNameServer())) { + mqProperties.setNameServer(binderConfigurationProperties.getNameServer()); + } + if (StringUtils.isEmpty(mqProperties.getSecretKey())) { + mqProperties.setSecretKey(binderConfigurationProperties.getSecretKey()); + } + if (StringUtils.isEmpty(mqProperties.getAccessKey())) { + mqProperties.setAccessKey(binderConfigurationProperties.getAccessKey()); + } + if (StringUtils.isEmpty(mqProperties.getAccessChannel())) { + mqProperties + .setAccessChannel(binderConfigurationProperties.getAccessChannel()); + } + if (StringUtils.isEmpty(mqProperties.getNamespace())) { + mqProperties.setNamespace(binderConfigurationProperties.getNamespace()); + } + if (StringUtils.isEmpty(mqProperties.getGroup())) { + mqProperties.setGroup(binderConfigurationProperties.getGroup()); + } + if (StringUtils.isEmpty(mqProperties.getCustomizedTraceTopic())) { + mqProperties.setCustomizedTraceTopic( + binderConfigurationProperties.getCustomizedTraceTopic()); + } + mqProperties.setNameServer(getNameServerStr(mqProperties.getNameServer())); + return mqProperties; + } + + public static String getInstanceName(RPCHook rpcHook, String identify) { + String separator = "|"; + StringBuilder instanceName = new StringBuilder(); + if (null != rpcHook) { + SessionCredentials sessionCredentials = ((AclClientRPCHook) rpcHook) + .getSessionCredentials(); + instanceName.append(sessionCredentials.getAccessKey()).append(separator) + .append(sessionCredentials.getSecretKey()).append(separator); + } + instanceName.append(identify).append(separator).append(UtilAll.getPid()); + return instanceName.toString(); + } + + public static String getNameServerStr(String nameServer) { + if (StringUtils.isEmpty(nameServer)) { + return null; + } + return nameServer.replaceAll(",", ";"); + } + + private static final String SQL = "sql:"; + + public static MessageSelector getMessageSelector(String expression) { + if (StringUtils.hasText(expression) && expression.startsWith(SQL)) { + return MessageSelector.bySql(expression.replaceFirst(SQL, "")); + } + return MessageSelector.byTag(expression); + } + +} From 5a763e0ec987041ae85702bfe36494bbc45f1ecf Mon Sep 17 00:00:00 2001 From: zkzlx Date: Mon, 1 Feb 2021 11:29:37 +0800 Subject: [PATCH 3/6] Code refactoring and some new feature support - delete some invalid files. --- .../rocketmq/RocketMQBinderConstants.java | 51 --------- .../RocketMQBinderAutoConfiguration.java | 81 -------------- ...inderHealthIndicatorAutoConfiguration.java | 40 ------- ...etMQComponent4BinderAutoConfiguration.java | 102 ------------------ .../main/resources/META-INF/spring.binders | 2 +- .../main/resources/META-INF/spring.factories | 2 +- 6 files changed, 2 insertions(+), 276 deletions(-) delete mode 100644 spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/RocketMQBinderConstants.java delete mode 100644 spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/config/RocketMQBinderAutoConfiguration.java delete mode 100644 spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/config/RocketMQBinderHealthIndicatorAutoConfiguration.java delete mode 100644 spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/config/RocketMQComponent4BinderAutoConfiguration.java diff --git a/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/RocketMQBinderConstants.java b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/RocketMQBinderConstants.java deleted file mode 100644 index 47e4b9e7f..000000000 --- a/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/RocketMQBinderConstants.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2013-2018 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.alibaba.cloud.stream.binder.rocketmq; - -import static org.apache.rocketmq.spring.support.RocketMQHeaders.PREFIX; - -/** - * @author Jim - * @author Xiejiashuai - */ -public final class RocketMQBinderConstants { - - /** - * Header key for RocketMQ Transactional Args. - */ - public static final String ROCKET_TRANSACTIONAL_ARG = "TRANSACTIONAL_ARG"; - - /** - * Default NameServer value. - */ - public static final String DEFAULT_NAME_SERVER = "127.0.0.1:9876"; - - /** - * Default group for SCS RocketMQ Binder. - */ - public static final String DEFAULT_GROUP = PREFIX + "binder_default_group_name"; - - /** - * RocketMQ re-consume times. - */ - public static final String ROCKETMQ_RECONSUME_TIMES = PREFIX + "RECONSUME_TIMES"; - - private RocketMQBinderConstants() { - throw new AssertionError("Must not instantiate constant utility class"); - } - -} diff --git a/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/config/RocketMQBinderAutoConfiguration.java b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/config/RocketMQBinderAutoConfiguration.java deleted file mode 100644 index 3031c2656..000000000 --- a/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/config/RocketMQBinderAutoConfiguration.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright 2013-2018 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.alibaba.cloud.stream.binder.rocketmq.config; - -import com.alibaba.cloud.stream.binder.rocketmq.RocketMQMessageChannelBinder; -import com.alibaba.cloud.stream.binder.rocketmq.metrics.InstrumentationManager; -import com.alibaba.cloud.stream.binder.rocketmq.properties.RocketMQBinderConfigurationProperties; -import com.alibaba.cloud.stream.binder.rocketmq.properties.RocketMQExtendedBindingProperties; -import com.alibaba.cloud.stream.binder.rocketmq.provisioning.RocketMQTopicProvisioner; -import org.apache.rocketmq.spring.autoconfigure.RocketMQAutoConfiguration; -import org.apache.rocketmq.spring.autoconfigure.RocketMQProperties; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.context.properties.EnableConfigurationProperties; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Import; - -/** - * @author Timur Valiev - * @author Jim - */ -@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(); - } - -} diff --git a/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/config/RocketMQBinderHealthIndicatorAutoConfiguration.java b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/config/RocketMQBinderHealthIndicatorAutoConfiguration.java deleted file mode 100644 index 1c3b5dc0d..000000000 --- a/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/config/RocketMQBinderHealthIndicatorAutoConfiguration.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2013-2018 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.alibaba.cloud.stream.binder.rocketmq.config; - -import com.alibaba.cloud.stream.binder.rocketmq.actuator.RocketMQBinderHealthIndicator; - -import org.springframework.boot.actuate.autoconfigure.health.ConditionalOnEnabledHealthIndicator; -import org.springframework.boot.actuate.endpoint.annotation.Endpoint; -import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -/** - * @author Jim - */ -@Configuration(proxyBeanMethods = false) -@ConditionalOnClass(Endpoint.class) -public class RocketMQBinderHealthIndicatorAutoConfiguration { - - @Bean - @ConditionalOnEnabledHealthIndicator("rocketmq") - public RocketMQBinderHealthIndicator rocketBinderHealthIndicator() { - return new RocketMQBinderHealthIndicator(); - } - -} diff --git a/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/config/RocketMQComponent4BinderAutoConfiguration.java b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/config/RocketMQComponent4BinderAutoConfiguration.java deleted file mode 100644 index 6968ead86..000000000 --- a/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/config/RocketMQComponent4BinderAutoConfiguration.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright 2013-2018 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.alibaba.cloud.stream.binder.rocketmq.config; - -import com.alibaba.cloud.stream.binder.rocketmq.RocketMQBinderConstants; -import com.fasterxml.jackson.databind.ObjectMapper; -import org.apache.rocketmq.acl.common.AclClientRPCHook; -import org.apache.rocketmq.acl.common.SessionCredentials; -import org.apache.rocketmq.client.producer.DefaultMQProducer; -import org.apache.rocketmq.spring.autoconfigure.RocketMQAutoConfiguration; -import org.apache.rocketmq.spring.config.RocketMQConfigUtils; -import org.apache.rocketmq.spring.config.RocketMQTransactionAnnotationProcessor; -import org.apache.rocketmq.spring.config.TransactionHandlerRegistry; -import org.apache.rocketmq.spring.core.RocketMQTemplate; - -import org.springframework.boot.autoconfigure.AutoConfigureAfter; -import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; -import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.core.env.Environment; -import org.springframework.util.StringUtils; - -/** - * @author Jim - */ -@Configuration(proxyBeanMethods = false) -@AutoConfigureAfter(RocketMQAutoConfiguration.class) -@ConditionalOnMissingBean(DefaultMQProducer.class) -public class RocketMQComponent4BinderAutoConfiguration { - - private final Environment environment; - - public RocketMQComponent4BinderAutoConfiguration(Environment environment) { - this.environment = environment; - } - - @Bean - @ConditionalOnMissingBean(DefaultMQProducer.class) - public DefaultMQProducer defaultMQProducer() { - DefaultMQProducer producer; - String configNameServer = environment.resolveRequiredPlaceholders( - "${spring.cloud.stream.rocketmq.binder.name-server:${rocketmq.producer.name-server:}}"); - String ak = environment.resolveRequiredPlaceholders( - "${spring.cloud.stream.rocketmq.binder.access-key:${rocketmq.producer.access-key:}}"); - String sk = environment.resolveRequiredPlaceholders( - "${spring.cloud.stream.rocketmq.binder.secret-key:${rocketmq.producer.secret-key:}}"); - if (!StringUtils.isEmpty(ak) && !StringUtils.isEmpty(sk)) { - producer = new DefaultMQProducer(RocketMQBinderConstants.DEFAULT_GROUP, - new AclClientRPCHook(new SessionCredentials(ak, sk))); - producer.setVipChannelEnabled(false); - } - else { - producer = new DefaultMQProducer(RocketMQBinderConstants.DEFAULT_GROUP); - } - if (StringUtils.isEmpty(configNameServer)) { - configNameServer = RocketMQBinderConstants.DEFAULT_NAME_SERVER; - } - producer.setNamesrvAddr(configNameServer); - return producer; - } - - @Bean(destroyMethod = "destroy") - @ConditionalOnMissingBean - public RocketMQTemplate rocketMQTemplate(DefaultMQProducer mqProducer, - ObjectMapper objectMapper) { - RocketMQTemplate rocketMQTemplate = new RocketMQTemplate(); - rocketMQTemplate.setProducer(mqProducer); - rocketMQTemplate.setObjectMapper(objectMapper); - return rocketMQTemplate; - } - - @Bean - @ConditionalOnBean(RocketMQTemplate.class) - @ConditionalOnMissingBean(TransactionHandlerRegistry.class) - public TransactionHandlerRegistry transactionHandlerRegistry( - RocketMQTemplate template) { - return new TransactionHandlerRegistry(template); - } - - @Bean(name = RocketMQConfigUtils.ROCKETMQ_TRANSACTION_ANNOTATION_PROCESSOR_BEAN_NAME) - @ConditionalOnBean(TransactionHandlerRegistry.class) - public static RocketMQTransactionAnnotationProcessor transactionAnnotationProcessor( - TransactionHandlerRegistry transactionHandlerRegistry) { - return new RocketMQTransactionAnnotationProcessor(transactionHandlerRegistry); - } - -} diff --git a/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/resources/META-INF/spring.binders b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/resources/META-INF/spring.binders index 2e5b99538..b232e1f10 100644 --- a/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/resources/META-INF/spring.binders +++ b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/resources/META-INF/spring.binders @@ -1 +1 @@ -rocketmq:com.alibaba.cloud.stream.binder.rocketmq.config.RocketMQBinderAutoConfiguration \ No newline at end of file +rocketmq:com.alibaba.cloud.stream.binder.rocketmq.autoconfigurate.RocketMQBinderAutoConfiguration \ No newline at end of file diff --git a/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/resources/META-INF/spring.factories b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/resources/META-INF/spring.factories index 82d344e00..e18651dc4 100644 --- a/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/resources/META-INF/spring.factories +++ b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/resources/META-INF/spring.factories @@ -1,2 +1,2 @@ org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ -com.alibaba.cloud.stream.binder.rocketmq.config.RocketMQComponent4BinderAutoConfiguration +com.alibaba.cloud.stream.binder.rocketmq.autoconfigurate.ExtendedBindingHandlerMappingsProviderConfiguration From c1c559717154a92d87739450ea85e3186fea4029 Mon Sep 17 00:00:00 2001 From: zkzlx Date: Mon, 1 Feb 2021 13:46:28 +0800 Subject: [PATCH 4/6] Code refactoring and some new feature support - delete some invalid files. --- .../RocketMQListenerBindingContainer.java | 470 ------------------ .../RocketMQMessageQueueChooser.java | 62 --- 2 files changed, 532 deletions(-) delete mode 100644 spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/consuming/RocketMQListenerBindingContainer.java delete mode 100644 spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/consuming/RocketMQMessageQueueChooser.java diff --git a/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/consuming/RocketMQListenerBindingContainer.java b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/consuming/RocketMQListenerBindingContainer.java deleted file mode 100644 index 7bd875f33..000000000 --- a/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/consuming/RocketMQListenerBindingContainer.java +++ /dev/null @@ -1,470 +0,0 @@ -/// * -// * Copyright 2013-2018 the original author or authors. -// * -// * Licensed under the Apache License, Version 2.0 (the "License"); -// * you may not use this file except in compliance with the License. -// * You may obtain a copy of the License at -// * -// * https://www.apache.org/licenses/LICENSE-2.0 -// * -// * Unless required by applicable law or agreed to in writing, software -// * distributed under the License is distributed on an "AS IS" BASIS, -// * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// * See the License for the specific language governing permissions and -// * limitations under the License. -// */ -// -// package com.alibaba.cloud.stream.binder.rocketmq.consuming; -// -// import java.util.List; -// import java.util.Objects; -// -// import com.alibaba.cloud.stream.binder.rocketmq.RocketMQBinderUtils; -// import com.alibaba.cloud.stream.binder.rocketmq.RocketMQMessageChannelBinder; -// import -/// com.alibaba.cloud.stream.binder.rocketmq.properties.RocketMQBinderConfigurationProperties; -// import com.alibaba.cloud.stream.binder.rocketmq.properties.RocketMQConsumerProperties; -// import com.alibaba.cloud.stream.binder.rocketmq.support.RocketMQHeaderMapper; -// import org.apache.rocketmq.acl.common.AclClientRPCHook; -// import org.apache.rocketmq.acl.common.SessionCredentials; -// import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer; -// import org.apache.rocketmq.client.consumer.MessageSelector; -// import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyContext; -// import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyStatus; -// import org.apache.rocketmq.client.consumer.listener.ConsumeOrderlyContext; -// import org.apache.rocketmq.client.consumer.listener.ConsumeOrderlyStatus; -// import org.apache.rocketmq.client.consumer.listener.MessageListenerConcurrently; -// import org.apache.rocketmq.client.consumer.listener.MessageListenerOrderly; -// import org.apache.rocketmq.client.consumer.rebalance.AllocateMessageQueueAveragely; -// import org.apache.rocketmq.client.exception.MQClientException; -// import org.apache.rocketmq.common.UtilAll; -// import org.apache.rocketmq.common.message.MessageExt; -// import org.apache.rocketmq.remoting.RPCHook; -// import org.apache.rocketmq.spring.annotation.ConsumeMode; -// import org.apache.rocketmq.spring.annotation.MessageModel; -// import org.apache.rocketmq.spring.annotation.SelectorType; -// import org.apache.rocketmq.spring.core.RocketMQListener; -// import org.apache.rocketmq.spring.core.RocketMQPushConsumerLifecycleListener; -// import org.apache.rocketmq.spring.support.RocketMQListenerContainer; -// import org.apache.rocketmq.spring.support.RocketMQUtil; -// import org.slf4j.Logger; -// import org.slf4j.LoggerFactory; -// -// import org.springframework.beans.factory.InitializingBean; -// import org.springframework.cloud.stream.binder.ExtendedConsumerProperties; -// import org.springframework.context.SmartLifecycle; -// import org.springframework.integration.support.MessageBuilder; -// import org.springframework.messaging.Message; -// import org.springframework.util.Assert; -// import org.springframework.util.StringUtils; -// -// import static -/// com.alibaba.cloud.stream.binder.rocketmq.RocketMQBinderConstants.ROCKETMQ_RECONSUME_TIMES; -// -/// ** -// * A class that Listen on rocketmq message. -// *

-// * this class will delegate {@link RocketMQListener} to handle message -// * -// * @author Jim -// * @author Xiejiashuai -// * @see RocketMQListener -// */ -// public class RocketMQListenerBindingContainer -// implements InitializingBean, RocketMQListenerContainer, SmartLifecycle { -// -// private final static Logger log = LoggerFactory -// .getLogger(RocketMQListenerBindingContainer.class); -// -// private long suspendCurrentQueueTimeMillis = 1000; -// -// /** -// * Message consume retry strategy
-// * -1,no retry,put into DLQ directly
-// * 0,broker control retry frequency
-// * >0,client control retry frequency. -// */ -// private int delayLevelWhenNextConsume = 0; -// -// private List nameServer; -// -// private String consumerGroup; -// -// private String topic; -// -// private int consumeThreadMax = 64; -// -// private String charset = "UTF-8"; -// -// private RocketMQListener rocketMQListener; -// -// private RocketMQHeaderMapper headerMapper; -// -// private DefaultMQPushConsumer consumer; -// -// private boolean running; -// -// private final ExtendedConsumerProperties -/// rocketMQConsumerProperties; -// -// private final RocketMQMessageChannelBinder rocketMQMessageChannelBinder; -// -// private final RocketMQBinderConfigurationProperties -/// rocketBinderConfigurationProperties; -// -// // The following properties came from RocketMQConsumerProperties. -// private ConsumeMode consumeMode; -// -// private SelectorType selectorType; -// -// private String selectorExpression; -// -// private MessageModel messageModel; -// -// public RocketMQListenerBindingContainer( -// ExtendedConsumerProperties rocketMQConsumerProperties, -// RocketMQBinderConfigurationProperties rocketBinderConfigurationProperties, -// RocketMQMessageChannelBinder rocketMQMessageChannelBinder) { -// this.rocketMQConsumerProperties = rocketMQConsumerProperties; -// this.rocketBinderConfigurationProperties = rocketBinderConfigurationProperties; -// this.rocketMQMessageChannelBinder = rocketMQMessageChannelBinder; -// this.consumeMode = rocketMQConsumerProperties.getExtension().getOrderly() -// ? ConsumeMode.ORDERLY : ConsumeMode.CONCURRENTLY; -// if (StringUtils.isEmpty(rocketMQConsumerProperties.getExtension().getSql())) { -// this.selectorType = SelectorType.TAG; -// this.selectorExpression = rocketMQConsumerProperties.getExtension().getTags(); -// } -// else { -// this.selectorType = SelectorType.SQL92; -// this.selectorExpression = rocketMQConsumerProperties.getExtension().getSql(); -// } -// this.messageModel = rocketMQConsumerProperties.getExtension().getBroadcasting() -// ? MessageModel.BROADCASTING : MessageModel.CLUSTERING; -// } -// -// @Override -// public void setupMessageListener(RocketMQListener rocketMQListener) { -// this.rocketMQListener = rocketMQListener; -// } -// -// @Override -// public void destroy() throws Exception { -// this.setRunning(false); -// if (Objects.nonNull(consumer)) { -// consumer.shutdown(); -// } -// log.info("container destroyed, {}", this.toString()); -// } -// -// @Override -// public void afterPropertiesSet() throws Exception { -// initRocketMQPushConsumer(); -// } -// -// @Override -// public boolean isAutoStartup() { -// return true; -// } -// -// @Override -// public void stop(Runnable callback) { -// stop(); -// callback.run(); -// } -// -// @Override -// public void start() { -// if (this.isRunning()) { -// throw new IllegalStateException( -// "container already running. " + this.toString()); -// } -// -// try { -// consumer.start(); -// } -// catch (MQClientException e) { -// throw new IllegalStateException("Failed to start RocketMQ push consumer", e); -// } -// this.setRunning(true); -// -// log.info("running container: {}", this.toString()); -// } -// -// @Override -// public void stop() { -// if (this.isRunning()) { -// if (Objects.nonNull(consumer)) { -// consumer.shutdown(); -// } -// setRunning(false); -// } -// } -// -// @Override -// public boolean isRunning() { -// return running; -// } -// -// private void setRunning(boolean running) { -// this.running = running; -// } -// -// @Override -// public int getPhase() { -// return Integer.MAX_VALUE; -// } -// -// private void initRocketMQPushConsumer() throws MQClientException { -// Assert.notNull(rocketMQListener, "Property 'rocketMQListener' is required"); -// Assert.notNull(consumerGroup, "Property 'consumerGroup' is required"); -// Assert.notNull(nameServer, "Property 'nameServer' is required"); -// Assert.notNull(topic, "Property 'topic' is required"); -// -// String ak = rocketBinderConfigurationProperties.getAccessKey(); -// String sk = rocketBinderConfigurationProperties.getSecretKey(); -// if (!StringUtils.isEmpty(ak) && !StringUtils.isEmpty(sk)) { -// RPCHook rpcHook = new AclClientRPCHook(new SessionCredentials(ak, sk)); -// consumer = new DefaultMQPushConsumer(consumerGroup, rpcHook, -// new AllocateMessageQueueAveragely(), -// rocketBinderConfigurationProperties.isEnableMsgTrace(), -// rocketBinderConfigurationProperties.getCustomizedTraceTopic()); -// consumer.setInstanceName(RocketMQUtil.getInstanceName(rpcHook, -// topic + "|" + UtilAll.getPid())); -// consumer.setVipChannelEnabled(false); -// } -// else { -// consumer = new DefaultMQPushConsumer(consumerGroup, -// rocketBinderConfigurationProperties.isEnableMsgTrace(), -// rocketBinderConfigurationProperties.getCustomizedTraceTopic()); -// } -// -// consumer.setNamesrvAddr(RocketMQBinderUtils.getNameServerStr(nameServer)); -// consumer.setConsumeThreadMax(rocketMQConsumerProperties.getConcurrency()); -// consumer.setConsumeThreadMin(rocketMQConsumerProperties.getConcurrency()); -// -// switch (messageModel) { -// case BROADCASTING: -// consumer.setMessageModel( -// org.apache.rocketmq.common.protocol.heartbeat.MessageModel.BROADCASTING); -// break; -// case CLUSTERING: -// consumer.setMessageModel( -// org.apache.rocketmq.common.protocol.heartbeat.MessageModel.CLUSTERING); -// break; -// default: -// throw new IllegalArgumentException("Property 'messageModel' was wrong."); -// } -// -// switch (selectorType) { -// case TAG: -// consumer.subscribe(topic, selectorExpression); -// break; -// case SQL92: -// consumer.subscribe(topic, MessageSelector.bySql(selectorExpression)); -// break; -// default: -// throw new IllegalArgumentException("Property 'selectorType' was wrong."); -// } -// -// switch (consumeMode) { -// case ORDERLY: -// consumer.setMessageListener(new DefaultMessageListenerOrderly()); -// break; -// case CONCURRENTLY: -// consumer.setMessageListener(new DefaultMessageListenerConcurrently()); -// break; -// default: -// throw new IllegalArgumentException("Property 'consumeMode' was wrong."); -// } -// -// if (rocketMQListener instanceof RocketMQPushConsumerLifecycleListener) { -// ((RocketMQPushConsumerLifecycleListener) rocketMQListener) -// .prepareStart(consumer); -// } -// -// } -// -// @Override -// public String toString() { -// return "RocketMQListenerBindingContainer{" + "consumerGroup='" + consumerGroup -// + '\'' + ", nameServer='" + nameServer + '\'' + ", topic='" + topic + '\'' -// + ", consumeMode=" + consumeMode + ", selectorType=" + selectorType -// + ", selectorExpression='" + selectorExpression + '\'' + ", messageModel=" -// + messageModel + '}'; -// } -// -// public long getSuspendCurrentQueueTimeMillis() { -// return suspendCurrentQueueTimeMillis; -// } -// -// public void setSuspendCurrentQueueTimeMillis(long suspendCurrentQueueTimeMillis) { -// this.suspendCurrentQueueTimeMillis = suspendCurrentQueueTimeMillis; -// } -// -// public int getDelayLevelWhenNextConsume() { -// return delayLevelWhenNextConsume; -// } -// -// public void setDelayLevelWhenNextConsume(int delayLevelWhenNextConsume) { -// this.delayLevelWhenNextConsume = delayLevelWhenNextConsume; -// } -// -// public List getNameServer() { -// return nameServer; -// } -// -// public void setNameServer(List nameServer) { -// this.nameServer = nameServer; -// } -// -// public String getConsumerGroup() { -// return consumerGroup; -// } -// -// public void setConsumerGroup(String consumerGroup) { -// this.consumerGroup = consumerGroup; -// } -// -// public String getTopic() { -// return topic; -// } -// -// public void setTopic(String topic) { -// this.topic = topic; -// } -// -// public int getConsumeThreadMax() { -// return consumeThreadMax; -// } -// -// public void setConsumeThreadMax(int consumeThreadMax) { -// this.consumeThreadMax = consumeThreadMax; -// } -// -// public String getCharset() { -// return charset; -// } -// -// public void setCharset(String charset) { -// this.charset = charset; -// } -// -// public RocketMQListener getRocketMQListener() { -// return rocketMQListener; -// } -// -// public void setRocketMQListener(RocketMQListener rocketMQListener) { -// this.rocketMQListener = rocketMQListener; -// } -// -// public DefaultMQPushConsumer getConsumer() { -// return consumer; -// } -// -// public void setConsumer(DefaultMQPushConsumer consumer) { -// this.consumer = consumer; -// } -// -// public ExtendedConsumerProperties -/// getRocketMQConsumerProperties() { -// return rocketMQConsumerProperties; -// } -// -// public ConsumeMode getConsumeMode() { -// return consumeMode; -// } -// -// public SelectorType getSelectorType() { -// return selectorType; -// } -// -// public String getSelectorExpression() { -// return selectorExpression; -// } -// -// public MessageModel getMessageModel() { -// return messageModel; -// } -// -// public RocketMQHeaderMapper getHeaderMapper() { -// return headerMapper; -// } -// -// public void setHeaderMapper(RocketMQHeaderMapper headerMapper) { -// this.headerMapper = headerMapper; -// } -// -// /** -// * Convert rocketmq {@link MessageExt} to Spring {@link Message}. -// * @param messageExt the rocketmq message -// * @return the converted Spring {@link Message} -// */ -// @SuppressWarnings("unchecked") -// private Message convertToSpringMessage(MessageExt messageExt) { -// -// // add reconsume-times header to messageExt -// int reconsumeTimes = messageExt.getReconsumeTimes(); -// messageExt.putUserProperty(ROCKETMQ_RECONSUME_TIMES, -// String.valueOf(reconsumeTimes)); -// Message message = RocketMQUtil.convertToSpringMessage(messageExt); -// return MessageBuilder.fromMessage(message) -// .copyHeaders(headerMapper.toHeaders(messageExt.getProperties())).build(); -// } -// -// public class DefaultMessageListenerConcurrently -// implements MessageListenerConcurrently { -// -// @SuppressWarnings({ "unchecked", "Duplicates" }) -// @Override -// public ConsumeConcurrentlyStatus consumeMessage(List msgs, -// ConsumeConcurrentlyContext context) { -// for (MessageExt messageExt : msgs) { -// log.debug("received msg: {}", messageExt); -// try { -// long now = System.currentTimeMillis(); -// rocketMQListener.onMessage(convertToSpringMessage(messageExt)); -// long costTime = System.currentTimeMillis() - now; -// log.debug("consume {} message key:[{}] cost: {} ms", -// messageExt.getMsgId(), messageExt.getKeys(), costTime); -// } -// catch (Exception e) { -// log.warn("consume message failed. messageExt:{}", messageExt, e); -// context.setDelayLevelWhenNextConsume(delayLevelWhenNextConsume); -// return ConsumeConcurrentlyStatus.RECONSUME_LATER; -// } -// } -// -// return ConsumeConcurrentlyStatus.CONSUME_SUCCESS; -// } -// -// } -// -// public class DefaultMessageListenerOrderly implements MessageListenerOrderly { -// -// @SuppressWarnings({ "unchecked", "Duplicates" }) -// @Override -// public ConsumeOrderlyStatus consumeMessage(List msgs, -// ConsumeOrderlyContext context) { -// for (MessageExt messageExt : msgs) { -// log.debug("received msg: {}", messageExt); -// try { -// long now = System.currentTimeMillis(); -// rocketMQListener.onMessage(convertToSpringMessage(messageExt)); -// long costTime = System.currentTimeMillis() - now; -// log.info("consume {} message key:[{}] cost: {} ms", -// messageExt.getMsgId(), messageExt.getKeys(), costTime); -// } -// catch (Exception e) { -// log.warn("consume message failed. messageExt:{}", messageExt, e); -// context.setSuspendCurrentQueueTimeMillis( -// suspendCurrentQueueTimeMillis); -// return ConsumeOrderlyStatus.SUSPEND_CURRENT_QUEUE_A_MOMENT; -// } -// } -// -// return ConsumeOrderlyStatus.SUCCESS; -// } -// -// } -// -// } diff --git a/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/consuming/RocketMQMessageQueueChooser.java b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/consuming/RocketMQMessageQueueChooser.java deleted file mode 100644 index 948555924..000000000 --- a/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/consuming/RocketMQMessageQueueChooser.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright 2013-2018 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.alibaba.cloud.stream.binder.rocketmq.consuming; - -import java.util.ArrayList; -import java.util.List; -import java.util.Set; - -import org.apache.rocketmq.common.message.MessageQueue; - -/** - * @author Jim - */ -public class RocketMQMessageQueueChooser { - - private volatile int queueIndex = 0; - - private volatile List messageQueues; - - public MessageQueue choose() { - return messageQueues.get(queueIndex); - } - - public int requeue() { - if (queueIndex - 1 < 0) { - this.queueIndex = messageQueues.size() - 1; - } - else { - this.queueIndex = this.queueIndex - 1; - } - return this.queueIndex; - } - - public void increment() { - this.queueIndex = (this.queueIndex + 1) % messageQueues.size(); - } - - public void reset(Set queueSet) { - this.messageQueues = null; - this.messageQueues = new ArrayList<>(queueSet); - this.queueIndex = 0; - } - - public List getMessageQueues() { - return messageQueues; - } - -} From 6d7c47a3660de3aa40fd519f52c84947638a4733 Mon Sep 17 00:00:00 2001 From: zkzlx Date: Mon, 22 Mar 2021 11:05:31 +0800 Subject: [PATCH 5/6] Code refactoring and some new feature support - delete some invalid files. --- .../src/main/resources/application.properties | 8 ++-- .../alibaba/cloud/examples/SenderService.java | 4 +- .../examples/TransactionListenerImpl.java | 38 +++++++++---------- .../src/main/resources/application.properties | 1 + .../rocketmq/contants/RocketMQConst.java | 13 +------ .../inbound/pull/RocketMQMessageSource.java | 25 +++++++++--- .../RocketMQProducerMessageHandler.java | 2 +- .../binder/rocketmq/utils/RocketMQUtils.java | 3 +- .../RocketMQAutoConfigurationTests.java | 22 +++++------ 9 files changed, 61 insertions(+), 55 deletions(-) diff --git a/spring-cloud-alibaba-examples/rocketmq-example/rocketmq-consume-example/src/main/resources/application.properties b/spring-cloud-alibaba-examples/rocketmq-example/rocketmq-consume-example/src/main/resources/application.properties index 2779db522..e2e77bd0b 100644 --- a/spring-cloud-alibaba-examples/rocketmq-example/rocketmq-consume-example/src/main/resources/application.properties +++ b/spring-cloud-alibaba-examples/rocketmq-example/rocketmq-consume-example/src/main/resources/application.properties @@ -3,20 +3,20 @@ spring.cloud.stream.rocketmq.binder.name-server=127.0.0.1:9876 spring.cloud.stream.bindings.input1.destination=test-topic spring.cloud.stream.bindings.input1.content-type=text/plain spring.cloud.stream.bindings.input1.group=test-group1 -spring.cloud.stream.rocketmq.bindings.input1.consumer.orderly=true +spring.cloud.stream.rocketmq.bindings.input1.consumer.push.orderly=true spring.cloud.stream.bindings.input2.destination=test-topic spring.cloud.stream.bindings.input2.content-type=text/plain spring.cloud.stream.bindings.input2.group=test-group2 -spring.cloud.stream.rocketmq.bindings.input2.consumer.orderly=false -spring.cloud.stream.rocketmq.bindings.input2.consumer.tags=tagStr +spring.cloud.stream.rocketmq.bindings.input2.consumer.push.orderly=false +spring.cloud.stream.rocketmq.bindings.input2.consumer.subscription=tagStr spring.cloud.stream.bindings.input2.consumer.concurrency=20 spring.cloud.stream.bindings.input2.consumer.maxAttempts=1 spring.cloud.stream.bindings.input3.destination=test-topic spring.cloud.stream.bindings.input3.content-type=application/json spring.cloud.stream.bindings.input3.group=test-group3 -spring.cloud.stream.rocketmq.bindings.input3.consumer.tags=tagObj +spring.cloud.stream.rocketmq.bindings.input3.consumer.subscription=tagObj spring.cloud.stream.bindings.input3.consumer.concurrency=20 spring.cloud.stream.bindings.input4.destination=TransactionTopic diff --git a/spring-cloud-alibaba-examples/rocketmq-example/rocketmq-produce-example/src/main/java/com/alibaba/cloud/examples/SenderService.java b/spring-cloud-alibaba-examples/rocketmq-example/rocketmq-produce-example/src/main/java/com/alibaba/cloud/examples/SenderService.java index cd9e50939..f7db15b57 100644 --- a/spring-cloud-alibaba-examples/rocketmq-example/rocketmq-produce-example/src/main/java/com/alibaba/cloud/examples/SenderService.java +++ b/spring-cloud-alibaba-examples/rocketmq-example/rocketmq-produce-example/src/main/java/com/alibaba/cloud/examples/SenderService.java @@ -20,8 +20,8 @@ import java.util.stream.Collectors; import java.util.stream.Stream; import com.alibaba.cloud.examples.RocketMQProduceApplication.MySource; +import com.alibaba.cloud.stream.binder.rocketmq.contants.RocketMQConst; import org.apache.rocketmq.common.message.MessageConst; -import org.apache.rocketmq.spring.support.RocketMQHeaders; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.messaging.Message; @@ -62,7 +62,7 @@ public class SenderService { MessageBuilder builder = MessageBuilder.withPayload(msg) .setHeader(MessageHeaders.CONTENT_TYPE, MimeTypeUtils.APPLICATION_JSON); builder.setHeader("test", String.valueOf(num)); - builder.setHeader(RocketMQHeaders.TAGS, "binder"); + builder.setHeader(RocketMQConst.USER_TRANSACTIONAL_ARGS, "binder"); Message message = builder.build(); source.output2().send(message); } diff --git a/spring-cloud-alibaba-examples/rocketmq-example/rocketmq-produce-example/src/main/java/com/alibaba/cloud/examples/TransactionListenerImpl.java b/spring-cloud-alibaba-examples/rocketmq-example/rocketmq-produce-example/src/main/java/com/alibaba/cloud/examples/TransactionListenerImpl.java index e58beb221..1cc1b3290 100644 --- a/spring-cloud-alibaba-examples/rocketmq-example/rocketmq-produce-example/src/main/java/com/alibaba/cloud/examples/TransactionListenerImpl.java +++ b/spring-cloud-alibaba-examples/rocketmq-example/rocketmq-produce-example/src/main/java/com/alibaba/cloud/examples/TransactionListenerImpl.java @@ -16,43 +16,43 @@ package com.alibaba.cloud.examples; -import org.apache.rocketmq.spring.annotation.RocketMQTransactionListener; -import org.apache.rocketmq.spring.core.RocketMQLocalTransactionListener; -import org.apache.rocketmq.spring.core.RocketMQLocalTransactionState; -import org.springframework.messaging.Message; +import org.apache.rocketmq.client.producer.LocalTransactionState; +import org.apache.rocketmq.client.producer.TransactionListener; +import org.apache.rocketmq.common.message.Message; +import org.apache.rocketmq.common.message.MessageExt; +import org.springframework.stereotype.Component; /** * @author Jim */ -@RocketMQTransactionListener(txProducerGroup = "myTxProducerGroup", corePoolSize = 5, - maximumPoolSize = 10) -public class TransactionListenerImpl implements RocketMQLocalTransactionListener { +@Component("myTransactionListener") +public class TransactionListenerImpl implements TransactionListener { @Override - public RocketMQLocalTransactionState executeLocalTransaction(Message msg, - Object arg) { - Object num = msg.getHeaders().get("test"); + public LocalTransactionState executeLocalTransaction(Message msg, + Object arg) { + Object num = msg.getProperty("test"); if ("1".equals(num)) { System.out.println( - "executer: " + new String((byte[]) msg.getPayload()) + " unknown"); - return RocketMQLocalTransactionState.UNKNOWN; + "executer: " + new String(msg.getBody()) + " unknown"); + return LocalTransactionState.UNKNOW; } else if ("2".equals(num)) { System.out.println( - "executer: " + new String((byte[]) msg.getPayload()) + " rollback"); - return RocketMQLocalTransactionState.ROLLBACK; + "executer: " + new String(msg.getBody()) + " rollback"); + return LocalTransactionState.ROLLBACK_MESSAGE; } System.out.println( - "executer: " + new String((byte[]) msg.getPayload()) + " commit"); - return RocketMQLocalTransactionState.COMMIT; + "executer: " + new String(msg.getBody()) + " commit"); + return LocalTransactionState.COMMIT_MESSAGE; } @Override - public RocketMQLocalTransactionState checkLocalTransaction(Message msg) { - System.out.println("check: " + new String((byte[]) msg.getPayload())); - return RocketMQLocalTransactionState.COMMIT; + public LocalTransactionState checkLocalTransaction(MessageExt msg) { + System.out.println("check: " + new String(msg.getBody())); + return LocalTransactionState.COMMIT_MESSAGE; } } diff --git a/spring-cloud-alibaba-examples/rocketmq-example/rocketmq-produce-example/src/main/resources/application.properties b/spring-cloud-alibaba-examples/rocketmq-example/rocketmq-produce-example/src/main/resources/application.properties index 772bf456e..08ab26ca0 100644 --- a/spring-cloud-alibaba-examples/rocketmq-example/rocketmq-produce-example/src/main/resources/application.properties +++ b/spring-cloud-alibaba-examples/rocketmq-example/rocketmq-produce-example/src/main/resources/application.properties @@ -11,6 +11,7 @@ spring.cloud.stream.bindings.output2.destination=TransactionTopic spring.cloud.stream.bindings.output2.content-type=application/json spring.cloud.stream.rocketmq.bindings.output2.producer.transactional=true spring.cloud.stream.rocketmq.bindings.output2.producer.group=myTxProducerGroup +spring.cloud.stream.rocketmq.bindings.output2.producer.transactionListener=myTransactionListener spring.cloud.stream.bindings.output3.destination=pull-topic spring.cloud.stream.bindings.output3.content-type=text/plain diff --git a/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/contants/RocketMQConst.java b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/contants/RocketMQConst.java index e83a6a172..694c8519c 100644 --- a/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/contants/RocketMQConst.java +++ b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/contants/RocketMQConst.java @@ -18,18 +18,11 @@ package com.alibaba.cloud.stream.binder.rocketmq.contants; import org.apache.rocketmq.common.message.MessageConst; -import static org.apache.rocketmq.spring.support.RocketMQHeaders.PREFIX; - /** * @author zkzlx */ public class RocketMQConst extends MessageConst { - /** - * Header key for RocketMQ Transactional Args. - */ - public static final String ROCKET_TRANSACTIONAL_ARG = "TRANSACTIONAL_ARG"; - /** * Default NameServer value. */ @@ -38,12 +31,8 @@ public class RocketMQConst extends MessageConst { /** * Default group for SCS RocketMQ Binder. */ - public static final String DEFAULT_GROUP = PREFIX + "binder_default_group_name"; + public static final String DEFAULT_GROUP = "binder_default_group_name"; - /** - * RocketMQ re-consume times. - */ - public static final String ROCKETMQ_RECONSUME_TIMES = PREFIX + "RECONSUME_TIMES"; public static final String USER_TRANSACTIONAL_ARGS = "TRANSACTIONAL_ARGS"; diff --git a/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/integration/inbound/pull/RocketMQMessageSource.java b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/integration/inbound/pull/RocketMQMessageSource.java index 2ca91384b..a378fc615 100644 --- a/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/integration/inbound/pull/RocketMQMessageSource.java +++ b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/integration/inbound/pull/RocketMQMessageSource.java @@ -17,6 +17,7 @@ package com.alibaba.cloud.stream.binder.rocketmq.integration.inbound.pull; import java.lang.reflect.Field; +import java.util.Iterator; import java.util.List; import com.alibaba.cloud.stream.binder.rocketmq.integration.inbound.RocketMQConsumerFactory; @@ -62,6 +63,8 @@ public class RocketMQMessageSource extends AbstractMessageSource private final MessageSelector messageSelector; private final ExtendedConsumerProperties extendedConsumerProperties; + private volatile Iterator messageExtIterator=null; + public RocketMQMessageSource(String name, ExtendedConsumerProperties extendedConsumerProperties) { this.topic = name; @@ -82,7 +85,7 @@ public class RocketMQMessageSource extends AbstractMessageSource this.consumer = RocketMQConsumerFactory .initPullConsumer(extendedConsumerProperties); // This parameter must be 1, otherwise doReceive cannot be handled singly. - this.consumer.setPullBatchSize(1); +// this.consumer.setPullBatchSize(1); this.consumer.subscribe(topic, messageSelector); this.consumer.setAutoCommit(false); this.assignedMessageQueue = acquireAssignedMessageQueue(this.consumer); @@ -132,11 +135,20 @@ public class RocketMQMessageSource extends AbstractMessageSource @Override protected synchronized Object doReceive() { - List messageExtList = consumer.poll(); - if (CollectionUtils.isEmpty(messageExtList) || messageExtList.size() > 1) { + if(messageExtIterator == null){ + List messageExtList = consumer.poll(); + if (CollectionUtils.isEmpty(messageExtList) || messageExtList.size() > 1) { + return null; + } + messageExtIterator = messageExtList.iterator(); + } + MessageExt messageExt=messageExtIterator.next(); + if(!messageExtIterator.hasNext()){ + messageExtIterator = null; + } + if(null == messageExt){ return null; } - MessageExt messageExt = messageExtList.get(0); MessageQueue messageQueue = null; for (MessageQueue queue : assignedMessageQueue.getAssignedMessageQueues()) { if (queue.getQueueId() == messageExt.getQueueId()) { @@ -144,8 +156,11 @@ public class RocketMQMessageSource extends AbstractMessageSource break; } } + if(messageQueue == null){ + throw new IllegalArgumentException("The message queue is not in assigned list"); + } Message message = RocketMQMessageConverterSupport - .convertMessage2Spring(messageExtList.get(0)); + .convertMessage2Spring(messageExt); return MessageBuilder.fromMessage(message) .setHeader(IntegrationMessageHeaderAccessor.ACKNOWLEDGMENT_CALLBACK, new RocketMQAckCallback(this.consumer, assignedMessageQueue, diff --git a/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/integration/outbound/RocketMQProducerMessageHandler.java b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/integration/outbound/RocketMQProducerMessageHandler.java index 66b58f797..3d58b8af0 100644 --- a/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/integration/outbound/RocketMQProducerMessageHandler.java +++ b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/integration/outbound/RocketMQProducerMessageHandler.java @@ -160,7 +160,7 @@ public class RocketMQProducerMessageHandler extends AbstractMessageHandler TransactionListener.class); if (transactionListener == null) { throw new MessagingException( - "TransactionMQProducer must have a TransactionMQProducer !!! "); + "TransactionMQProducer must have a TransactionListener !!! "); } ((TransactionMQProducer) defaultMQProducer) .setTransactionListener(transactionListener); diff --git a/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/utils/RocketMQUtils.java b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/utils/RocketMQUtils.java index 3f7898422..85165955d 100644 --- a/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/utils/RocketMQUtils.java +++ b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/utils/RocketMQUtils.java @@ -16,6 +16,7 @@ package com.alibaba.cloud.stream.binder.rocketmq.utils; +import com.alibaba.cloud.stream.binder.rocketmq.contants.RocketMQConst; import com.alibaba.cloud.stream.binder.rocketmq.properties.RocketMQBinderConfigurationProperties; import com.alibaba.cloud.stream.binder.rocketmq.properties.RocketMQCommonProperties; import org.apache.rocketmq.acl.common.AclClientRPCHook; @@ -81,7 +82,7 @@ public class RocketMQUtils { public static String getNameServerStr(String nameServer) { if (StringUtils.isEmpty(nameServer)) { - return null; + return RocketMQConst.DEFAULT_NAME_SERVER; } return nameServer.replaceAll(",", ";"); } diff --git a/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/test/java/com/alibaba/cloud/stream/binder/rocketmq/RocketMQAutoConfigurationTests.java b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/test/java/com/alibaba/cloud/stream/binder/rocketmq/RocketMQAutoConfigurationTests.java index 8207f9893..02d0de9f9 100644 --- a/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/test/java/com/alibaba/cloud/stream/binder/rocketmq/RocketMQAutoConfigurationTests.java +++ b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/test/java/com/alibaba/cloud/stream/binder/rocketmq/RocketMQAutoConfigurationTests.java @@ -18,7 +18,7 @@ package com.alibaba.cloud.stream.binder.rocketmq; import java.util.Arrays; -import com.alibaba.cloud.stream.binder.rocketmq.config.RocketMQBinderAutoConfiguration; +import com.alibaba.cloud.stream.binder.rocketmq.autoconfigurate.RocketMQBinderAutoConfiguration; import com.alibaba.cloud.stream.binder.rocketmq.properties.RocketMQBinderConfigurationProperties; import com.alibaba.cloud.stream.binder.rocketmq.properties.RocketMQExtendedBindingProperties; import org.junit.Test; @@ -37,20 +37,20 @@ public class RocketMQAutoConfigurationTests { .withConfiguration( AutoConfigurations.of(RocketMQBinderAutoConfiguration.class)) .withPropertyValues( - "spring.cloud.stream.rocketmq.binder.name-server[0]=127.0.0.1:9876", - "spring.cloud.stream.rocketmq.binder.name-server[1]=127.0.0.1:9877", + "spring.cloud.stream.rocketmq.binder.name-server=127.0.0.1:9876,127.0.0.1:9877", "spring.cloud.stream.bindings.output.destination=TopicOrderTest", "spring.cloud.stream.bindings.output.content-type=application/json", + "spring.cloud.stream.bindings.input1.destination=TopicOrderTest", "spring.cloud.stream.bindings.input1.content-type=application/json", "spring.cloud.stream.bindings.input1.group=test-group1", - "spring.cloud.stream.rocketmq.bindings.input1.consumer.orderly=true", + "spring.cloud.stream.rocketmq.bindings.input1.consumer.push.orderly=true", "spring.cloud.stream.bindings.input1.consumer.maxAttempts=1", "spring.cloud.stream.bindings.input2.destination=TopicOrderTest", "spring.cloud.stream.bindings.input2.content-type=application/json", "spring.cloud.stream.bindings.input2.group=test-group2", - "spring.cloud.stream.rocketmq.bindings.input2.consumer.orderly=false", - "spring.cloud.stream.rocketmq.bindings.input2.consumer.tags=tag1"); + "spring.cloud.stream.rocketmq.bindings.input2.consumer.push.orderly=false", + "spring.cloud.stream.rocketmq.bindings.input2.consumer.subscription=tag1"); @Test public void testProperties() { @@ -58,16 +58,16 @@ public class RocketMQAutoConfigurationTests { RocketMQBinderConfigurationProperties binderConfigurationProperties = context .getBean(RocketMQBinderConfigurationProperties.class); assertThat(binderConfigurationProperties.getNameServer()) - .isEqualTo(Arrays.asList("127.0.0.1:9876", "127.0.0.1:9877")); + .isEqualTo("127.0.0.1:9876,127.0.0.1:9877"); RocketMQExtendedBindingProperties bindingProperties = context .getBean(RocketMQExtendedBindingProperties.class); assertThat( - bindingProperties.getExtendedConsumerProperties("input2").getTags()) + bindingProperties.getExtendedConsumerProperties("input2").getSubscription()) .isEqualTo("tag1"); - assertThat(bindingProperties.getExtendedConsumerProperties("input2") - .getOrderly()).isFalse(); + assertThat(bindingProperties.getExtendedConsumerProperties("input2").getPush().getOrderly() + ).isFalse(); assertThat(bindingProperties.getExtendedConsumerProperties("input1") - .getOrderly()).isTrue(); + .getPush().getOrderly()).isTrue(); }); } From 9379d18ace1a4ca3fb2400920c7e95b17eb4fda9 Mon Sep 17 00:00:00 2001 From: zkzlx Date: Mon, 22 Mar 2021 14:37:22 +0800 Subject: [PATCH 6/6] Code style --- .../examples/TransactionListenerImpl.java | 14 +++--- .../RocketMQMessageChannelBinder.java | 7 +-- .../RocketMQBinderAutoConfiguration.java | 4 +- .../rocketmq/contants/RocketMQConst.java | 33 +++++++++++--- .../convert/RocketMQMessageConverter.java | 14 ++++-- .../custom/RocketMQBeanContainerCache.java | 9 ++-- .../RocketMQConfigBeanPostProcessor.java | 6 +-- .../extend/ErrorAcknowledgeHandler.java | 6 +-- .../inbound/RocketMQConsumerFactory.java | 6 ++- .../RocketMQInboundChannelAdapter.java | 12 ++--- .../pull/DefaultErrorAcknowledgeHandler.java | 9 ++-- .../inbound/pull/RocketMQAckCallback.java | 13 ++++-- .../inbound/pull/RocketMQMessageSource.java | 21 +++++---- .../outbound/RocketMQProduceFactory.java | 9 +++- .../RocketMQProducerMessageHandler.java | 24 ++++++---- .../rocketmq/metrics/Instrumentation.java | 14 ++++++ .../metrics/InstrumentationManager.java | 3 ++ ...RocketMQBinderConfigurationProperties.java | 5 ++- .../properties/RocketMQCommonProperties.java | 29 ++++++------ .../RocketMQConsumerProperties.java | 45 ++++++++++--------- .../RocketMQExtendedBindingProperties.java | 4 +- .../RocketMQProducerProperties.java | 32 ++++++++++--- .../RocketMQSpecificPropertiesProvider.java | 4 +- .../RocketMQMessageConverterSupport.java | 10 +++-- .../binder/rocketmq/utils/RocketMQUtils.java | 11 ++--- .../RocketMQAutoConfigurationTests.java | 15 +++---- 26 files changed, 231 insertions(+), 128 deletions(-) diff --git a/spring-cloud-alibaba-examples/rocketmq-example/rocketmq-produce-example/src/main/java/com/alibaba/cloud/examples/TransactionListenerImpl.java b/spring-cloud-alibaba-examples/rocketmq-example/rocketmq-produce-example/src/main/java/com/alibaba/cloud/examples/TransactionListenerImpl.java index 1cc1b3290..446570ec9 100644 --- a/spring-cloud-alibaba-examples/rocketmq-example/rocketmq-produce-example/src/main/java/com/alibaba/cloud/examples/TransactionListenerImpl.java +++ b/spring-cloud-alibaba-examples/rocketmq-example/rocketmq-produce-example/src/main/java/com/alibaba/cloud/examples/TransactionListenerImpl.java @@ -16,11 +16,11 @@ package com.alibaba.cloud.examples; - import org.apache.rocketmq.client.producer.LocalTransactionState; import org.apache.rocketmq.client.producer.TransactionListener; import org.apache.rocketmq.common.message.Message; import org.apache.rocketmq.common.message.MessageExt; + import org.springframework.stereotype.Component; /** @@ -30,22 +30,18 @@ import org.springframework.stereotype.Component; public class TransactionListenerImpl implements TransactionListener { @Override - public LocalTransactionState executeLocalTransaction(Message msg, - Object arg) { + public LocalTransactionState executeLocalTransaction(Message msg, Object arg) { Object num = msg.getProperty("test"); if ("1".equals(num)) { - System.out.println( - "executer: " + new String(msg.getBody()) + " unknown"); + System.out.println("executer: " + new String(msg.getBody()) + " unknown"); return LocalTransactionState.UNKNOW; } else if ("2".equals(num)) { - System.out.println( - "executer: " + new String(msg.getBody()) + " rollback"); + System.out.println("executer: " + new String(msg.getBody()) + " rollback"); return LocalTransactionState.ROLLBACK_MESSAGE; } - System.out.println( - "executer: " + new String(msg.getBody()) + " commit"); + System.out.println("executer: " + new String(msg.getBody()) + " commit"); return LocalTransactionState.COMMIT_MESSAGE; } diff --git a/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/RocketMQMessageChannelBinder.java b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/RocketMQMessageChannelBinder.java index 5683bff68..403f51476 100644 --- a/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/RocketMQMessageChannelBinder.java +++ b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/RocketMQMessageChannelBinder.java @@ -1,11 +1,11 @@ /* - * Copyright (C) 2018 the original author or authors. + * Copyright 2013-2018 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -60,6 +60,7 @@ public class RocketMQMessageChannelBinder extends ExtendedPropertiesBinder { private final RocketMQExtendedBindingProperties extendedBindingProperties; + private final RocketMQBinderConfigurationProperties binderConfigurationProperties; public RocketMQMessageChannelBinder( @@ -175,7 +176,6 @@ public class RocketMQMessageChannelBinder extends /** * Binders can return an {@link ErrorMessageStrategy} for building error messages; * binder implementations typically might add extra headers to the error message. - * * @return the implementation - may be null. */ @Override @@ -203,4 +203,5 @@ public class RocketMQMessageChannelBinder extends public Class getExtendedPropertiesEntryClass() { return this.extendedBindingProperties.getExtendedPropertiesEntryClass(); } + } diff --git a/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/autoconfigurate/RocketMQBinderAutoConfiguration.java b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/autoconfigurate/RocketMQBinderAutoConfiguration.java index abcb9b961..ec47e951a 100644 --- a/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/autoconfigurate/RocketMQBinderAutoConfiguration.java +++ b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/autoconfigurate/RocketMQBinderAutoConfiguration.java @@ -34,7 +34,8 @@ import org.springframework.context.annotation.Configuration; import org.springframework.messaging.converter.CompositeMessageConverter; /** - * issue:https://github.com/alibaba/spring-cloud-alibaba/issues/1681 + * issue:https://github.com/alibaba/spring-cloud-alibaba/issues/1681 . + * * @author Timur Valiev * @author Jim */ @@ -45,6 +46,7 @@ public class RocketMQBinderAutoConfiguration { @Autowired private RocketMQExtendedBindingProperties extendedBindingProperties; + @Autowired private RocketMQBinderConfigurationProperties rocketBinderConfigurationProperties; diff --git a/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/contants/RocketMQConst.java b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/contants/RocketMQConst.java index 694c8519c..4f893642e 100644 --- a/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/contants/RocketMQConst.java +++ b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/contants/RocketMQConst.java @@ -1,11 +1,11 @@ /* - * Copyright (C) 2018 the original author or authors. + * Copyright 2013-2018 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -31,9 +31,11 @@ public class RocketMQConst extends MessageConst { /** * Default group for SCS RocketMQ Binder. */ - public static final String DEFAULT_GROUP = "binder_default_group_name"; - + public static final String DEFAULT_GROUP = "binder_default_group_name"; + /** + * user args for SCS RocketMQ Binder. + */ public static final String USER_TRANSACTIONAL_ARGS = "TRANSACTIONAL_ARGS"; /** @@ -41,19 +43,34 @@ public class RocketMQConst extends MessageConst { * and parameters are passed through HEADERS. */ public static class Headers { + + /** + * keys for SCS RocketMQ Headers. + */ public static final String KEYS = MessageConst.PROPERTY_KEYS; + + /** + * tags for SCS RocketMQ Headers. + */ public static final String TAGS = MessageConst.PROPERTY_TAGS; + + /** + * topic for SCS RocketMQ Headers. + */ public static final String TOPIC = "MQ_TOPIC"; + /** * The ID of the message. */ public static final String MESSAGE_ID = "MQ_MESSAGE_ID"; + /** * The timestamp that the message producer invokes the message sending API. */ public static final String BORN_TIMESTAMP = "MQ_BORN_TIMESTAMP"; + /** - * The IP and port number of the message producer + * The IP and port number of the message producer. */ public static final String BORN_HOST = "MQ_BORN_HOST"; @@ -61,19 +78,23 @@ public class RocketMQConst extends MessageConst { * Message flag, MQ is not processed and is available for use by applications. */ public static final String FLAG = "MQ_FLAG"; + /** - * Message consumption queue ID + * Message consumption queue ID. */ public static final String QUEUE_ID = "MQ_QUEUE_ID"; + /** * Message system Flag, such as whether or not to compress, whether or not to * transactional messages. */ public static final String SYS_FLAG = "MQ_SYS_FLAG"; + /** * The transaction ID of the transaction message. */ public static final String TRANSACTION_ID = "MQ_TRANSACTION_ID"; + } } diff --git a/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/convert/RocketMQMessageConverter.java b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/convert/RocketMQMessageConverter.java index 58f17c6ef..98bd03263 100644 --- a/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/convert/RocketMQMessageConverter.java +++ b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/convert/RocketMQMessageConverter.java @@ -1,11 +1,11 @@ /* - * Copyright (C) 2018 the original author or authors. + * Copyright 2013-2018 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -27,14 +27,19 @@ import org.springframework.messaging.converter.StringMessageConverter; import org.springframework.util.ClassUtils; /** - * The default message converter of rocketMq,its bean name is {@link #DEFAULT_NAME} + * The default message converter of rocketMq,its bean name is {@link #DEFAULT_NAME} . + * * @author zkzlx */ public class RocketMQMessageConverter { + /** + * rocketMQMessageConverter. + */ public static final String DEFAULT_NAME = "rocketMQMessageConverter"; private static final boolean JACKSON_PRESENT; + private static final boolean FASTJSON_PRESENT; static { @@ -81,4 +86,5 @@ public class RocketMQMessageConverter { public void setMessageConverter(CompositeMessageConverter messageConverter) { this.messageConverter = messageConverter; } -} \ No newline at end of file + +} diff --git a/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/custom/RocketMQBeanContainerCache.java b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/custom/RocketMQBeanContainerCache.java index 9afc94821..21c62aede 100644 --- a/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/custom/RocketMQBeanContainerCache.java +++ b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/custom/RocketMQBeanContainerCache.java @@ -1,11 +1,11 @@ /* - * Copyright (C) 2018 the original author or authors. + * Copyright 2013-2018 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -32,12 +32,15 @@ import org.springframework.messaging.converter.CompositeMessageConverter; import org.springframework.util.StringUtils; /** - * Gets the beans configured in the configuration file + * Gets the beans configured in the configuration file. * * @author junboXiang */ public final class RocketMQBeanContainerCache { + private RocketMQBeanContainerCache() { + } + private static final Class[] CLASSES = new Class[] { CompositeMessageConverter.class, AllocateMessageQueueStrategy.class, MessageQueueSelector.class, MessageListener.class, TransactionListener.class, diff --git a/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/custom/RocketMQConfigBeanPostProcessor.java b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/custom/RocketMQConfigBeanPostProcessor.java index 30bd64328..a83fdbe08 100644 --- a/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/custom/RocketMQConfigBeanPostProcessor.java +++ b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/custom/RocketMQConfigBeanPostProcessor.java @@ -1,11 +1,11 @@ /* - * Copyright (C) 2018 the original author or authors. + * Copyright 2013-2018 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -22,7 +22,7 @@ import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.BeanPostProcessor; /** - * find RocketMQ bean by annotations + * find RocketMQ bean by annotations. * * @author junboXiang * diff --git a/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/extend/ErrorAcknowledgeHandler.java b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/extend/ErrorAcknowledgeHandler.java index fcf6de804..dfe65fd94 100644 --- a/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/extend/ErrorAcknowledgeHandler.java +++ b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/extend/ErrorAcknowledgeHandler.java @@ -1,11 +1,11 @@ /* - * Copyright (C) 2018 the original author or authors. + * Copyright 2013-2018 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -27,7 +27,7 @@ public interface ErrorAcknowledgeHandler { /** * Ack state handling, including receive, reject, and retry, when a consumption * exception occurs. - * @param message + * @param message message * @return see {@link Status} */ Status handler(Message message); diff --git a/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/integration/inbound/RocketMQConsumerFactory.java b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/integration/inbound/RocketMQConsumerFactory.java index 876249581..7f7e1bf26 100644 --- a/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/integration/inbound/RocketMQConsumerFactory.java +++ b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/integration/inbound/RocketMQConsumerFactory.java @@ -41,6 +41,9 @@ import org.springframework.util.StringUtils; */ public final class RocketMQConsumerFactory { + private RocketMQConsumerFactory() { + } + private final static Logger log = LoggerFactory .getLogger(RocketMQConsumerFactory.class); @@ -91,7 +94,8 @@ public final class RocketMQConsumerFactory { /** * todo Compatible with versions less than 4.6 ? - * @return + * @param extendedConsumerProperties extendedConsumerProperties + * @return DefaultLitePullConsumer */ public static DefaultLitePullConsumer initPullConsumer( ExtendedConsumerProperties extendedConsumerProperties) { diff --git a/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/integration/inbound/RocketMQInboundChannelAdapter.java b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/integration/inbound/RocketMQInboundChannelAdapter.java index d0aec5523..61c0eedd3 100644 --- a/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/integration/inbound/RocketMQInboundChannelAdapter.java +++ b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/integration/inbound/RocketMQInboundChannelAdapter.java @@ -48,7 +48,6 @@ import org.springframework.util.Assert; import org.springframework.util.CollectionUtils; /** - * TODO Describe what it does * @author Jim */ public class RocketMQInboundChannelAdapter extends MessageProducerSupport @@ -58,10 +57,13 @@ public class RocketMQInboundChannelAdapter extends MessageProducerSupport .getLogger(RocketMQInboundChannelAdapter.class); private RetryTemplate retryTemplate; + private RecoveryCallback recoveryCallback; + private DefaultMQPushConsumer pushConsumer; private final String topic; + private final ExtendedConsumerProperties extendedConsumerProperties; public RocketMQInboundChannelAdapter(String topic, @@ -146,11 +148,11 @@ public class RocketMQInboundChannelAdapter extends MessageProducerSupport * The actual execution of a user-defined input consumption service method. * @param messageExtList rocket mq message list * @param failSupplier {@link ConsumeConcurrentlyStatus} or - * {@link ConsumeOrderlyStatus} + * {@link ConsumeOrderlyStatus} * @param sucSupplier {@link ConsumeConcurrentlyStatus} or - * {@link ConsumeOrderlyStatus} - * @param - * @return + * {@link ConsumeOrderlyStatus} + * @param object + * @return R */ private R consumeMessage(List messageExtList, Supplier failSupplier, Supplier sucSupplier) { diff --git a/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/integration/inbound/pull/DefaultErrorAcknowledgeHandler.java b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/integration/inbound/pull/DefaultErrorAcknowledgeHandler.java index 3296a128e..458324741 100644 --- a/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/integration/inbound/pull/DefaultErrorAcknowledgeHandler.java +++ b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/integration/inbound/pull/DefaultErrorAcknowledgeHandler.java @@ -1,11 +1,11 @@ /* - * Copyright (C) 2018 the original author or authors. + * Copyright 2013-2018 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -29,15 +29,16 @@ import org.springframework.messaging.Message; * @author zkzlx */ public class DefaultErrorAcknowledgeHandler implements ErrorAcknowledgeHandler { + /** * Ack state handling, including receive, reject, and retry, when a consumption * exception occurs. - * - * @param message + * @param message message * @return see {@link Status} */ @Override public Status handler(Message message) { return Status.REQUEUE; } + } diff --git a/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/integration/inbound/pull/RocketMQAckCallback.java b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/integration/inbound/pull/RocketMQAckCallback.java index f617dd097..56e50ca4a 100644 --- a/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/integration/inbound/pull/RocketMQAckCallback.java +++ b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/integration/inbound/pull/RocketMQAckCallback.java @@ -1,11 +1,11 @@ /* - * Copyright (C) 2018 the original author or authors. + * Copyright 2013-2018 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -31,16 +31,23 @@ import org.springframework.util.Assert; /** * A pollable {@link org.springframework.integration.core.MessageSource} for RocketMQ. + * * @author zkzlx */ public class RocketMQAckCallback implements AcknowledgmentCallback { + private final static Logger log = LoggerFactory.getLogger(RocketMQAckCallback.class); private boolean acknowledged; + private boolean autoAckEnabled = true; + private MessageExt messageExt; + private AssignedMessageQueue assignedMessageQueue; + private DefaultLitePullConsumer consumer; + private final MessageQueue messageQueue; public RocketMQAckCallback(DefaultLitePullConsumer consumer, @@ -109,4 +116,4 @@ public class RocketMQAckCallback implements AcknowledgmentCallback { } } -} \ No newline at end of file +} diff --git a/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/integration/inbound/pull/RocketMQMessageSource.java b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/integration/inbound/pull/RocketMQMessageSource.java index a378fc615..a7d7e73da 100644 --- a/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/integration/inbound/pull/RocketMQMessageSource.java +++ b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/integration/inbound/pull/RocketMQMessageSource.java @@ -56,14 +56,18 @@ public class RocketMQMessageSource extends AbstractMessageSource .getLogger(RocketMQMessageSource.class); private DefaultLitePullConsumer consumer; + private AssignedMessageQueue assignedMessageQueue; + private volatile boolean running; private final String topic; + private final MessageSelector messageSelector; + private final ExtendedConsumerProperties extendedConsumerProperties; - private volatile Iterator messageExtIterator=null; + private volatile Iterator messageExtIterator = null; public RocketMQMessageSource(String name, ExtendedConsumerProperties extendedConsumerProperties) { @@ -85,7 +89,7 @@ public class RocketMQMessageSource extends AbstractMessageSource this.consumer = RocketMQConsumerFactory .initPullConsumer(extendedConsumerProperties); // This parameter must be 1, otherwise doReceive cannot be handled singly. -// this.consumer.setPullBatchSize(1); + // this.consumer.setPullBatchSize(1); this.consumer.subscribe(topic, messageSelector); this.consumer.setAutoCommit(false); this.assignedMessageQueue = acquireAssignedMessageQueue(this.consumer); @@ -135,18 +139,18 @@ public class RocketMQMessageSource extends AbstractMessageSource @Override protected synchronized Object doReceive() { - if(messageExtIterator == null){ + if (messageExtIterator == null) { List messageExtList = consumer.poll(); if (CollectionUtils.isEmpty(messageExtList) || messageExtList.size() > 1) { return null; } messageExtIterator = messageExtList.iterator(); } - MessageExt messageExt=messageExtIterator.next(); - if(!messageExtIterator.hasNext()){ + MessageExt messageExt = messageExtIterator.next(); + if (!messageExtIterator.hasNext()) { messageExtIterator = null; } - if(null == messageExt){ + if (null == messageExt) { return null; } MessageQueue messageQueue = null; @@ -156,8 +160,9 @@ public class RocketMQMessageSource extends AbstractMessageSource break; } } - if(messageQueue == null){ - throw new IllegalArgumentException("The message queue is not in assigned list"); + if (messageQueue == null) { + throw new IllegalArgumentException( + "The message queue is not in assigned list"); } Message message = RocketMQMessageConverterSupport .convertMessage2Spring(messageExt); diff --git a/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/integration/outbound/RocketMQProduceFactory.java b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/integration/outbound/RocketMQProduceFactory.java index 7017ba46e..463868438 100644 --- a/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/integration/outbound/RocketMQProduceFactory.java +++ b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/integration/outbound/RocketMQProduceFactory.java @@ -39,18 +39,23 @@ import org.springframework.util.Assert; import org.springframework.util.StringUtils; /** - * Extended function related to producer . eg:initial + * Extended function related to producer . eg:initial . * * @author zkzlx */ public final class RocketMQProduceFactory { + private RocketMQProduceFactory() { + } + private final static Logger log = LoggerFactory .getLogger(RocketMQProduceFactory.class); /** * init for the producer,including convert producer params. - * @return + * @param topic topic + * @param producerProperties producerProperties + * @return DefaultMQProducer */ public static DefaultMQProducer initRocketMQProducer(String topic, RocketMQProducerProperties producerProperties) { diff --git a/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/integration/outbound/RocketMQProducerMessageHandler.java b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/integration/outbound/RocketMQProducerMessageHandler.java index 3d58b8af0..56c208759 100644 --- a/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/integration/outbound/RocketMQProducerMessageHandler.java +++ b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/integration/outbound/RocketMQProducerMessageHandler.java @@ -1,11 +1,11 @@ /* - * Copyright (C) 2018 the original author or authors. + * Copyright 2013-2018 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -61,16 +61,23 @@ public class RocketMQProducerMessageHandler extends AbstractMessageHandler .getLogger(RocketMQProducerMessageHandler.class); private volatile boolean running = false; + private volatile boolean isTrans = false; private ErrorMessageStrategy errorMessageStrategy; + private MessageChannel sendFailureChannel; + private MessageConverterConfigurer.PartitioningInterceptor partitioningInterceptor; + private DefaultMQProducer defaultMQProducer; + private MessageQueueSelector messageQueueSelector; private final ProducerDestination destination; + private final ExtendedProducerProperties extendedProducerProperties; + private final RocketMQProducerProperties mqProducerProperties; public RocketMQProducerMessageHandler(ProducerDestination destination, @@ -93,10 +100,8 @@ public class RocketMQProducerMessageHandler extends AbstractMessageHandler // Use the default if the partition is on and no customization is available. this.messageQueueSelector = RocketMQBeanContainerCache.getBean( mqProducerProperties.getMessageQueueSelector(), - MessageQueueSelector.class, - extendedProducerProperties.isPartitioned() - ? new PartitionMessageQueueSelector() - : null); + MessageQueueSelector.class, extendedProducerProperties.isPartitioned() + ? new PartitionMessageQueueSelector() : null); } @Override @@ -226,9 +231,9 @@ public class RocketMQProducerMessageHandler extends AbstractMessageHandler } /** - * https://github.com/alibaba/spring-cloud-alibaba/issues/1408 - * @param message - * @return + * https://github.com/alibaba/spring-cloud-alibaba/issues/1408 . + * @param message message + * @return SendCallback */ private SendCallback getSendCallback(Message message) { SendCallback sendCallback = RocketMQBeanContainerCache @@ -283,4 +288,5 @@ public class RocketMQProducerMessageHandler extends AbstractMessageHandler this.partitioningInterceptor = partitioningInterceptor; return this; } + } diff --git a/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/metrics/Instrumentation.java b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/metrics/Instrumentation.java index 397e62854..e26482855 100644 --- a/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/metrics/Instrumentation.java +++ b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/metrics/Instrumentation.java @@ -28,6 +28,7 @@ import org.springframework.context.Lifecycle; public class Instrumentation { private final String name; + private Lifecycle actuator; protected final AtomicBoolean started = new AtomicBoolean(false); @@ -88,4 +89,17 @@ public class Instrumentation { public int hashCode() { return Objects.hash(getName(), getActuator()); } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Instrumentation that = (Instrumentation) o; + return name.equals(that.name) && actuator.equals(that.actuator); + } + } diff --git a/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/metrics/InstrumentationManager.java b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/metrics/InstrumentationManager.java index de6e1e794..ad7958e44 100644 --- a/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/metrics/InstrumentationManager.java +++ b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/metrics/InstrumentationManager.java @@ -26,6 +26,9 @@ import java.util.Map; */ public final class InstrumentationManager { + private InstrumentationManager() { + } + private static final Map HEALTH_INSTRUMENTATIONS = new HashMap<>(); public static Collection getHealthInstrumentations() { diff --git a/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/properties/RocketMQBinderConfigurationProperties.java b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/properties/RocketMQBinderConfigurationProperties.java index fd5e77919..3da04ea18 100644 --- a/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/properties/RocketMQBinderConfigurationProperties.java +++ b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/properties/RocketMQBinderConfigurationProperties.java @@ -1,11 +1,11 @@ /* - * Copyright (C) 2018 the original author or authors. + * Copyright 2013-2018 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -20,6 +20,7 @@ import org.springframework.boot.context.properties.ConfigurationProperties; /** * binding rocketMq properties. + * * @author Jim */ @ConfigurationProperties(prefix = "spring.cloud.stream.rocketmq.binder") diff --git a/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/properties/RocketMQCommonProperties.java b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/properties/RocketMQCommonProperties.java index 00e7d30dd..9e9114641 100644 --- a/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/properties/RocketMQCommonProperties.java +++ b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/properties/RocketMQCommonProperties.java @@ -1,11 +1,11 @@ /* - * Copyright (C) 2018 the original author or authors. + * Copyright 2013-2018 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -26,6 +26,7 @@ import org.apache.rocketmq.remoting.netty.TlsSystemConfig; * @author zkzlx */ public class RocketMQCommonProperties implements Serializable { + private static final long serialVersionUID = -6724870154343284715L; private boolean enabled = true; @@ -41,38 +42,36 @@ public class RocketMQCommonProperties implements Serializable { * The property of "secret-key". */ private String secretKey; + /** * Consumers of the same role is required to have exactly same subscriptions and * consumerGroup to correctly achieve load balance. It's required and needs to be - * globally unique. - *

- * Producer group conceptually aggregates all producer instances of exactly same role, - * which is particularly important when transactional messages are involved. - *

- *

- * For non-transactional messages, it does not matter as long as it's unique per - * process. - *

- *

- * See here for further - * discussion. + * globally unique. Producer group conceptually aggregates all producer instances of + * exactly same role, which is particularly important when transactional messages are + * involved. For non-transactional messages, it does not matter as long as it's unique + * per process. See here + * for further discussion. */ private String group; private String namespace; + private String accessChannel = AccessChannel.LOCAL.name(); + /** * Pulling topic information interval from the named server. * see{@link MQClientInstance#startScheduledTask()},eg:ScheduledTask * updateTopicRouteInfoFromNameServer. */ private int pollNameServerInterval = 1000 * 30; + /** * Heartbeat interval in microseconds with message broker. * see{@link MQClientInstance#startScheduledTask()},eg:ScheduledTask * sendHeartbeatToAllBroker . */ private int heartbeatBrokerInterval = 1000 * 30; + /** * Offset persistent interval for consumer. * see{@link MQClientInstance#startScheduledTask()},eg:ScheduledTask @@ -85,6 +84,7 @@ public class RocketMQCommonProperties implements Serializable { private boolean useTLS = TlsSystemConfig.tlsEnable; private boolean enableMsgTrace = true; + private String customizedTraceTopic; public boolean getEnabled() { @@ -198,4 +198,5 @@ public class RocketMQCommonProperties implements Serializable { public void setCustomizedTraceTopic(String customizedTraceTopic) { this.customizedTraceTopic = customizedTraceTopic; } + } diff --git a/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/properties/RocketMQConsumerProperties.java b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/properties/RocketMQConsumerProperties.java index 1a889f6d7..ebe2c1c43 100644 --- a/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/properties/RocketMQConsumerProperties.java +++ b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/properties/RocketMQConsumerProperties.java @@ -1,11 +1,11 @@ /* - * Copyright (C) 2018 the original author or authors. + * Copyright 2013-2018 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -37,8 +37,6 @@ public class RocketMQConsumerProperties extends RocketMQCommonProperties { /** * Message model defines the way how messages are delivered to each consumer clients. - *

- * * This field defaults to clustering. */ private String messageModel = MessageModel.CLUSTERING.getModeCN(); @@ -60,13 +58,12 @@ public class RocketMQConsumerProperties extends RocketMQCommonProperties { private String subscription; /** - * Delay some time when exception occur + * Delay some time when exception occur . */ private long pullTimeDelayMillsWhenException = 1000; /** * Consuming point on consumer booting. - *

* * There are three consuming points: *
    @@ -90,6 +87,7 @@ public class RocketMQConsumerProperties extends RocketMQCommonProperties { *
*/ private ConsumeFromWhere consumeFromWhere = ConsumeFromWhere.CONSUME_FROM_LAST_OFFSET; + /** * Backtracking consumption time with second precision. Time format is * 20131223171201
@@ -102,13 +100,14 @@ public class RocketMQConsumerProperties extends RocketMQCommonProperties { /** * Flow control threshold on queue level, each message queue will cache at most 1000 * messages by default, Consider the {@link #pullBatchSize}, the instantaneous value - * may exceed the limit + * may exceed the limit . */ private int pullThresholdForQueue = 1000; + /** * Limit the cached message size on queue level, each message queue will cache at most * 100 MiB messages by default, Consider the {@link #pullBatchSize}, the instantaneous - * value may exceed the limit + * value may exceed the limit . * *

* The size of a message only measured by message body, so it's not accurate @@ -126,6 +125,7 @@ public class RocketMQConsumerProperties extends RocketMQCommonProperties { private int consumeMaxSpan = 2000; private Push push = new Push(); + private Pull pull = new Pull(); public String getMessageModel() { @@ -238,6 +238,7 @@ public class RocketMQConsumerProperties extends RocketMQCommonProperties { } public static class Push implements Serializable { + private static final long serialVersionUID = -7398468554978817630L; /** @@ -245,6 +246,7 @@ public class RocketMQConsumerProperties extends RocketMQCommonProperties { * false, using {@link MessageListenerConcurrently}. */ private boolean orderly = false; + /** * Suspending pulling time for cases requiring slow pulling like flow-control * scenario. see{@link ConsumeMessageOrderlyService#processConsumeResult}. @@ -254,10 +256,9 @@ public class RocketMQConsumerProperties extends RocketMQCommonProperties { /** * https://github.com/alibaba/spring-cloud-alibaba/issues/1866 Max re-consume - * times. -1 means 16 times. - *

- * If messages are re-consumed more than {@link #maxReconsumeTimes} before - * success, it's be directed to a deletion queue waiting. + * times. -1 means 16 times. If messages are re-consumed more than + * {@link #maxReconsumeTimes} before success, it's be directed to a deletion queue + * waiting. */ private int maxReconsumeTimes; @@ -285,21 +286,21 @@ public class RocketMQConsumerProperties extends RocketMQCommonProperties { * MiB(Unlimited) *

* The value of {@code pullThresholdSizeForQueue} will be overwrote and calculated - * based on {@code pullThresholdSizeForTopic} if it is't unlimited + * based on {@code pullThresholdSizeForTopic} if it is't unlimited . *

* For example, if the value of pullThresholdSizeForTopic is 1000 MiB and 10 * message queues are assigned to this consumer, then pullThresholdSizeForQueue - * will be set to 100 MiB + * will be set to 100 MiB . */ private int pullThresholdSizeForTopic = -1; /** - * Message pull Interval + * Message pull Interval. */ private long pullInterval = 0; /** - * Batch consumption size + * Batch consumption size. */ private int consumeMessageBatchMaxSize = 1; @@ -366,15 +367,18 @@ public class RocketMQConsumerProperties extends RocketMQCommonProperties { public void setConsumeMessageBatchMaxSize(int consumeMessageBatchMaxSize) { this.consumeMessageBatchMaxSize = consumeMessageBatchMaxSize; } + } public static class Pull implements Serializable { + /** - * The poll timeout in milliseconds + * The poll timeout in milliseconds. */ private long pollTimeoutMillis = 1000 * 5; + /** - * Pull thread number + * Pull thread number. */ private int pullThreadNums = 20; @@ -385,13 +389,13 @@ public class RocketMQConsumerProperties extends RocketMQCommonProperties { /** * Long polling mode, the Consumer connection timeout(must greater than - * brokerSuspendMaxTimeMillis), it is not recommended to modify + * brokerSuspendMaxTimeMillis), it is not recommended to modify. */ private long consumerTimeoutMillisWhenSuspend = 1000 * 30; /** * Ack state handling, including receive, reject, and retry, when a consumption - * exception occurs. see {@link } + * exception occurs. */ private String errAcknowledge; @@ -446,6 +450,7 @@ public class RocketMQConsumerProperties extends RocketMQCommonProperties { public void setPullThresholdForAll(long pullThresholdForAll) { this.pullThresholdForAll = pullThresholdForAll; } + } } diff --git a/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/properties/RocketMQExtendedBindingProperties.java b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/properties/RocketMQExtendedBindingProperties.java index 5fc34ed08..6c4af119d 100644 --- a/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/properties/RocketMQExtendedBindingProperties.java +++ b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/properties/RocketMQExtendedBindingProperties.java @@ -1,11 +1,11 @@ /* - * Copyright (C) 2018 the original author or authors. + * Copyright 2013-2018 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, diff --git a/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/properties/RocketMQProducerProperties.java b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/properties/RocketMQProducerProperties.java index 8f73cf93f..4035f1483 100644 --- a/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/properties/RocketMQProducerProperties.java +++ b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/properties/RocketMQProducerProperties.java @@ -1,11 +1,11 @@ /* - * Copyright (C) 2018 the original author or authors. + * Copyright 2013-2018 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -37,7 +37,6 @@ public class RocketMQProducerProperties extends RocketMQCommonProperties { /** * Maximum number of retry to perform internally before claiming sending failure in * synchronous mode. - *

* * This may potentially cause message duplication which is up to application * developers to resolve. @@ -47,7 +46,6 @@ public class RocketMQProducerProperties extends RocketMQCommonProperties { /** * Maximum number of retry to perform internally before claiming sending failure in * asynchronous mode. - *

* * This may potentially cause message duplication which is up to application * developers to resolve. @@ -203,19 +201,41 @@ public class RocketMQProducerProperties extends RocketMQCommonProperties { } public enum ProducerType { - Normal, Trans; + + /** + * Is not a transaction. + */ + Normal, + /** + * a transaction. + */ + Trans; public boolean equalsName(String name) { return this.name().equalsIgnoreCase(name); } + } public enum SendType { - OneWay, Async, Sync,; + + /** + * one way. + */ + OneWay, + /** + * Asynchronization Model. + */ + Async, + /** + * synchronization. + */ + Sync,; public boolean equalsName(String name) { return this.name().equalsIgnoreCase(name); } + } } diff --git a/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/properties/RocketMQSpecificPropertiesProvider.java b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/properties/RocketMQSpecificPropertiesProvider.java index 99a1a36fb..990a211ce 100644 --- a/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/properties/RocketMQSpecificPropertiesProvider.java +++ b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/properties/RocketMQSpecificPropertiesProvider.java @@ -1,11 +1,11 @@ /* - * Copyright (C) 2018 the original author or authors. + * Copyright 2013-2018 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, diff --git a/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/support/RocketMQMessageConverterSupport.java b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/support/RocketMQMessageConverterSupport.java index d4b62e5fa..0509805ea 100644 --- a/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/support/RocketMQMessageConverterSupport.java +++ b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/support/RocketMQMessageConverterSupport.java @@ -1,11 +1,11 @@ /* - * Copyright (C) 2018 the original author or authors. + * Copyright 2013-2018 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -36,10 +36,12 @@ import org.springframework.util.MimeTypeUtils; import org.springframework.util.StringUtils; /** - * * @author zkzlx */ -public class RocketMQMessageConverterSupport { +public final class RocketMQMessageConverterSupport { + + private RocketMQMessageConverterSupport() { + } private static final CompositeMessageConverter MESSAGE_CONVERTER = RocketMQBeanContainerCache .getBean(RocketMQMessageConverter.DEFAULT_NAME, diff --git a/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/utils/RocketMQUtils.java b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/utils/RocketMQUtils.java index 85165955d..1aed546a0 100644 --- a/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/utils/RocketMQUtils.java +++ b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/utils/RocketMQUtils.java @@ -1,11 +1,11 @@ /* - * Copyright (C) 2018 the original author or authors. + * Copyright 2013-2018 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -28,11 +28,12 @@ import org.apache.rocketmq.remoting.RPCHook; import org.springframework.util.StringUtils; /** - * TODO Describe what it does - * * @author Jim */ -public class RocketMQUtils { +public final class RocketMQUtils { + + private RocketMQUtils() { + } public static T mergeRocketMQProperties( RocketMQBinderConfigurationProperties binderConfigurationProperties, diff --git a/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/test/java/com/alibaba/cloud/stream/binder/rocketmq/RocketMQAutoConfigurationTests.java b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/test/java/com/alibaba/cloud/stream/binder/rocketmq/RocketMQAutoConfigurationTests.java index 02d0de9f9..f850afb4e 100644 --- a/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/test/java/com/alibaba/cloud/stream/binder/rocketmq/RocketMQAutoConfigurationTests.java +++ b/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/test/java/com/alibaba/cloud/stream/binder/rocketmq/RocketMQAutoConfigurationTests.java @@ -16,8 +16,6 @@ package com.alibaba.cloud.stream.binder.rocketmq; -import java.util.Arrays; - import com.alibaba.cloud.stream.binder.rocketmq.autoconfigurate.RocketMQBinderAutoConfiguration; import com.alibaba.cloud.stream.binder.rocketmq.properties.RocketMQBinderConfigurationProperties; import com.alibaba.cloud.stream.binder.rocketmq.properties.RocketMQExtendedBindingProperties; @@ -61,13 +59,12 @@ public class RocketMQAutoConfigurationTests { .isEqualTo("127.0.0.1:9876,127.0.0.1:9877"); RocketMQExtendedBindingProperties bindingProperties = context .getBean(RocketMQExtendedBindingProperties.class); - assertThat( - bindingProperties.getExtendedConsumerProperties("input2").getSubscription()) - .isEqualTo("tag1"); - assertThat(bindingProperties.getExtendedConsumerProperties("input2").getPush().getOrderly() - ).isFalse(); - assertThat(bindingProperties.getExtendedConsumerProperties("input1") - .getPush().getOrderly()).isTrue(); + assertThat(bindingProperties.getExtendedConsumerProperties("input2") + .getSubscription()).isEqualTo("tag1"); + assertThat(bindingProperties.getExtendedConsumerProperties("input2").getPush() + .getOrderly()).isFalse(); + assertThat(bindingProperties.getExtendedConsumerProperties("input1").getPush() + .getOrderly()).isTrue(); }); }