Commit a2aff61fe3ccbdaa2745868c1334a579bec519f2
1 parent
b2ebdd73
整合阿里云RocketMQ SDK
Showing
14 changed files
with
960 additions
and
1352 deletions
pom.xml
| ... | ... | @@ -60,17 +60,6 @@ |
| 60 | 60 | <artifactId>spring-boot-starter</artifactId> |
| 61 | 61 | </dependency> |
| 62 | 62 | <dependency> |
| 63 | - <groupId>org.apache.rocketmq</groupId> | |
| 64 | - <artifactId>rocketmq-client</artifactId> | |
| 65 | - <version>${rocketmq-version}</version> | |
| 66 | - <exclusions> | |
| 67 | - <exclusion> | |
| 68 | - <groupId>org.slf4j</groupId> | |
| 69 | - <artifactId>slf4j-api</artifactId> | |
| 70 | - </exclusion> | |
| 71 | - </exclusions> | |
| 72 | - </dependency> | |
| 73 | - <dependency> | |
| 74 | 63 | <groupId>com.aliyun.openservices</groupId> |
| 75 | 64 | <artifactId>ons-client</artifactId> |
| 76 | 65 | <version>1.7.2.Final</version> | ... | ... |
src/main/java/org/apache/rocketmq/spring/starter/AliyunRocketMQAutoConfiguration.java
| ... | ... | @@ -22,13 +22,12 @@ import static org.apache.rocketmq.spring.starter.core.DefaultRocketMQListenerCon |
| 22 | 22 | import static org.apache.rocketmq.spring.starter.core.DefaultRocketMQListenerContainerConstants.PROP_CONSUME_MODE; |
| 23 | 23 | import static org.apache.rocketmq.spring.starter.core.DefaultRocketMQListenerContainerConstants.PROP_CONSUME_THREAD_MAX; |
| 24 | 24 | import static org.apache.rocketmq.spring.starter.core.DefaultRocketMQListenerContainerConstants.PROP_MESSAGE_MODEL; |
| 25 | -import static org.apache.rocketmq.spring.starter.core.DefaultRocketMQListenerContainerConstants.PROP_NAMESERVER; | |
| 26 | 25 | import static org.apache.rocketmq.spring.starter.core.DefaultRocketMQListenerContainerConstants.PROP_OBJECT_MAPPER; |
| 27 | 26 | import static org.apache.rocketmq.spring.starter.core.DefaultRocketMQListenerContainerConstants.PROP_ROCKETMQ_LISTENER; |
| 28 | 27 | import static org.apache.rocketmq.spring.starter.core.DefaultRocketMQListenerContainerConstants.PROP_ROCKETMQ_TEMPLATE; |
| 29 | 28 | import static org.apache.rocketmq.spring.starter.core.DefaultRocketMQListenerContainerConstants.PROP_SELECTOR_EXPRESS; |
| 30 | 29 | import static org.apache.rocketmq.spring.starter.core.DefaultRocketMQListenerContainerConstants.PROP_SELECTOR_TYPE; |
| 31 | -import static org.apache.rocketmq.spring.starter.core.DefaultRocketMQListenerContainerConstants.PROP_TOPIC; | |
| 30 | +import static org.apache.rocketmq.spring.starter.core.DefaultRocketMQListenerContainerConstants.*; | |
| 32 | 31 | |
| 33 | 32 | import java.util.Map; |
| 34 | 33 | import java.util.Objects; |
| ... | ... | @@ -39,7 +38,6 @@ import javax.annotation.Resource; |
| 39 | 38 | |
| 40 | 39 | import org.apache.rocketmq.spring.starter.annotation.RocketMQMessageListener; |
| 41 | 40 | import org.apache.rocketmq.spring.starter.core.AliyunRocketMQListenerContainer; |
| 42 | -import org.apache.rocketmq.spring.starter.core.DefaultRocketMQListenerContainer; | |
| 43 | 41 | import org.apache.rocketmq.spring.starter.core.RocketMQListener; |
| 44 | 42 | import org.apache.rocketmq.spring.starter.core.RocketMQTemplate; |
| 45 | 43 | import org.springframework.aop.support.AopUtils; |
| ... | ... | @@ -72,7 +70,6 @@ import lombok.extern.slf4j.Slf4j; |
| 72 | 70 | |
| 73 | 71 | @Configuration |
| 74 | 72 | @EnableConfigurationProperties(RocketMQProperties.class) |
| 75 | -@ConditionalOnProperty(name = "spring.rocketmq.aliyun",havingValue="true") | |
| 76 | 73 | @Order |
| 77 | 74 | @Slf4j |
| 78 | 75 | public class AliyunRocketMQAutoConfiguration { |
| ... | ... | @@ -80,23 +77,27 @@ public class AliyunRocketMQAutoConfiguration { |
| 80 | 77 | @Bean |
| 81 | 78 | @ConditionalOnClass(Producer.class) |
| 82 | 79 | @ConditionalOnMissingBean(Producer.class) |
| 83 | - @ConditionalOnProperty(prefix = "spring.rocketmq", value = {"nameServer", "producer.group"}) | |
| 80 | + @ConditionalOnProperty(prefix = "spring.rocketmq", value = {"environmentPrefix", "producer.group"}) | |
| 84 | 81 | public Producer mqProducer(RocketMQProperties rocketMQProperties) { |
| 85 | 82 | |
| 86 | 83 | RocketMQProperties.Producer producerConfig = rocketMQProperties.getProducer(); |
| 87 | 84 | String groupName = producerConfig.getGroup(); |
| 88 | 85 | Assert.hasText(groupName, "[spring.rocketmq.producer.group] must not be null"); |
| 89 | 86 | String accessKey = rocketMQProperties.getAccessKey(); |
| 90 | - Assert.hasText(accessKey, "[spring.rocketmq.producer.accessKey] must not be null"); | |
| 87 | + Assert.hasText(accessKey, "[spring.rocketmq.accessKey] must not be null"); | |
| 91 | 88 | String secretKey = rocketMQProperties.getSecretKey(); |
| 92 | - Assert.hasText(secretKey, "[spring.rocketmq.producer.secretKey] must not be null"); | |
| 89 | + Assert.hasText(secretKey, "[spring.rocketmq.secretKey] must not be null"); | |
| 90 | + String onsAddr = rocketMQProperties.getOnsAddr(); | |
| 91 | + Assert.hasText(secretKey, "[spring.rocketmq.onsAddr] must not be null"); | |
| 92 | + String environmentPrefix = rocketMQProperties.getEnvironmentPrefix(); | |
| 93 | + Assert.hasText(secretKey, "[spring.rocketmq.environmentPrefix] must not be null"); | |
| 93 | 94 | |
| 94 | 95 | Properties producerProperties = new Properties(); |
| 95 | - producerProperties.setProperty(PropertyKeyConst.ProducerId, "PID_"+groupName); | |
| 96 | + //生成者ProducerId添加前缀:PID_+环境标识_+groupName | |
| 97 | + producerProperties.setProperty(PropertyKeyConst.ProducerId, "PID_"+environmentPrefix+"_"+groupName); | |
| 96 | 98 | producerProperties.setProperty(PropertyKeyConst.AccessKey, accessKey); |
| 97 | 99 | producerProperties.setProperty(PropertyKeyConst.SecretKey, secretKey); |
| 98 | - producerProperties.setProperty(PropertyKeyConst.ONSAddr, rocketMQProperties.getNameServer()); | |
| 99 | - | |
| 100 | + producerProperties.setProperty(PropertyKeyConst.ONSAddr, onsAddr); | |
| 100 | 101 | Producer producer = ONSFactory.createProducer(producerProperties); |
| 101 | 102 | return producer; |
| 102 | 103 | } |
| ... | ... | @@ -111,12 +112,13 @@ public class AliyunRocketMQAutoConfiguration { |
| 111 | 112 | @Bean(destroyMethod = "destroy") |
| 112 | 113 | @ConditionalOnBean(Producer.class) |
| 113 | 114 | @ConditionalOnMissingBean(name = "rocketMQTemplate") |
| 114 | - public RocketMQTemplate rocketMQTemplate(Producer mqProducer, | |
| 115 | + public RocketMQTemplate rocketMQTemplate(Producer mqProducer,RocketMQProperties rocketMQProperties, | |
| 115 | 116 | @Autowired(required = false) |
| 116 | 117 | @Qualifier("rocketMQMessageObjectMapper") |
| 117 | 118 | ObjectMapper objectMapper) { |
| 118 | 119 | RocketMQTemplate rocketMQTemplate = new RocketMQTemplate(); |
| 119 | 120 | rocketMQTemplate.setAliyunProducer(mqProducer); |
| 121 | + rocketMQTemplate.setEnvironmentPrefix(rocketMQProperties.getEnvironmentPrefix()); | |
| 120 | 122 | if (Objects.nonNull(objectMapper)) { |
| 121 | 123 | rocketMQTemplate.setObjectMapper(objectMapper); |
| 122 | 124 | } |
| ... | ... | @@ -176,10 +178,11 @@ public class AliyunRocketMQAutoConfiguration { |
| 176 | 178 | RocketMQListener rocketMQListener = (RocketMQListener) bean; |
| 177 | 179 | RocketMQMessageListener annotation = clazz.getAnnotation(RocketMQMessageListener.class); |
| 178 | 180 | BeanDefinitionBuilder beanBuilder = BeanDefinitionBuilder.rootBeanDefinition(AliyunRocketMQListenerContainer.class); |
| 179 | - beanBuilder.addPropertyValue(PROP_NAMESERVER, rocketMQProperties.getNameServer()); | |
| 180 | - beanBuilder.addPropertyValue(PROP_TOPIC, environment.resolvePlaceholders(annotation.topic())); | |
| 181 | + beanBuilder.addPropertyValue(PROP_ONS_Addr, rocketMQProperties.getOnsAddr()); | |
| 182 | + beanBuilder.addPropertyValue(PROP_TOPIC, rocketMQProperties.getEnvironmentPrefix()+"_"+environment.resolvePlaceholders(annotation.topic())); | |
| 181 | 183 | |
| 182 | - beanBuilder.addPropertyValue(PROP_CONSUMER_GROUP, environment.resolvePlaceholders(annotation.consumerGroup())); | |
| 184 | + //消费者ConsumerId添加前缀:PID_+环境标识_+groupName | |
| 185 | + beanBuilder.addPropertyValue(PROP_CONSUMER_GROUP, "CID_"+rocketMQProperties.getEnvironmentPrefix()+"_"+environment.resolvePlaceholders(annotation.consumerGroup())); | |
| 183 | 186 | beanBuilder.addPropertyValue(PROP_CONSUME_MODE, annotation.consumeMode()); |
| 184 | 187 | beanBuilder.addPropertyValue(PROP_CONSUME_THREAD_MAX, annotation.consumeThreadMax()); |
| 185 | 188 | beanBuilder.addPropertyValue(PROP_MESSAGE_MODEL, annotation.messageModel()); |
| ... | ... | @@ -187,13 +190,14 @@ public class AliyunRocketMQAutoConfiguration { |
| 187 | 190 | beanBuilder.addPropertyValue(PROP_SELECTOR_TYPE, annotation.selectorType()); |
| 188 | 191 | beanBuilder.addPropertyValue(PROP_ROCKETMQ_LISTENER, rocketMQListener); |
| 189 | 192 | beanBuilder.addPropertyValue(PROP_ROCKETMQ_TEMPLATE, rocketMQTemplate); |
| 193 | + beanBuilder.addPropertyValue(PROP_ENVIRONMENT_PREFIX, rocketMQProperties.getEnvironmentPrefix()); | |
| 190 | 194 | if (Objects.nonNull(objectMapper)) { |
| 191 | 195 | beanBuilder.addPropertyValue(PROP_OBJECT_MAPPER, objectMapper); |
| 192 | 196 | } |
| 193 | 197 | beanBuilder.setDestroyMethodName(METHOD_DESTROY); |
| 194 | 198 | //增加阿里云key |
| 195 | - beanBuilder.addPropertyValue("accessKey", rocketMQProperties.getAccessKey()); | |
| 196 | - beanBuilder.addPropertyValue("secretKey", rocketMQProperties.getSecretKey()); | |
| 199 | + beanBuilder.addPropertyValue(PROP_ACCESS_KEY, rocketMQProperties.getAccessKey()); | |
| 200 | + beanBuilder.addPropertyValue(PROP_SECRET_KEY, rocketMQProperties.getSecretKey()); | |
| 197 | 201 | |
| 198 | 202 | String containerBeanName = String.format("%s_%s", AliyunRocketMQListenerContainer.class.getName(), counter.incrementAndGet()); |
| 199 | 203 | DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) applicationContext.getBeanFactory(); | ... | ... |
src/main/java/org/apache/rocketmq/spring/starter/RocketMQAutoConfiguration.java deleted
| 1 | -/* | |
| 2 | - * Licensed to the Apache Software Foundation (ASF) under one or more | |
| 3 | - * contributor license agreements. See the NOTICE file distributed with | |
| 4 | - * this work for additional information regarding copyright ownership. | |
| 5 | - * The ASF licenses this file to You under the Apache License, Version 2.0 | |
| 6 | - * (the "License"); you may not use this file except in compliance with | |
| 7 | - * the License. You may obtain a copy of the License at | |
| 8 | - * | |
| 9 | - * http://www.apache.org/licenses/LICENSE-2.0 | |
| 10 | - * | |
| 11 | - * Unless required by applicable law or agreed to in writing, software | |
| 12 | - * distributed under the License is distributed on an "AS IS" BASIS, | |
| 13 | - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| 14 | - * See the License for the specific language governing permissions and | |
| 15 | - * limitations under the License. | |
| 16 | - */ | |
| 17 | - | |
| 18 | -package org.apache.rocketmq.spring.starter; | |
| 19 | - | |
| 20 | -import com.fasterxml.jackson.databind.ObjectMapper; | |
| 21 | -import org.apache.rocketmq.spring.starter.annotation.RocketMQMessageListener; | |
| 22 | -import org.apache.rocketmq.spring.starter.core.DefaultRocketMQListenerContainer; | |
| 23 | -import org.apache.rocketmq.spring.starter.core.RocketMQListener; | |
| 24 | -import org.apache.rocketmq.spring.starter.core.RocketMQTemplate; | |
| 25 | -import java.util.Map; | |
| 26 | -import java.util.Objects; | |
| 27 | -import java.util.concurrent.atomic.AtomicLong; | |
| 28 | -import javax.annotation.Resource; | |
| 29 | -import lombok.extern.slf4j.Slf4j; | |
| 30 | -import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer; | |
| 31 | -import org.apache.rocketmq.client.impl.MQClientAPIImpl; | |
| 32 | -import org.apache.rocketmq.client.producer.DefaultMQProducer; | |
| 33 | -import org.springframework.aop.support.AopUtils; | |
| 34 | -import org.springframework.beans.BeansException; | |
| 35 | -import org.springframework.beans.factory.InitializingBean; | |
| 36 | -import org.springframework.beans.factory.annotation.Autowired; | |
| 37 | -import org.springframework.beans.factory.annotation.Qualifier; | |
| 38 | -import org.springframework.beans.factory.support.BeanDefinitionBuilder; | |
| 39 | -import org.springframework.beans.factory.support.DefaultListableBeanFactory; | |
| 40 | -import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; | |
| 41 | -import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; | |
| 42 | -import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; | |
| 43 | -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; | |
| 44 | -import org.springframework.boot.context.properties.EnableConfigurationProperties; | |
| 45 | -import org.springframework.context.ApplicationContext; | |
| 46 | -import org.springframework.context.ApplicationContextAware; | |
| 47 | -import org.springframework.context.ConfigurableApplicationContext; | |
| 48 | -import org.springframework.context.annotation.Bean; | |
| 49 | -import org.springframework.context.annotation.Configuration; | |
| 50 | -import org.springframework.core.annotation.Order; | |
| 51 | -import org.springframework.core.env.StandardEnvironment; | |
| 52 | -import org.springframework.util.Assert; | |
| 53 | - | |
| 54 | -import static org.apache.rocketmq.spring.starter.core.DefaultRocketMQListenerContainerConstants.*; | |
| 55 | - | |
| 56 | -@Configuration | |
| 57 | -@ConditionalOnProperty(name = "spring.rocketmq.aliyun",havingValue="false") | |
| 58 | -@EnableConfigurationProperties(RocketMQProperties.class) | |
| 59 | -@ConditionalOnClass(MQClientAPIImpl.class) | |
| 60 | -@Order | |
| 61 | -@Slf4j | |
| 62 | -public class RocketMQAutoConfiguration { | |
| 63 | - | |
| 64 | - @Bean | |
| 65 | - @ConditionalOnClass(DefaultMQProducer.class) | |
| 66 | - @ConditionalOnMissingBean(DefaultMQProducer.class) | |
| 67 | - @ConditionalOnProperty(prefix = "spring.rocketmq", value = {"nameServer", "producer.group"}) | |
| 68 | - public DefaultMQProducer mqProducer(RocketMQProperties rocketMQProperties) { | |
| 69 | - | |
| 70 | - RocketMQProperties.Producer producerConfig = rocketMQProperties.getProducer(); | |
| 71 | - String groupName = producerConfig.getGroup(); | |
| 72 | - Assert.hasText(groupName, "[spring.rocketmq.producer.group] must not be null"); | |
| 73 | - | |
| 74 | - DefaultMQProducer producer = new DefaultMQProducer(producerConfig.getGroup()); | |
| 75 | - producer.setNamesrvAddr(rocketMQProperties.getNameServer()); | |
| 76 | - producer.setSendMsgTimeout(producerConfig.getSendMsgTimeout()); | |
| 77 | - producer.setRetryTimesWhenSendFailed(producerConfig.getRetryTimesWhenSendFailed()); | |
| 78 | - producer.setRetryTimesWhenSendAsyncFailed(producerConfig.getRetryTimesWhenSendAsyncFailed()); | |
| 79 | - producer.setMaxMessageSize(producerConfig.getMaxMessageSize()); | |
| 80 | - producer.setCompressMsgBodyOverHowmuch(producerConfig.getCompressMsgBodyOverHowmuch()); | |
| 81 | - producer.setRetryAnotherBrokerWhenNotStoreOK(producerConfig.isRetryAnotherBrokerWhenNotStoreOk()); | |
| 82 | - | |
| 83 | - return producer; | |
| 84 | - } | |
| 85 | - | |
| 86 | - @Bean | |
| 87 | - @ConditionalOnClass(ObjectMapper.class) | |
| 88 | - @ConditionalOnMissingBean(name = "rocketMQMessageObjectMapper") | |
| 89 | - public ObjectMapper rocketMQMessageObjectMapper() { | |
| 90 | - return new ObjectMapper(); | |
| 91 | - } | |
| 92 | - | |
| 93 | - @Bean(destroyMethod = "destroy") | |
| 94 | - @ConditionalOnBean(DefaultMQProducer.class) | |
| 95 | - @ConditionalOnMissingBean(name = "rocketMQTemplate") | |
| 96 | - public RocketMQTemplate rocketMQTemplate(DefaultMQProducer mqProducer, | |
| 97 | - @Autowired(required = false) | |
| 98 | - @Qualifier("rocketMQMessageObjectMapper") | |
| 99 | - ObjectMapper objectMapper) { | |
| 100 | - RocketMQTemplate rocketMQTemplate = new RocketMQTemplate(); | |
| 101 | - rocketMQTemplate.setDefaultProducer(mqProducer); | |
| 102 | - if (Objects.nonNull(objectMapper)) { | |
| 103 | - rocketMQTemplate.setObjectMapper(objectMapper); | |
| 104 | - } | |
| 105 | - | |
| 106 | - return rocketMQTemplate; | |
| 107 | - } | |
| 108 | - | |
| 109 | - @Configuration | |
| 110 | - @ConditionalOnClass(DefaultMQPushConsumer.class) | |
| 111 | - @EnableConfigurationProperties(RocketMQProperties.class) | |
| 112 | - @ConditionalOnProperty(prefix = "spring.rocketmq", value = "nameServer") | |
| 113 | - @Order | |
| 114 | - public static class ListenerContainerConfiguration implements ApplicationContextAware, InitializingBean { | |
| 115 | - private ConfigurableApplicationContext applicationContext; | |
| 116 | - | |
| 117 | - private AtomicLong counter = new AtomicLong(0); | |
| 118 | - | |
| 119 | - @Resource | |
| 120 | - private StandardEnvironment environment; | |
| 121 | - | |
| 122 | - @Resource | |
| 123 | - private RocketMQProperties rocketMQProperties; | |
| 124 | - | |
| 125 | - private ObjectMapper objectMapper; | |
| 126 | - | |
| 127 | - @Autowired | |
| 128 | - private RocketMQTemplate rocketMQTemplate; | |
| 129 | - | |
| 130 | - public ListenerContainerConfiguration() { | |
| 131 | - } | |
| 132 | - | |
| 133 | - @Autowired(required = false) | |
| 134 | - public ListenerContainerConfiguration( | |
| 135 | - @Qualifier("rocketMQMessageObjectMapper") ObjectMapper objectMapper) { | |
| 136 | - this.objectMapper = objectMapper; | |
| 137 | - } | |
| 138 | - | |
| 139 | - @Override | |
| 140 | - public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { | |
| 141 | - this.applicationContext = (ConfigurableApplicationContext) applicationContext; | |
| 142 | - } | |
| 143 | - | |
| 144 | - @Override | |
| 145 | - public void afterPropertiesSet() { | |
| 146 | - Map<String, Object> beans = this.applicationContext.getBeansWithAnnotation(RocketMQMessageListener.class); | |
| 147 | - | |
| 148 | - if (Objects.nonNull(beans)) { | |
| 149 | - beans.forEach(this::registerContainer); | |
| 150 | - } | |
| 151 | - } | |
| 152 | - | |
| 153 | - private void registerContainer(String beanName, Object bean) { | |
| 154 | - Class<?> clazz = AopUtils.getTargetClass(bean); | |
| 155 | - | |
| 156 | - if (!RocketMQListener.class.isAssignableFrom(bean.getClass())) { | |
| 157 | - throw new IllegalStateException(clazz + " is not instance of " + RocketMQListener.class.getName()); | |
| 158 | - } | |
| 159 | - | |
| 160 | - RocketMQListener rocketMQListener = (RocketMQListener) bean; | |
| 161 | - RocketMQMessageListener annotation = clazz.getAnnotation(RocketMQMessageListener.class); | |
| 162 | - BeanDefinitionBuilder beanBuilder = BeanDefinitionBuilder.rootBeanDefinition(DefaultRocketMQListenerContainer.class); | |
| 163 | - beanBuilder.addPropertyValue(PROP_NAMESERVER, rocketMQProperties.getNameServer()); | |
| 164 | - beanBuilder.addPropertyValue(PROP_TOPIC, environment.resolvePlaceholders(annotation.topic())); | |
| 165 | - | |
| 166 | - beanBuilder.addPropertyValue(PROP_CONSUMER_GROUP, environment.resolvePlaceholders(annotation.consumerGroup())); | |
| 167 | - beanBuilder.addPropertyValue(PROP_CONSUME_MODE, annotation.consumeMode()); | |
| 168 | - beanBuilder.addPropertyValue(PROP_CONSUME_THREAD_MAX, annotation.consumeThreadMax()); | |
| 169 | - beanBuilder.addPropertyValue(PROP_MESSAGE_MODEL, annotation.messageModel()); | |
| 170 | - beanBuilder.addPropertyValue(PROP_SELECTOR_EXPRESS, environment.resolvePlaceholders(annotation.selectorExpress())); | |
| 171 | - beanBuilder.addPropertyValue(PROP_SELECTOR_TYPE, annotation.selectorType()); | |
| 172 | - beanBuilder.addPropertyValue(PROP_ROCKETMQ_LISTENER, rocketMQListener); | |
| 173 | - beanBuilder.addPropertyValue(PROP_ROCKETMQ_TEMPLATE, rocketMQTemplate); | |
| 174 | - if (Objects.nonNull(objectMapper)) { | |
| 175 | - beanBuilder.addPropertyValue(PROP_OBJECT_MAPPER, objectMapper); | |
| 176 | - } | |
| 177 | - beanBuilder.setDestroyMethodName(METHOD_DESTROY); | |
| 178 | - | |
| 179 | - String containerBeanName = String.format("%s_%s", DefaultRocketMQListenerContainer.class.getName(), counter.incrementAndGet()); | |
| 180 | - DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) applicationContext.getBeanFactory(); | |
| 181 | - beanFactory.registerBeanDefinition(containerBeanName, beanBuilder.getBeanDefinition()); | |
| 182 | - | |
| 183 | - DefaultRocketMQListenerContainer container = beanFactory.getBean(containerBeanName, DefaultRocketMQListenerContainer.class); | |
| 184 | - | |
| 185 | - if (!container.isStarted()) { | |
| 186 | - try { | |
| 187 | - container.start(); | |
| 188 | - } catch (Exception e) { | |
| 189 | - log.error("started container failed. {}", container, e); | |
| 190 | - throw new RuntimeException(e); | |
| 191 | - } | |
| 192 | - } | |
| 193 | - | |
| 194 | - log.info("register rocketMQ listener to container, listenerBeanName:{}, containerBeanName:{}", beanName, containerBeanName); | |
| 195 | - } | |
| 196 | - } | |
| 197 | -} |
src/main/java/org/apache/rocketmq/spring/starter/RocketMQProperties.java
| ... | ... | @@ -24,22 +24,25 @@ import org.springframework.boot.context.properties.ConfigurationProperties; |
| 24 | 24 | @ConfigurationProperties(prefix = "spring.rocketmq") |
| 25 | 25 | @Data |
| 26 | 26 | public class RocketMQProperties { |
| 27 | - | |
| 28 | - /** | |
| 29 | - * name server for rocketMQ, formats: `host:port;host:port` | |
| 27 | + /** | |
| 28 | + * 环境前缀 | |
| 29 | + */ | |
| 30 | + private String environmentPrefix; | |
| 31 | + /** | |
| 32 | + * 消息队列服务接入点 | |
| 30 | 33 | */ |
| 31 | - private String nameServer; | |
| 34 | + private String onsAddr; | |
| 32 | 35 | |
| 33 | - private Producer producer; | |
| 34 | - /** | |
| 35 | - * 阿里云分配的accesskey | |
| 36 | + /** | |
| 37 | + * AccessKey, 用于标识、校验用户身份 | |
| 36 | 38 | */ |
| 37 | 39 | private String accessKey; |
| 38 | 40 | /** |
| 39 | - * 阿里云分配的secretKey | |
| 41 | + * SecretKey, 用于标识、校验用户身份 | |
| 40 | 42 | */ |
| 41 | 43 | private String secretKey; |
| 42 | 44 | |
| 45 | + private Producer producer; | |
| 43 | 46 | @Data |
| 44 | 47 | public static class Producer { |
| 45 | 48 | ... | ... |
src/main/java/org/apache/rocketmq/spring/starter/annotation/RocketMQMessageListener.java
| ... | ... | @@ -17,15 +17,17 @@ |
| 17 | 17 | |
| 18 | 18 | package org.apache.rocketmq.spring.starter.annotation; |
| 19 | 19 | |
| 20 | -import org.apache.rocketmq.common.filter.ExpressionType; | |
| 21 | -import org.apache.rocketmq.spring.starter.enums.ConsumeMode; | |
| 22 | -import org.apache.rocketmq.spring.starter.enums.SelectorType; | |
| 23 | 20 | import java.lang.annotation.Documented; |
| 24 | 21 | import java.lang.annotation.ElementType; |
| 25 | 22 | import java.lang.annotation.Retention; |
| 26 | 23 | import java.lang.annotation.RetentionPolicy; |
| 27 | 24 | import java.lang.annotation.Target; |
| 28 | -import org.apache.rocketmq.common.protocol.heartbeat.MessageModel; | |
| 25 | + | |
| 26 | +import org.apache.rocketmq.spring.starter.enums.ConsumeMode; | |
| 27 | +import org.apache.rocketmq.spring.starter.enums.SelectorType; | |
| 28 | + | |
| 29 | +import com.aliyun.openservices.ons.api.ExpressionType; | |
| 30 | +import com.aliyun.openservices.shade.com.alibaba.rocketmq.common.protocol.heartbeat.MessageModel; | |
| 29 | 31 | |
| 30 | 32 | @Target(ElementType.TYPE) |
| 31 | 33 | @Retention(RetentionPolicy.RUNTIME) | ... | ... |
src/main/java/org/apache/rocketmq/spring/starter/core/AliyunRocketMQListenerContainer.java
| ... | ... | @@ -25,38 +25,39 @@ import java.util.List; |
| 25 | 25 | import java.util.Objects; |
| 26 | 26 | import java.util.Properties; |
| 27 | 27 | |
| 28 | -import org.apache.commons.lang3.StringUtils; | |
| 29 | -import org.apache.commons.lang3.exception.ExceptionUtils; | |
| 30 | -import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer; | |
| 31 | -import org.apache.rocketmq.client.consumer.MessageSelector; | |
| 32 | -import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyContext; | |
| 33 | -import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyStatus; | |
| 34 | -import org.apache.rocketmq.client.consumer.listener.ConsumeOrderlyContext; | |
| 35 | -import org.apache.rocketmq.client.consumer.listener.ConsumeOrderlyStatus; | |
| 36 | -import org.apache.rocketmq.client.exception.MQClientException; | |
| 37 | -import org.apache.rocketmq.common.message.MessageExt; | |
| 38 | -import org.apache.rocketmq.common.protocol.heartbeat.MessageModel; | |
| 39 | 28 | import org.apache.rocketmq.spring.starter.enums.ConsumeMode; |
| 40 | 29 | import org.apache.rocketmq.spring.starter.enums.SelectorType; |
| 41 | 30 | import org.apache.rocketmq.spring.starter.exception.ConvertMsgException; |
| 42 | 31 | import org.apache.rocketmq.spring.starter.msgvo.ConsumeFailedMsgVO; |
| 32 | +import org.apache.rocketmq.spring.starter.utils.ExceptionUtil; | |
| 43 | 33 | import org.apache.rocketmq.spring.starter.utils.IPUtil; |
| 44 | 34 | import org.springframework.beans.factory.InitializingBean; |
| 45 | 35 | import org.springframework.util.Assert; |
| 36 | +import org.springframework.util.StringUtils; | |
| 46 | 37 | |
| 47 | 38 | import com.aliyun.openservices.ons.api.Action; |
| 48 | 39 | import com.aliyun.openservices.ons.api.ConsumeContext; |
| 49 | 40 | import com.aliyun.openservices.ons.api.Consumer; |
| 50 | 41 | import com.aliyun.openservices.ons.api.Message; |
| 51 | 42 | import com.aliyun.openservices.ons.api.MessageListener; |
| 43 | +import com.aliyun.openservices.ons.api.MessageSelector; | |
| 52 | 44 | import com.aliyun.openservices.ons.api.ONSFactory; |
| 53 | 45 | import com.aliyun.openservices.ons.api.PropertyKeyConst; |
| 54 | 46 | import com.aliyun.openservices.ons.api.batch.BatchConsumer; |
| 55 | -import com.aliyun.openservices.ons.api.bean.BatchConsumerBean; | |
| 47 | +import com.aliyun.openservices.ons.api.batch.BatchMessageListener; | |
| 48 | +import com.aliyun.openservices.ons.api.order.ConsumeOrderContext; | |
| 56 | 49 | import com.aliyun.openservices.ons.api.order.MessageOrderListener; |
| 50 | +import com.aliyun.openservices.ons.api.order.OrderAction; | |
| 57 | 51 | import com.aliyun.openservices.ons.api.order.OrderConsumer; |
| 52 | +import com.aliyun.openservices.shade.com.alibaba.rocketmq.client.consumer.DefaultMQPushConsumer; | |
| 53 | +import com.aliyun.openservices.shade.com.alibaba.rocketmq.client.consumer.listener.ConsumeConcurrentlyStatus; | |
| 54 | +import com.aliyun.openservices.shade.com.alibaba.rocketmq.client.consumer.listener.ConsumeOrderlyContext; | |
| 55 | +import com.aliyun.openservices.shade.com.alibaba.rocketmq.client.consumer.listener.ConsumeOrderlyStatus; | |
| 56 | +import com.aliyun.openservices.shade.com.alibaba.rocketmq.client.exception.MQClientException; | |
| 57 | +import com.aliyun.openservices.shade.com.alibaba.rocketmq.common.message.MessageExt; | |
| 58 | +import com.aliyun.openservices.shade.com.alibaba.rocketmq.common.protocol.heartbeat.MessageModel; | |
| 58 | 59 | import com.fasterxml.jackson.databind.ObjectMapper; |
| 59 | - | |
| 60 | +import static org.apache.rocketmq.spring.starter.core.DefaultRocketMQListenerContainerConstants.*; | |
| 60 | 61 | import lombok.Getter; |
| 61 | 62 | import lombok.Setter; |
| 62 | 63 | import lombok.extern.slf4j.Slf4j; |
| ... | ... | @@ -77,23 +78,13 @@ public class AliyunRocketMQListenerContainer implements InitializingBean, Rocket |
| 77 | 78 | |
| 78 | 79 | @Setter |
| 79 | 80 | @Getter |
| 80 | - private long suspendCurrentQueueTimeMillis = 1000; | |
| 81 | - | |
| 81 | + private String consumerGroup; | |
| 82 | 82 | /** |
| 83 | - * Message consume retry strategy<br> -1,no retry,put into DLQ directly<br> 0,broker control retry frequency<br> | |
| 84 | - * >0,client control retry frequency | |
| 83 | + * 消息队列服务接入点 | |
| 85 | 84 | */ |
| 86 | 85 | @Setter |
| 87 | 86 | @Getter |
| 88 | - private int delayLevelWhenNextConsume = 0; | |
| 89 | - | |
| 90 | - @Setter | |
| 91 | - @Getter | |
| 92 | - private String consumerGroup; | |
| 93 | - | |
| 94 | - @Setter | |
| 95 | - @Getter | |
| 96 | - private String nameServer; | |
| 87 | + private String onsAddr; | |
| 97 | 88 | |
| 98 | 89 | @Setter |
| 99 | 90 | @Getter |
| ... | ... | @@ -141,6 +132,11 @@ public class AliyunRocketMQListenerContainer implements InitializingBean, Rocket |
| 141 | 132 | private BatchConsumer batchConsumer; |
| 142 | 133 | |
| 143 | 134 | private Class messageType; |
| 135 | + /** | |
| 136 | + * 环境前缀 | |
| 137 | + */ | |
| 138 | + @Setter | |
| 139 | + private String environmentPrefix; | |
| 144 | 140 | |
| 145 | 141 | @Setter |
| 146 | 142 | private RocketMQTemplate rocketMQTemplate; |
| ... | ... | @@ -180,66 +176,62 @@ public class AliyunRocketMQListenerContainer implements InitializingBean, Rocket |
| 180 | 176 | |
| 181 | 177 | @SuppressWarnings("unchecked") |
| 182 | 178 | public Action consume(final Message message, final ConsumeContext context){ |
| 183 | - for (MessageExt messageExt : msgs) { | |
| 184 | - Date consumeBeginTime = new Date(); | |
| 185 | - log.debug("received msg: {}", messageExt); | |
| 186 | - try { | |
| 187 | - long now = System.currentTimeMillis(); | |
| 188 | - rocketMQListener.onMessage(doConvertMessage(messageExt)); | |
| 189 | - long costTime = System.currentTimeMillis() - now; | |
| 190 | - log.debug("consume {} cost: {} ms", messageExt.getMsgId(), costTime); | |
| 191 | - } catch (Exception e) { | |
| 192 | - log.warn("consume message failed. messageExt:{}", messageExt, e); | |
| 193 | - context.setDelayLevelWhenNextConsume(delayLevelWhenNextConsume); | |
| 194 | - if(messageExt.getTopic().equals("DATA_COLLECTION_TOPIC") && "ConsumeMsgFailed".equals(messageExt.getTags())){ | |
| 195 | - log.error("消费失败的消息为“保存消费失败日志消息”,不需要记录日志,不需要重新消费,直接返回成功"); | |
| 196 | - return ConsumeConcurrentlyStatus.CONSUME_SUCCESS; | |
| 197 | - } | |
| 198 | - if(e instanceof ConvertMsgException){ | |
| 199 | - log.error("消费失败的原因为转换对象失败,需要记录日志,不需要重新消费,返回消费成功"); | |
| 200 | - //消息消费失败,发送失败消息 | |
| 201 | - this.sendConsumeMsgFailed(messageExt,e,consumeBeginTime); | |
| 202 | - return ConsumeConcurrentlyStatus.CONSUME_SUCCESS; | |
| 203 | - } | |
| 204 | - this.sendConsumeMsgFailed(messageExt,e,consumeBeginTime); | |
| 205 | - return ConsumeConcurrentlyStatus.RECONSUME_LATER; | |
| 179 | + Date consumeBeginTime = new Date(); | |
| 180 | + log.debug("received msg: {}", message); | |
| 181 | + try { | |
| 182 | + long now = consumeBeginTime.getTime(); | |
| 183 | + rocketMQListener.onMessage(doConvertMessage(message)); | |
| 184 | + long costTime = System.currentTimeMillis() - now; | |
| 185 | + log.debug("consume {} cost: {} ms", message.getMsgID(), costTime); | |
| 186 | + } catch (Exception e) { | |
| 187 | + log.warn("consume message failed. message:{}", message, e); | |
| 188 | + if(message.getTopic().equals(environmentPrefix+"_"+CONSUMEFAILED_TOPIC) && CONSUMEFAILED_TAG.equals(message.getTag())){ | |
| 189 | + log.error("消费失败的消息为“保存消费失败日志消息”,不需要记录日志,不需要重新消费,直接返回成功"); | |
| 190 | + return Action.CommitMessage; | |
| 191 | + } | |
| 192 | + if(e instanceof ConvertMsgException){ | |
| 193 | + log.error("消费失败的原因为转换对象失败,需要记录日志,不需要重新消费,返回消费成功"); | |
| 194 | + //消息消费失败,发送失败消息 | |
| 195 | + this.sendConsumeMsgFailed(message,e,consumeBeginTime); | |
| 196 | + return Action.CommitMessage; | |
| 206 | 197 | } |
| 198 | + this.sendConsumeMsgFailed(message,e,consumeBeginTime); | |
| 199 | + return Action.ReconsumeLater; | |
| 207 | 200 | } |
| 208 | - | |
| 209 | - return ConsumeConcurrentlyStatus.CONSUME_SUCCESS; | |
| 201 | + | |
| 202 | + return Action.CommitMessage; | |
| 210 | 203 | } |
| 211 | 204 | /** |
| 212 | 205 | * 发送消息消费失败消息 |
| 213 | - * @param messageExt | |
| 206 | + * @param message | |
| 214 | 207 | * @param e |
| 215 | 208 | * 2018年3月22日 zhaowg |
| 216 | 209 | */ |
| 217 | - private void sendConsumeMsgFailed(MessageExt messageExt, Exception e,Date consumeBeginTime) { | |
| 210 | + private void sendConsumeMsgFailed(Message message, Exception e,Date consumeBeginTime) { | |
| 218 | 211 | log.info("消费消息失败,开始发送消费失败MQ"); |
| 219 | - String topic = "DATA_COLLECTION_TOPIC"; | |
| 220 | - String tag = "ConsumeMsgFailed"; | |
| 212 | + String topic = environmentPrefix+"_"+CONSUMEFAILED_TOPIC; | |
| 213 | + String tag = CONSUMEFAILED_TAG; | |
| 221 | 214 | try{ |
| 222 | 215 | Date consumeEndTime = new Date(); |
| 223 | - String destination = topic+":"+tag; | |
| 224 | 216 | ConsumeFailedMsgVO consumeFailedMsgVO = new ConsumeFailedMsgVO(); |
| 225 | 217 | consumeFailedMsgVO.setConsumeBeginTime(consumeBeginTime); |
| 226 | 218 | consumeFailedMsgVO.setConsumeEndTime(consumeEndTime); |
| 227 | 219 | consumeFailedMsgVO.setConsumeGroup(consumerGroup); |
| 228 | 220 | consumeFailedMsgVO.setConsumeIp(IPUtil.getLocalHost()); |
| 229 | 221 | if(e!=null){ |
| 230 | - String errMsg = ExceptionUtils.getStackTrace(e); | |
| 231 | - if(StringUtils.isNotBlank(errMsg)){ | |
| 222 | + String errMsg = ExceptionUtil.getTrace(e); | |
| 223 | + if(!StringUtils.isEmpty(errMsg)){ | |
| 232 | 224 | //最多保存1024个字符 |
| 233 | 225 | consumeFailedMsgVO.setCunsumerErrMsg(errMsg.substring(0, 1024)); |
| 234 | 226 | } |
| 235 | 227 | } |
| 236 | - consumeFailedMsgVO.setMsg(new String(messageExt.getBody())); | |
| 237 | - consumeFailedMsgVO.setMsgId(messageExt.getMsgId()); | |
| 238 | - consumeFailedMsgVO.setMsgKeys(messageExt.getKeys()); | |
| 239 | - consumeFailedMsgVO.setReconsumeTimes(messageExt.getReconsumeTimes()); | |
| 240 | - consumeFailedMsgVO.setTag(messageExt.getTags()); | |
| 241 | - consumeFailedMsgVO.setTopic(messageExt.getTopic()); | |
| 242 | - rocketMQTemplate.sendOneWay(destination, consumeFailedMsgVO); | |
| 228 | + consumeFailedMsgVO.setMsg(new String(message.getBody())); | |
| 229 | + consumeFailedMsgVO.setMsgId(message.getMsgID()); | |
| 230 | + consumeFailedMsgVO.setMsgKeys(message.getKey()); | |
| 231 | + consumeFailedMsgVO.setReconsumeTimes(message.getReconsumeTimes()); | |
| 232 | + consumeFailedMsgVO.setTag(message.getTag()); | |
| 233 | + consumeFailedMsgVO.setTopic(message.getTopic()); | |
| 234 | + rocketMQTemplate.sendOneWay(topic, tag, consumeFailedMsgVO); | |
| 243 | 235 | log.info("发送消息消费失败MQ成功"); |
| 244 | 236 | }catch(Exception e1){ |
| 245 | 237 | log.info("发送消息消费失败MQ异常",e); |
| ... | ... | @@ -250,50 +242,103 @@ public class AliyunRocketMQListenerContainer implements InitializingBean, Rocket |
| 250 | 242 | |
| 251 | 243 | public class DefaultMessageListenerOrderly implements MessageOrderListener { |
| 252 | 244 | |
| 253 | - @SuppressWarnings("unchecked") | |
| 254 | - public ConsumeOrderlyStatus consumeMessage(List<MessageExt> msgs, ConsumeOrderlyContext context) { | |
| 255 | - for (MessageExt messageExt : msgs) { | |
| 256 | - log.debug("received msg: {}", messageExt); | |
| 257 | - try { | |
| 258 | - long now = System.currentTimeMillis(); | |
| 259 | - rocketMQListener.onMessage(doConvertMessage(messageExt)); | |
| 260 | - long costTime = System.currentTimeMillis() - now; | |
| 261 | - log.info("consume {} cost: {} ms", messageExt.getMsgId(), costTime); | |
| 262 | - } catch (Exception e) { | |
| 263 | - log.warn("consume message failed. messageExt:{}", messageExt, e); | |
| 264 | - context.setSuspendCurrentQueueTimeMillis(suspendCurrentQueueTimeMillis); | |
| 265 | - return ConsumeOrderlyStatus.SUSPEND_CURRENT_QUEUE_A_MOMENT; | |
| 266 | - } | |
| 245 | + @Override | |
| 246 | + public OrderAction consume(Message message, ConsumeOrderContext context) { | |
| 247 | + log.debug("received msg: {}", message); | |
| 248 | + try { | |
| 249 | + long now = System.currentTimeMillis(); | |
| 250 | + rocketMQListener.onMessage(doConvertMessage(message)); | |
| 251 | + long costTime = System.currentTimeMillis() - now; | |
| 252 | + log.info("consume {} cost: {} ms", message.getMsgID(), costTime); | |
| 253 | + } catch (Exception e) { | |
| 254 | + log.warn("consume message failed. message:{}", message, e); | |
| 255 | + return OrderAction.Suspend; | |
| 267 | 256 | } |
| 268 | - | |
| 269 | - return ConsumeOrderlyStatus.SUCCESS; | |
| 270 | - } | |
| 257 | + return OrderAction.Success; | |
| 258 | + } | |
| 259 | + } | |
| 260 | + | |
| 261 | + public class DefaultMessageListenerBatchs implements BatchMessageListener{ | |
| 262 | + | |
| 263 | + @Override | |
| 264 | + public Action consume(List<Message> messages, ConsumeContext context) { | |
| 265 | + for (Message message : messages) { | |
| 266 | + Date consumeBeginTime = new Date(); | |
| 267 | + log.debug("received msg: {}", message); | |
| 268 | + try { | |
| 269 | + long now = consumeBeginTime.getTime(); | |
| 270 | + rocketMQListener.onMessage(doConvertMessage(message)); | |
| 271 | + long costTime = System.currentTimeMillis() - now; | |
| 272 | + log.debug("consume {} cost: {} ms", message.getMsgID(), costTime); | |
| 273 | + } catch (Exception e) { | |
| 274 | + log.warn("consume message failed. message:{}", message, e); | |
| 275 | + if(message.getTopic().equals(environmentPrefix+"_"+CONSUMEFAILED_TOPIC) && CONSUMEFAILED_TAG.equals(message.getTag())){ | |
| 276 | + log.error("消费失败的消息为“保存消费失败日志消息”,不需要记录日志,不需要重新消费,直接返回成功"); | |
| 277 | + continue; | |
| 278 | + } | |
| 279 | + if(e instanceof ConvertMsgException){ | |
| 280 | + log.error("消费失败的原因为转换对象失败,需要记录日志,不需要重新消费,返回消费成功"); | |
| 281 | + //消息消费失败,发送失败消息 | |
| 282 | + this.sendConsumeMsgFailed(message,e,consumeBeginTime); | |
| 283 | + continue; | |
| 284 | + } | |
| 285 | + this.sendConsumeMsgFailed(message,e,consumeBeginTime); | |
| 286 | + return Action.ReconsumeLater; | |
| 287 | + } | |
| 288 | + } | |
| 289 | + return Action.CommitMessage; | |
| 290 | + } | |
| 291 | + | |
| 292 | + /** | |
| 293 | + * 发送消息消费失败消息 | |
| 294 | + * @param message | |
| 295 | + * @param e | |
| 296 | + * 2018年3月22日 zhaowg | |
| 297 | + */ | |
| 298 | + private void sendConsumeMsgFailed(Message message, Exception e,Date consumeBeginTime) { | |
| 299 | + log.info("消费消息失败,开始发送消费失败MQ"); | |
| 300 | + String topic = environmentPrefix+"_"+CONSUMEFAILED_TOPIC; | |
| 301 | + String tag = CONSUMEFAILED_TAG; | |
| 302 | + try{ | |
| 303 | + Date consumeEndTime = new Date(); | |
| 304 | + ConsumeFailedMsgVO consumeFailedMsgVO = new ConsumeFailedMsgVO(); | |
| 305 | + consumeFailedMsgVO.setConsumeBeginTime(consumeBeginTime); | |
| 306 | + consumeFailedMsgVO.setConsumeEndTime(consumeEndTime); | |
| 307 | + consumeFailedMsgVO.setConsumeGroup(consumerGroup); | |
| 308 | + consumeFailedMsgVO.setConsumeIp(IPUtil.getLocalHost()); | |
| 309 | + if(e!=null){ | |
| 310 | + String errMsg = ExceptionUtil.getTrace(e); | |
| 311 | + if(!StringUtils.isEmpty(errMsg)){ | |
| 312 | + //最多保存1024个字符 | |
| 313 | + consumeFailedMsgVO.setCunsumerErrMsg(errMsg.substring(0, 1024)); | |
| 314 | + } | |
| 315 | + } | |
| 316 | + consumeFailedMsgVO.setMsg(new String(message.getBody())); | |
| 317 | + consumeFailedMsgVO.setMsgId(message.getMsgID()); | |
| 318 | + consumeFailedMsgVO.setMsgKeys(message.getKey()); | |
| 319 | + consumeFailedMsgVO.setReconsumeTimes(message.getReconsumeTimes()); | |
| 320 | + consumeFailedMsgVO.setTag(message.getTag()); | |
| 321 | + consumeFailedMsgVO.setTopic(message.getTopic()); | |
| 322 | + rocketMQTemplate.sendOneWay(topic, tag, consumeFailedMsgVO); | |
| 323 | + log.info("发送消息消费失败MQ成功"); | |
| 324 | + }catch(Exception e1){ | |
| 325 | + log.info("发送消息消费失败MQ异常",e); | |
| 326 | + } | |
| 327 | + | |
| 328 | + } | |
| 271 | 329 | } |
| 272 | - | |
| 273 | 330 | @Override |
| 274 | 331 | public void afterPropertiesSet() throws Exception { |
| 275 | 332 | start(); |
| 276 | 333 | } |
| 277 | 334 | |
| 278 | - @Override | |
| 279 | - public String toString() { | |
| 280 | - return "DefaultRocketMQListenerContainer{" + | |
| 281 | - "consumerGroup='" + consumerGroup + '\'' + | |
| 282 | - ", nameServer='" + nameServer + '\'' + | |
| 283 | - ", topic='" + topic + '\'' + | |
| 284 | - ", consumeMode=" + consumeMode + | |
| 285 | - ", selectorType=" + selectorType + | |
| 286 | - ", selectorExpress='" + selectorExpress + '\'' + | |
| 287 | - ", messageModel=" + messageModel + | |
| 288 | - '}'; | |
| 289 | - } | |
| 290 | 335 | |
| 291 | 336 | @SuppressWarnings("unchecked") |
| 292 | - private Object doConvertMessage(MessageExt messageExt) { | |
| 293 | - if (Objects.equals(messageType, MessageExt.class)) { | |
| 294 | - return messageExt; | |
| 337 | + private Object doConvertMessage(Message message) { | |
| 338 | + if (Objects.equals(messageType, Message.class)) { | |
| 339 | + return message; | |
| 295 | 340 | } else { |
| 296 | - String str = new String(messageExt.getBody(), Charset.forName(charset)); | |
| 341 | + String str = new String(message.getBody(), Charset.forName(charset)); | |
| 297 | 342 | if (Objects.equals(messageType, String.class)) { |
| 298 | 343 | return str; |
| 299 | 344 | } else { |
| ... | ... | @@ -335,72 +380,45 @@ public class AliyunRocketMQListenerContainer implements InitializingBean, Rocket |
| 335 | 380 | |
| 336 | 381 | Assert.notNull(rocketMQListener, "Property 'rocketMQListener' is required"); |
| 337 | 382 | Assert.notNull(consumerGroup, "Property 'consumerGroup' is required"); |
| 338 | - Assert.notNull(nameServer, "Property 'nameServer' is required"); | |
| 383 | + Assert.notNull(onsAddr, "Property 'nameServer' is required"); | |
| 339 | 384 | Assert.notNull(topic, "Property 'topic' is required"); |
| 340 | 385 | |
| 341 | 386 | Properties consumerProperties = new Properties(); |
| 342 | - consumerProperties.setProperty(PropertyKeyConst.ConsumerId, "CID_"+consumerGroup); | |
| 387 | + consumerProperties.setProperty(PropertyKeyConst.ConsumerId, consumerGroup); | |
| 343 | 388 | consumerProperties.setProperty(PropertyKeyConst.AccessKey, accessKey); |
| 344 | 389 | consumerProperties.setProperty(PropertyKeyConst.SecretKey, secretKey); |
| 345 | - consumerProperties.setProperty(PropertyKeyConst.ONSAddr, nameServer); | |
| 390 | + consumerProperties.setProperty(PropertyKeyConst.ONSAddr, onsAddr); | |
| 346 | 391 | consumerProperties.setProperty(PropertyKeyConst.ConsumeThreadNums, consumeThreadMax+""); |
| 347 | 392 | consumerProperties.setProperty(PropertyKeyConst.MessageModel, messageModel.getModeCN()); |
| 348 | - //判断是否为批量消费者 | |
| 349 | - boolean isBatchConsume = false; | |
| 350 | 393 | //允许用户自己设置该consumer的一些配置 |
| 351 | - DefaultMQPushConsumer defaultMQPushConsumer = new DefaultMQPushConsumer(); | |
| 352 | - if (rocketMQListener instanceof RocketMQPushConsumerLifecycleListener) { | |
| 353 | - ((RocketMQPushConsumerLifecycleListener) rocketMQListener).prepareStart(defaultMQPushConsumer); | |
| 354 | - isBatchConsume = defaultMQPushConsumer.getConsumeMessageBatchMaxSize()>1; | |
| 394 | + if (rocketMQListener instanceof AliyunRocketMQPushConsumerLifecycleListener) { | |
| 395 | + ((AliyunRocketMQPushConsumerLifecycleListener) rocketMQListener).prepareStart(consumerProperties); | |
| 355 | 396 | } |
| 356 | - | |
| 357 | 397 | switch (consumeMode) { |
| 358 | 398 | case ORDERLY://顺序消息 |
| 359 | 399 | orderConsumer = ONSFactory.createOrderedConsumer(consumerProperties); |
| 360 | 400 | if(selectorType == SelectorType.TAG){ |
| 361 | 401 | orderConsumer.subscribe(topic, selectorExpress, new DefaultMessageListenerOrderly()); |
| 362 | 402 | }else if(selectorType == SelectorType.SQL92){ |
| 363 | - orderConsumer.subscribe(topic, com.aliyun.openservices.ons.api.MessageSelector.bySql(selectorExpress), new DefaultMessageListenerOrderly()); | |
| 403 | + orderConsumer.subscribe(topic, MessageSelector.bySql(selectorExpress), new DefaultMessageListenerOrderly()); | |
| 364 | 404 | } |
| 365 | 405 | break; |
| 366 | 406 | case CONCURRENTLY://普通消息 |
| 367 | - if(isBatchConsume){ | |
| 368 | - //批量消息 | |
| 369 | - | |
| 370 | - } | |
| 371 | - | |
| 372 | 407 | consumer = ONSFactory.createConsumer(consumerProperties); |
| 373 | 408 | if(selectorType == SelectorType.TAG){ |
| 374 | 409 | consumer.subscribe(topic, selectorExpress, new DefaultMessageListenerConcurrently()); |
| 375 | 410 | }else if(selectorType == SelectorType.SQL92){ |
| 376 | - consumer.subscribe(topic, com.aliyun.openservices.ons.api.MessageSelector.bySql(selectorExpress), new DefaultMessageListenerConcurrently()); | |
| 411 | + consumer.subscribe(topic, MessageSelector.bySql(selectorExpress), new DefaultMessageListenerConcurrently()); | |
| 377 | 412 | } |
| 378 | 413 | break; |
| 414 | + case BATCH://批量消息 | |
| 415 | + batchConsumer = ONSFactory.createBatchConsumer(consumerProperties); | |
| 416 | + batchConsumer.subscribe(topic, selectorExpress, new DefaultMessageListenerBatchs()); | |
| 417 | + break; | |
| 379 | 418 | default: |
| 380 | 419 | throw new IllegalArgumentException("Property 'consumeMode' was wrong."); |
| 381 | 420 | } |
| 382 | 421 | |
| 383 | - | |
| 384 | - | |
| 385 | - | |
| 386 | - | |
| 387 | - consumer.subscribe(MqConfig.TOPIC, MqConfig.TAG, new MessageListenerImpl()); | |
| 388 | - consumer.start(); | |
| 389 | - | |
| 390 | - switch (selectorType) { | |
| 391 | - case TAG: | |
| 392 | - consumer.subscribe(topic, selectorExpress); | |
| 393 | - break; | |
| 394 | - case SQL92: | |
| 395 | - consumer.subscribe(topic, MessageSelector.bySql(selectorExpress)); | |
| 396 | - break; | |
| 397 | - default: | |
| 398 | - throw new IllegalArgumentException("Property 'selectorType' was wrong."); | |
| 399 | - } | |
| 400 | - | |
| 401 | - | |
| 402 | - | |
| 403 | - | |
| 404 | 422 | } |
| 405 | 423 | |
| 406 | 424 | } | ... | ... |
src/main/java/org/apache/rocketmq/spring/starter/core/RocketMQPushConsumerLifecycleListener.java renamed to src/main/java/org/apache/rocketmq/spring/starter/core/AliyunRocketMQPushConsumerLifecycleListener.java
| ... | ... | @@ -17,7 +17,7 @@ |
| 17 | 17 | |
| 18 | 18 | package org.apache.rocketmq.spring.starter.core; |
| 19 | 19 | |
| 20 | -import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer; | |
| 20 | +import java.util.Properties; | |
| 21 | 21 | |
| 22 | -public interface RocketMQPushConsumerLifecycleListener extends RocketMQConsumerLifecycleListener<DefaultMQPushConsumer> { | |
| 22 | +public interface AliyunRocketMQPushConsumerLifecycleListener extends RocketMQConsumerLifecycleListener<Properties> { | |
| 23 | 23 | } | ... | ... |
src/main/java/org/apache/rocketmq/spring/starter/core/DefaultRocketMQListenerContainer.java
| 1 | -/* | |
| 2 | - * Licensed to the Apache Software Foundation (ASF) under one or more | |
| 3 | - * contributor license agreements. See the NOTICE file distributed with | |
| 4 | - * this work for additional information regarding copyright ownership. | |
| 5 | - * The ASF licenses this file to You under the Apache License, Version 2.0 | |
| 6 | - * (the "License"); you may not use this file except in compliance with | |
| 7 | - * the License. You may obtain a copy of the License at | |
| 8 | - * | |
| 9 | - * http://www.apache.org/licenses/LICENSE-2.0 | |
| 10 | - * | |
| 11 | - * Unless required by applicable law or agreed to in writing, software | |
| 12 | - * distributed under the License is distributed on an "AS IS" BASIS, | |
| 13 | - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| 14 | - * See the License for the specific language governing permissions and | |
| 15 | - * limitations under the License. | |
| 16 | - */ | |
| 17 | - | |
| 18 | -package org.apache.rocketmq.spring.starter.core; | |
| 19 | - | |
| 20 | -import java.lang.reflect.ParameterizedType; | |
| 21 | -import java.lang.reflect.Type; | |
| 22 | -import java.nio.charset.Charset; | |
| 23 | -import java.util.Date; | |
| 24 | -import java.util.List; | |
| 25 | -import java.util.Objects; | |
| 26 | - | |
| 27 | -import org.apache.commons.lang3.StringUtils; | |
| 28 | -import org.apache.commons.lang3.exception.ExceptionUtils; | |
| 29 | -import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer; | |
| 30 | -import org.apache.rocketmq.client.consumer.MessageSelector; | |
| 31 | -import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyContext; | |
| 32 | -import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyStatus; | |
| 33 | -import org.apache.rocketmq.client.consumer.listener.ConsumeOrderlyContext; | |
| 34 | -import org.apache.rocketmq.client.consumer.listener.ConsumeOrderlyStatus; | |
| 35 | -import org.apache.rocketmq.client.consumer.listener.MessageListenerConcurrently; | |
| 36 | -import org.apache.rocketmq.client.consumer.listener.MessageListenerOrderly; | |
| 37 | -import org.apache.rocketmq.client.exception.MQClientException; | |
| 38 | -import org.apache.rocketmq.common.message.MessageExt; | |
| 39 | -import org.apache.rocketmq.common.protocol.heartbeat.MessageModel; | |
| 40 | -import org.apache.rocketmq.spring.starter.enums.ConsumeMode; | |
| 41 | -import org.apache.rocketmq.spring.starter.enums.SelectorType; | |
| 42 | -import org.apache.rocketmq.spring.starter.exception.ConvertMsgException; | |
| 43 | -import org.apache.rocketmq.spring.starter.msgvo.ConsumeFailedMsgVO; | |
| 44 | -import org.apache.rocketmq.spring.starter.utils.IPUtil; | |
| 45 | -import org.springframework.beans.factory.InitializingBean; | |
| 46 | -import org.springframework.util.Assert; | |
| 47 | - | |
| 48 | -import com.fasterxml.jackson.databind.ObjectMapper; | |
| 49 | - | |
| 50 | -import lombok.Getter; | |
| 51 | -import lombok.Setter; | |
| 52 | -import lombok.extern.slf4j.Slf4j; | |
| 53 | - | |
| 54 | -@SuppressWarnings("WeakerAccess") | |
| 55 | -@Slf4j | |
| 56 | -public class DefaultRocketMQListenerContainer implements InitializingBean, RocketMQListenerContainer { | |
| 57 | - | |
| 58 | - @Setter | |
| 59 | - @Getter | |
| 60 | - private long suspendCurrentQueueTimeMillis = 1000; | |
| 61 | - | |
| 62 | - /** | |
| 63 | - * Message consume retry strategy<br> -1,no retry,put into DLQ directly<br> 0,broker control retry frequency<br> | |
| 64 | - * >0,client control retry frequency | |
| 65 | - */ | |
| 66 | - @Setter | |
| 67 | - @Getter | |
| 68 | - private int delayLevelWhenNextConsume = 0; | |
| 69 | - | |
| 70 | - @Setter | |
| 71 | - @Getter | |
| 72 | - private String consumerGroup; | |
| 73 | - | |
| 74 | - @Setter | |
| 75 | - @Getter | |
| 76 | - private String nameServer; | |
| 77 | - | |
| 78 | - @Setter | |
| 79 | - @Getter | |
| 80 | - private String topic; | |
| 81 | - | |
| 82 | - @Setter | |
| 83 | - @Getter | |
| 84 | - private ConsumeMode consumeMode = ConsumeMode.CONCURRENTLY; | |
| 85 | - | |
| 86 | - @Setter | |
| 87 | - @Getter | |
| 88 | - private SelectorType selectorType = SelectorType.TAG; | |
| 89 | - | |
| 90 | - @Setter | |
| 91 | - @Getter | |
| 92 | - private String selectorExpress = "*"; | |
| 93 | - | |
| 94 | - @Setter | |
| 95 | - @Getter | |
| 96 | - private MessageModel messageModel = MessageModel.CLUSTERING; | |
| 97 | - | |
| 98 | - @Setter | |
| 99 | - @Getter | |
| 100 | - private int consumeThreadMax = 64; | |
| 101 | - | |
| 102 | - @Getter | |
| 103 | - @Setter | |
| 104 | - private String charset = "UTF-8"; | |
| 105 | - | |
| 106 | - @Setter | |
| 107 | - @Getter | |
| 108 | - private ObjectMapper objectMapper = new ObjectMapper(); | |
| 109 | - | |
| 110 | - @Setter | |
| 111 | - @Getter | |
| 112 | - private boolean started; | |
| 113 | - | |
| 114 | - @Setter | |
| 115 | - private RocketMQListener rocketMQListener; | |
| 116 | - | |
| 117 | - private DefaultMQPushConsumer consumer; | |
| 118 | - | |
| 119 | - private Class messageType; | |
| 120 | - | |
| 121 | - @Setter | |
| 122 | - private RocketMQTemplate rocketMQTemplate; | |
| 123 | - | |
| 124 | - public void setupMessageListener(RocketMQListener rocketMQListener) { | |
| 125 | - this.rocketMQListener = rocketMQListener; | |
| 126 | - } | |
| 127 | - | |
| 128 | - @Override | |
| 129 | - public void destroy() { | |
| 130 | - this.setStarted(false); | |
| 131 | - if (Objects.nonNull(consumer)) { | |
| 132 | - consumer.shutdown(); | |
| 133 | - } | |
| 134 | - log.info("container destroyed, {}", this.toString()); | |
| 135 | - } | |
| 136 | - | |
| 137 | - public synchronized void start() throws MQClientException { | |
| 138 | - | |
| 139 | - if (this.isStarted()) { | |
| 140 | - throw new IllegalStateException("container already started. " + this.toString()); | |
| 141 | - } | |
| 142 | - | |
| 143 | - initRocketMQPushConsumer(); | |
| 144 | - | |
| 145 | - // parse message type | |
| 146 | - this.messageType = getMessageType(); | |
| 147 | - log.debug("msgType: {}", messageType.getName()); | |
| 148 | - | |
| 149 | - consumer.start(); | |
| 150 | - this.setStarted(true); | |
| 151 | - | |
| 152 | - log.info("started container: {}", this.toString()); | |
| 153 | - } | |
| 154 | - | |
| 155 | - public class DefaultMessageListenerConcurrently implements MessageListenerConcurrently { | |
| 156 | - | |
| 157 | - @SuppressWarnings("unchecked") | |
| 158 | - public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs, ConsumeConcurrentlyContext context) { | |
| 159 | - for (MessageExt messageExt : msgs) { | |
| 160 | - Date consumeBeginTime = new Date(); | |
| 161 | - log.debug("received msg: {}", messageExt); | |
| 162 | - try { | |
| 163 | - long now = System.currentTimeMillis(); | |
| 164 | - rocketMQListener.onMessage(doConvertMessage(messageExt)); | |
| 165 | - long costTime = System.currentTimeMillis() - now; | |
| 166 | - log.debug("consume {} cost: {} ms", messageExt.getMsgId(), costTime); | |
| 167 | - } catch (Exception e) { | |
| 168 | - log.warn("consume message failed. messageExt:{}", messageExt, e); | |
| 169 | - context.setDelayLevelWhenNextConsume(delayLevelWhenNextConsume); | |
| 170 | - if(messageExt.getTopic().equals("DATA_COLLECTION_TOPIC") && "ConsumeMsgFailed".equals(messageExt.getTags())){ | |
| 171 | - log.error("消费失败的消息为“保存消费失败日志消息”,不需要记录日志,不需要重新消费,直接返回成功"); | |
| 172 | - return ConsumeConcurrentlyStatus.CONSUME_SUCCESS; | |
| 173 | - } | |
| 174 | - if(e instanceof ConvertMsgException){ | |
| 175 | - log.error("消费失败的原因为转换对象失败,需要记录日志,不需要重新消费,返回消费成功"); | |
| 176 | - //消息消费失败,发送失败消息 | |
| 177 | - this.sendConsumeMsgFailed(messageExt,e,consumeBeginTime); | |
| 178 | - return ConsumeConcurrentlyStatus.CONSUME_SUCCESS; | |
| 179 | - } | |
| 180 | - this.sendConsumeMsgFailed(messageExt,e,consumeBeginTime); | |
| 181 | - return ConsumeConcurrentlyStatus.RECONSUME_LATER; | |
| 182 | - } | |
| 183 | - } | |
| 184 | - | |
| 185 | - return ConsumeConcurrentlyStatus.CONSUME_SUCCESS; | |
| 186 | - } | |
| 187 | - /** | |
| 188 | - * 发送消息消费失败消息 | |
| 189 | - * @param messageExt | |
| 190 | - * @param e | |
| 191 | - * 2018年3月22日 zhaowg | |
| 192 | - */ | |
| 193 | - private void sendConsumeMsgFailed(MessageExt messageExt, Exception e,Date consumeBeginTime) { | |
| 194 | - log.info("消费消息失败,开始发送消费失败MQ"); | |
| 195 | - String topic = "DATA_COLLECTION_TOPIC"; | |
| 196 | - String tag = "ConsumeMsgFailed"; | |
| 197 | - try{ | |
| 198 | - Date consumeEndTime = new Date(); | |
| 199 | - String destination = topic+":"+tag; | |
| 200 | - ConsumeFailedMsgVO consumeFailedMsgVO = new ConsumeFailedMsgVO(); | |
| 201 | - consumeFailedMsgVO.setConsumeBeginTime(consumeBeginTime); | |
| 202 | - consumeFailedMsgVO.setConsumeEndTime(consumeEndTime); | |
| 203 | - consumeFailedMsgVO.setConsumeGroup(consumerGroup); | |
| 204 | - consumeFailedMsgVO.setConsumeIp(IPUtil.getLocalHost()); | |
| 205 | - if(e!=null){ | |
| 206 | - String errMsg = ExceptionUtils.getStackTrace(e); | |
| 207 | - if(StringUtils.isNotBlank(errMsg)){ | |
| 208 | - //最多保存1024个字符 | |
| 209 | - consumeFailedMsgVO.setCunsumerErrMsg(errMsg.substring(0, 1024)); | |
| 210 | - } | |
| 211 | - } | |
| 212 | - consumeFailedMsgVO.setMsg(new String(messageExt.getBody())); | |
| 213 | - consumeFailedMsgVO.setMsgId(messageExt.getMsgId()); | |
| 214 | - consumeFailedMsgVO.setMsgKeys(messageExt.getKeys()); | |
| 215 | - consumeFailedMsgVO.setReconsumeTimes(messageExt.getReconsumeTimes()); | |
| 216 | - consumeFailedMsgVO.setTag(messageExt.getTags()); | |
| 217 | - consumeFailedMsgVO.setTopic(messageExt.getTopic()); | |
| 218 | - rocketMQTemplate.sendOneWay(destination, consumeFailedMsgVO); | |
| 219 | - log.info("发送消息消费失败MQ成功"); | |
| 220 | - }catch(Exception e1){ | |
| 221 | - log.info("发送消息消费失败MQ异常",e); | |
| 222 | - } | |
| 223 | - | |
| 224 | - } | |
| 225 | - } | |
| 226 | - | |
| 227 | - public class DefaultMessageListenerOrderly implements MessageListenerOrderly { | |
| 228 | - | |
| 229 | - @SuppressWarnings("unchecked") | |
| 230 | - public ConsumeOrderlyStatus consumeMessage(List<MessageExt> msgs, ConsumeOrderlyContext context) { | |
| 231 | - for (MessageExt messageExt : msgs) { | |
| 232 | - log.debug("received msg: {}", messageExt); | |
| 233 | - try { | |
| 234 | - long now = System.currentTimeMillis(); | |
| 235 | - rocketMQListener.onMessage(doConvertMessage(messageExt)); | |
| 236 | - long costTime = System.currentTimeMillis() - now; | |
| 237 | - log.info("consume {} cost: {} ms", messageExt.getMsgId(), costTime); | |
| 238 | - } catch (Exception e) { | |
| 239 | - log.warn("consume message failed. messageExt:{}", messageExt, e); | |
| 240 | - context.setSuspendCurrentQueueTimeMillis(suspendCurrentQueueTimeMillis); | |
| 241 | - return ConsumeOrderlyStatus.SUSPEND_CURRENT_QUEUE_A_MOMENT; | |
| 242 | - } | |
| 243 | - } | |
| 244 | - | |
| 245 | - return ConsumeOrderlyStatus.SUCCESS; | |
| 246 | - } | |
| 247 | - } | |
| 248 | - | |
| 249 | - @Override | |
| 250 | - public void afterPropertiesSet() throws Exception { | |
| 251 | - start(); | |
| 252 | - } | |
| 253 | - | |
| 254 | - @Override | |
| 255 | - public String toString() { | |
| 256 | - return "DefaultRocketMQListenerContainer{" + | |
| 257 | - "consumerGroup='" + consumerGroup + '\'' + | |
| 258 | - ", nameServer='" + nameServer + '\'' + | |
| 259 | - ", topic='" + topic + '\'' + | |
| 260 | - ", consumeMode=" + consumeMode + | |
| 261 | - ", selectorType=" + selectorType + | |
| 262 | - ", selectorExpress='" + selectorExpress + '\'' + | |
| 263 | - ", messageModel=" + messageModel + | |
| 264 | - '}'; | |
| 265 | - } | |
| 266 | - | |
| 267 | - @SuppressWarnings("unchecked") | |
| 268 | - private Object doConvertMessage(MessageExt messageExt) { | |
| 269 | - if (Objects.equals(messageType, MessageExt.class)) { | |
| 270 | - return messageExt; | |
| 271 | - } else { | |
| 272 | - String str = new String(messageExt.getBody(), Charset.forName(charset)); | |
| 273 | - if (Objects.equals(messageType, String.class)) { | |
| 274 | - return str; | |
| 275 | - } else { | |
| 276 | - // if msgType not string, use objectMapper change it. | |
| 277 | - try { | |
| 278 | - return objectMapper.readValue(str, messageType); | |
| 279 | - } catch (Exception e) { | |
| 280 | - log.info("convert failed. str:{}, msgType:{}", str, messageType); | |
| 281 | - throw new ConvertMsgException("cannot convert message to " + messageType, e); | |
| 282 | - } | |
| 283 | - } | |
| 284 | - } | |
| 285 | - } | |
| 286 | - | |
| 287 | - private Class getMessageType() { | |
| 288 | - Type[] interfaces = rocketMQListener.getClass().getGenericInterfaces(); | |
| 289 | - if (Objects.nonNull(interfaces)) { | |
| 290 | - for (Type type : interfaces) { | |
| 291 | - if (type instanceof ParameterizedType) { | |
| 292 | - ParameterizedType parameterizedType = (ParameterizedType) type; | |
| 293 | - if (Objects.equals(parameterizedType.getRawType(), RocketMQListener.class)) { | |
| 294 | - Type[] actualTypeArguments = parameterizedType.getActualTypeArguments(); | |
| 295 | - if (Objects.nonNull(actualTypeArguments) && actualTypeArguments.length > 0) { | |
| 296 | - return (Class) actualTypeArguments[0]; | |
| 297 | - } else { | |
| 298 | - return Object.class; | |
| 299 | - } | |
| 300 | - } | |
| 301 | - } | |
| 302 | - } | |
| 303 | - | |
| 304 | - return Object.class; | |
| 305 | - } else { | |
| 306 | - return Object.class; | |
| 307 | - } | |
| 308 | - } | |
| 309 | - | |
| 310 | - private void initRocketMQPushConsumer() throws MQClientException { | |
| 311 | - | |
| 312 | - Assert.notNull(rocketMQListener, "Property 'rocketMQListener' is required"); | |
| 313 | - Assert.notNull(consumerGroup, "Property 'consumerGroup' is required"); | |
| 314 | - Assert.notNull(nameServer, "Property 'nameServer' is required"); | |
| 315 | - Assert.notNull(topic, "Property 'topic' is required"); | |
| 316 | - | |
| 317 | - consumer = new DefaultMQPushConsumer(consumerGroup); | |
| 318 | - consumer.setNamesrvAddr(nameServer); | |
| 319 | - consumer.setConsumeThreadMax(consumeThreadMax); | |
| 320 | - if (consumeThreadMax < consumer.getConsumeThreadMin()) { | |
| 321 | - consumer.setConsumeThreadMin(consumeThreadMax); | |
| 322 | - } | |
| 323 | - | |
| 324 | - consumer.setMessageModel(messageModel); | |
| 325 | - | |
| 326 | - switch (selectorType) { | |
| 327 | - case TAG: | |
| 328 | - consumer.subscribe(topic, selectorExpress); | |
| 329 | - break; | |
| 330 | - case SQL92: | |
| 331 | - consumer.subscribe(topic, MessageSelector.bySql(selectorExpress)); | |
| 332 | - break; | |
| 333 | - default: | |
| 334 | - throw new IllegalArgumentException("Property 'selectorType' was wrong."); | |
| 335 | - } | |
| 336 | - | |
| 337 | - switch (consumeMode) { | |
| 338 | - case ORDERLY: | |
| 339 | - consumer.setMessageListener(new DefaultMessageListenerOrderly()); | |
| 340 | - break; | |
| 341 | - case CONCURRENTLY: | |
| 342 | - consumer.setMessageListener(new DefaultMessageListenerConcurrently()); | |
| 343 | - break; | |
| 344 | - default: | |
| 345 | - throw new IllegalArgumentException("Property 'consumeMode' was wrong."); | |
| 346 | - } | |
| 347 | - | |
| 348 | - // provide an entryway to custom setting RocketMQ consumer | |
| 349 | - if (rocketMQListener instanceof RocketMQPushConsumerLifecycleListener) { | |
| 350 | - ((RocketMQPushConsumerLifecycleListener) rocketMQListener).prepareStart(consumer); | |
| 351 | - } | |
| 352 | - | |
| 353 | - } | |
| 354 | - | |
| 355 | -} | |
| 1 | +///* | |
| 2 | +// * Licensed to the Apache Software Foundation (ASF) under one or more | |
| 3 | +// * contributor license agreements. See the NOTICE file distributed with | |
| 4 | +// * this work for additional information regarding copyright ownership. | |
| 5 | +// * The ASF licenses this file to You under the Apache License, Version 2.0 | |
| 6 | +// * (the "License"); you may not use this file except in compliance with | |
| 7 | +// * the License. You may obtain a copy of the License at | |
| 8 | +// * | |
| 9 | +// * http://www.apache.org/licenses/LICENSE-2.0 | |
| 10 | +// * | |
| 11 | +// * Unless required by applicable law or agreed to in writing, software | |
| 12 | +// * distributed under the License is distributed on an "AS IS" BASIS, | |
| 13 | +// * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| 14 | +// * See the License for the specific language governing permissions and | |
| 15 | +// * limitations under the License. | |
| 16 | +// */ | |
| 17 | +// | |
| 18 | +//package org.apache.rocketmq.spring.starter.core; | |
| 19 | +// | |
| 20 | +//import java.lang.reflect.ParameterizedType; | |
| 21 | +//import java.lang.reflect.Type; | |
| 22 | +//import java.nio.charset.Charset; | |
| 23 | +//import java.util.Date; | |
| 24 | +//import java.util.List; | |
| 25 | +//import java.util.Objects; | |
| 26 | +// | |
| 27 | +//import org.apache.commons.lang3.StringUtils; | |
| 28 | +//import org.apache.commons.lang3.exception.ExceptionUtils; | |
| 29 | +//import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer; | |
| 30 | +//import org.apache.rocketmq.client.consumer.MessageSelector; | |
| 31 | +//import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyContext; | |
| 32 | +//import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyStatus; | |
| 33 | +//import org.apache.rocketmq.client.consumer.listener.ConsumeOrderlyContext; | |
| 34 | +//import org.apache.rocketmq.client.consumer.listener.ConsumeOrderlyStatus; | |
| 35 | +//import org.apache.rocketmq.client.consumer.listener.MessageListenerConcurrently; | |
| 36 | +//import org.apache.rocketmq.client.consumer.listener.MessageListenerOrderly; | |
| 37 | +//import org.apache.rocketmq.client.exception.MQClientException; | |
| 38 | +//import org.apache.rocketmq.common.message.MessageExt; | |
| 39 | +//import org.apache.rocketmq.common.protocol.heartbeat.MessageModel; | |
| 40 | +//import org.apache.rocketmq.spring.starter.enums.ConsumeMode; | |
| 41 | +//import org.apache.rocketmq.spring.starter.enums.SelectorType; | |
| 42 | +//import org.apache.rocketmq.spring.starter.exception.ConvertMsgException; | |
| 43 | +//import org.apache.rocketmq.spring.starter.msgvo.ConsumeFailedMsgVO; | |
| 44 | +//import org.apache.rocketmq.spring.starter.utils.IPUtil; | |
| 45 | +//import org.springframework.beans.factory.InitializingBean; | |
| 46 | +//import org.springframework.util.Assert; | |
| 47 | +// | |
| 48 | +//import com.fasterxml.jackson.databind.ObjectMapper; | |
| 49 | +// | |
| 50 | +//import lombok.Getter; | |
| 51 | +//import lombok.Setter; | |
| 52 | +//import lombok.extern.slf4j.Slf4j; | |
| 53 | +// | |
| 54 | +//@SuppressWarnings("WeakerAccess") | |
| 55 | +//@Slf4j | |
| 56 | +//public class DefaultRocketMQListenerContainer implements InitializingBean, RocketMQListenerContainer { | |
| 57 | +// | |
| 58 | +// @Setter | |
| 59 | +// @Getter | |
| 60 | +// private long suspendCurrentQueueTimeMillis = 1000; | |
| 61 | +// | |
| 62 | +// /** | |
| 63 | +// * Message consume retry strategy<br> -1,no retry,put into DLQ directly<br> 0,broker control retry frequency<br> | |
| 64 | +// * >0,client control retry frequency | |
| 65 | +// */ | |
| 66 | +// @Setter | |
| 67 | +// @Getter | |
| 68 | +// private int delayLevelWhenNextConsume = 0; | |
| 69 | +// | |
| 70 | +// @Setter | |
| 71 | +// @Getter | |
| 72 | +// private String consumerGroup; | |
| 73 | +// | |
| 74 | +// @Setter | |
| 75 | +// @Getter | |
| 76 | +// private String nameServer; | |
| 77 | +// | |
| 78 | +// @Setter | |
| 79 | +// @Getter | |
| 80 | +// private String topic; | |
| 81 | +// | |
| 82 | +// @Setter | |
| 83 | +// @Getter | |
| 84 | +// private ConsumeMode consumeMode = ConsumeMode.CONCURRENTLY; | |
| 85 | +// | |
| 86 | +// @Setter | |
| 87 | +// @Getter | |
| 88 | +// private SelectorType selectorType = SelectorType.TAG; | |
| 89 | +// | |
| 90 | +// @Setter | |
| 91 | +// @Getter | |
| 92 | +// private String selectorExpress = "*"; | |
| 93 | +// | |
| 94 | +// @Setter | |
| 95 | +// @Getter | |
| 96 | +// private MessageModel messageModel = MessageModel.CLUSTERING; | |
| 97 | +// | |
| 98 | +// @Setter | |
| 99 | +// @Getter | |
| 100 | +// private int consumeThreadMax = 64; | |
| 101 | +// | |
| 102 | +// @Getter | |
| 103 | +// @Setter | |
| 104 | +// private String charset = "UTF-8"; | |
| 105 | +// | |
| 106 | +// @Setter | |
| 107 | +// @Getter | |
| 108 | +// private ObjectMapper objectMapper = new ObjectMapper(); | |
| 109 | +// | |
| 110 | +// @Setter | |
| 111 | +// @Getter | |
| 112 | +// private boolean started; | |
| 113 | +// | |
| 114 | +// @Setter | |
| 115 | +// private RocketMQListener rocketMQListener; | |
| 116 | +// | |
| 117 | +// private DefaultMQPushConsumer consumer; | |
| 118 | +// | |
| 119 | +// private Class messageType; | |
| 120 | +// | |
| 121 | +// @Setter | |
| 122 | +// private RocketMQTemplate rocketMQTemplate; | |
| 123 | +// | |
| 124 | +// public void setupMessageListener(RocketMQListener rocketMQListener) { | |
| 125 | +// this.rocketMQListener = rocketMQListener; | |
| 126 | +// } | |
| 127 | +// | |
| 128 | +// @Override | |
| 129 | +// public void destroy() { | |
| 130 | +// this.setStarted(false); | |
| 131 | +// if (Objects.nonNull(consumer)) { | |
| 132 | +// consumer.shutdown(); | |
| 133 | +// } | |
| 134 | +// log.info("container destroyed, {}", this.toString()); | |
| 135 | +// } | |
| 136 | +// | |
| 137 | +// public synchronized void start() throws MQClientException { | |
| 138 | +// | |
| 139 | +// if (this.isStarted()) { | |
| 140 | +// throw new IllegalStateException("container already started. " + this.toString()); | |
| 141 | +// } | |
| 142 | +// | |
| 143 | +// initRocketMQPushConsumer(); | |
| 144 | +// | |
| 145 | +// // parse message type | |
| 146 | +// this.messageType = getMessageType(); | |
| 147 | +// log.debug("msgType: {}", messageType.getName()); | |
| 148 | +// | |
| 149 | +// consumer.start(); | |
| 150 | +// this.setStarted(true); | |
| 151 | +// | |
| 152 | +// log.info("started container: {}", this.toString()); | |
| 153 | +// } | |
| 154 | +// | |
| 155 | +// public class DefaultMessageListenerConcurrently implements MessageListenerConcurrently { | |
| 156 | +// | |
| 157 | +// @SuppressWarnings("unchecked") | |
| 158 | +// public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs, ConsumeConcurrentlyContext context) { | |
| 159 | +// for (MessageExt messageExt : msgs) { | |
| 160 | +// Date consumeBeginTime = new Date(); | |
| 161 | +// log.debug("received msg: {}", messageExt); | |
| 162 | +// try { | |
| 163 | +// long now = System.currentTimeMillis(); | |
| 164 | +// rocketMQListener.onMessage(doConvertMessage(messageExt)); | |
| 165 | +// long costTime = System.currentTimeMillis() - now; | |
| 166 | +// log.debug("consume {} cost: {} ms", messageExt.getMsgId(), costTime); | |
| 167 | +// } catch (Exception e) { | |
| 168 | +// log.warn("consume message failed. messageExt:{}", messageExt, e); | |
| 169 | +// context.setDelayLevelWhenNextConsume(delayLevelWhenNextConsume); | |
| 170 | +// if(messageExt.getTopic().equals("DATA_COLLECTION_TOPIC") && "ConsumeMsgFailed".equals(messageExt.getTags())){ | |
| 171 | +// log.error("消费失败的消息为“保存消费失败日志消息”,不需要记录日志,不需要重新消费,直接返回成功"); | |
| 172 | +// return ConsumeConcurrentlyStatus.CONSUME_SUCCESS; | |
| 173 | +// } | |
| 174 | +// if(e instanceof ConvertMsgException){ | |
| 175 | +// log.error("消费失败的原因为转换对象失败,需要记录日志,不需要重新消费,返回消费成功"); | |
| 176 | +// //消息消费失败,发送失败消息 | |
| 177 | +// this.sendConsumeMsgFailed(messageExt,e,consumeBeginTime); | |
| 178 | +// return ConsumeConcurrentlyStatus.CONSUME_SUCCESS; | |
| 179 | +// } | |
| 180 | +// this.sendConsumeMsgFailed(messageExt,e,consumeBeginTime); | |
| 181 | +// return ConsumeConcurrentlyStatus.RECONSUME_LATER; | |
| 182 | +// } | |
| 183 | +// } | |
| 184 | +// | |
| 185 | +// return ConsumeConcurrentlyStatus.CONSUME_SUCCESS; | |
| 186 | +// } | |
| 187 | +// /** | |
| 188 | +// * 发送消息消费失败消息 | |
| 189 | +// * @param messageExt | |
| 190 | +// * @param e | |
| 191 | +// * 2018年3月22日 zhaowg | |
| 192 | +// */ | |
| 193 | +// private void sendConsumeMsgFailed(MessageExt messageExt, Exception e,Date consumeBeginTime) { | |
| 194 | +// log.info("消费消息失败,开始发送消费失败MQ"); | |
| 195 | +// String topic = "DATA_COLLECTION_TOPIC"; | |
| 196 | +// String tag = "ConsumeMsgFailed"; | |
| 197 | +// try{ | |
| 198 | +// Date consumeEndTime = new Date(); | |
| 199 | +// String destination = topic+":"+tag; | |
| 200 | +// ConsumeFailedMsgVO consumeFailedMsgVO = new ConsumeFailedMsgVO(); | |
| 201 | +// consumeFailedMsgVO.setConsumeBeginTime(consumeBeginTime); | |
| 202 | +// consumeFailedMsgVO.setConsumeEndTime(consumeEndTime); | |
| 203 | +// consumeFailedMsgVO.setConsumeGroup(consumerGroup); | |
| 204 | +// consumeFailedMsgVO.setConsumeIp(IPUtil.getLocalHost()); | |
| 205 | +// if(e!=null){ | |
| 206 | +// String errMsg = ExceptionUtils.getStackTrace(e); | |
| 207 | +// if(StringUtils.isNotBlank(errMsg)){ | |
| 208 | +// //最多保存1024个字符 | |
| 209 | +// consumeFailedMsgVO.setCunsumerErrMsg(errMsg.substring(0, 1024)); | |
| 210 | +// } | |
| 211 | +// } | |
| 212 | +// consumeFailedMsgVO.setMsg(new String(messageExt.getBody())); | |
| 213 | +// consumeFailedMsgVO.setMsgId(messageExt.getMsgId()); | |
| 214 | +// consumeFailedMsgVO.setMsgKeys(messageExt.getKeys()); | |
| 215 | +// consumeFailedMsgVO.setReconsumeTimes(messageExt.getReconsumeTimes()); | |
| 216 | +// consumeFailedMsgVO.setTag(messageExt.getTags()); | |
| 217 | +// consumeFailedMsgVO.setTopic(messageExt.getTopic()); | |
| 218 | +// rocketMQTemplate.sendOneWay(destination, consumeFailedMsgVO); | |
| 219 | +// log.info("发送消息消费失败MQ成功"); | |
| 220 | +// }catch(Exception e1){ | |
| 221 | +// log.info("发送消息消费失败MQ异常",e); | |
| 222 | +// } | |
| 223 | +// | |
| 224 | +// } | |
| 225 | +// } | |
| 226 | +// | |
| 227 | +// public class DefaultMessageListenerOrderly implements MessageListenerOrderly { | |
| 228 | +// | |
| 229 | +// @SuppressWarnings("unchecked") | |
| 230 | +// public ConsumeOrderlyStatus consumeMessage(List<MessageExt> msgs, ConsumeOrderlyContext context) { | |
| 231 | +// for (MessageExt messageExt : msgs) { | |
| 232 | +// log.debug("received msg: {}", messageExt); | |
| 233 | +// try { | |
| 234 | +// long now = System.currentTimeMillis(); | |
| 235 | +// rocketMQListener.onMessage(doConvertMessage(messageExt)); | |
| 236 | +// long costTime = System.currentTimeMillis() - now; | |
| 237 | +// log.info("consume {} cost: {} ms", messageExt.getMsgId(), costTime); | |
| 238 | +// } catch (Exception e) { | |
| 239 | +// log.warn("consume message failed. messageExt:{}", messageExt, e); | |
| 240 | +// context.setSuspendCurrentQueueTimeMillis(suspendCurrentQueueTimeMillis); | |
| 241 | +// return ConsumeOrderlyStatus.SUSPEND_CURRENT_QUEUE_A_MOMENT; | |
| 242 | +// } | |
| 243 | +// } | |
| 244 | +// | |
| 245 | +// return ConsumeOrderlyStatus.SUCCESS; | |
| 246 | +// } | |
| 247 | +// } | |
| 248 | +// | |
| 249 | +// @Override | |
| 250 | +// public void afterPropertiesSet() throws Exception { | |
| 251 | +// start(); | |
| 252 | +// } | |
| 253 | +// | |
| 254 | +// @Override | |
| 255 | +// public String toString() { | |
| 256 | +// return "DefaultRocketMQListenerContainer{" + | |
| 257 | +// "consumerGroup='" + consumerGroup + '\'' + | |
| 258 | +// ", nameServer='" + nameServer + '\'' + | |
| 259 | +// ", topic='" + topic + '\'' + | |
| 260 | +// ", consumeMode=" + consumeMode + | |
| 261 | +// ", selectorType=" + selectorType + | |
| 262 | +// ", selectorExpress='" + selectorExpress + '\'' + | |
| 263 | +// ", messageModel=" + messageModel + | |
| 264 | +// '}'; | |
| 265 | +// } | |
| 266 | +// | |
| 267 | +// @SuppressWarnings("unchecked") | |
| 268 | +// private Object doConvertMessage(MessageExt messageExt) { | |
| 269 | +// if (Objects.equals(messageType, MessageExt.class)) { | |
| 270 | +// return messageExt; | |
| 271 | +// } else { | |
| 272 | +// String str = new String(messageExt.getBody(), Charset.forName(charset)); | |
| 273 | +// if (Objects.equals(messageType, String.class)) { | |
| 274 | +// return str; | |
| 275 | +// } else { | |
| 276 | +// // if msgType not string, use objectMapper change it. | |
| 277 | +// try { | |
| 278 | +// return objectMapper.readValue(str, messageType); | |
| 279 | +// } catch (Exception e) { | |
| 280 | +// log.info("convert failed. str:{}, msgType:{}", str, messageType); | |
| 281 | +// throw new ConvertMsgException("cannot convert message to " + messageType, e); | |
| 282 | +// } | |
| 283 | +// } | |
| 284 | +// } | |
| 285 | +// } | |
| 286 | +// | |
| 287 | +// private Class getMessageType() { | |
| 288 | +// Type[] interfaces = rocketMQListener.getClass().getGenericInterfaces(); | |
| 289 | +// if (Objects.nonNull(interfaces)) { | |
| 290 | +// for (Type type : interfaces) { | |
| 291 | +// if (type instanceof ParameterizedType) { | |
| 292 | +// ParameterizedType parameterizedType = (ParameterizedType) type; | |
| 293 | +// if (Objects.equals(parameterizedType.getRawType(), RocketMQListener.class)) { | |
| 294 | +// Type[] actualTypeArguments = parameterizedType.getActualTypeArguments(); | |
| 295 | +// if (Objects.nonNull(actualTypeArguments) && actualTypeArguments.length > 0) { | |
| 296 | +// return (Class) actualTypeArguments[0]; | |
| 297 | +// } else { | |
| 298 | +// return Object.class; | |
| 299 | +// } | |
| 300 | +// } | |
| 301 | +// } | |
| 302 | +// } | |
| 303 | +// | |
| 304 | +// return Object.class; | |
| 305 | +// } else { | |
| 306 | +// return Object.class; | |
| 307 | +// } | |
| 308 | +// } | |
| 309 | +// | |
| 310 | +// private void initRocketMQPushConsumer() throws MQClientException { | |
| 311 | +// | |
| 312 | +// Assert.notNull(rocketMQListener, "Property 'rocketMQListener' is required"); | |
| 313 | +// Assert.notNull(consumerGroup, "Property 'consumerGroup' is required"); | |
| 314 | +// Assert.notNull(nameServer, "Property 'nameServer' is required"); | |
| 315 | +// Assert.notNull(topic, "Property 'topic' is required"); | |
| 316 | +// | |
| 317 | +// consumer = new DefaultMQPushConsumer(consumerGroup); | |
| 318 | +// consumer.setNamesrvAddr(nameServer); | |
| 319 | +// consumer.setConsumeThreadMax(consumeThreadMax); | |
| 320 | +// if (consumeThreadMax < consumer.getConsumeThreadMin()) { | |
| 321 | +// consumer.setConsumeThreadMin(consumeThreadMax); | |
| 322 | +// } | |
| 323 | +// | |
| 324 | +// consumer.setMessageModel(messageModel); | |
| 325 | +// | |
| 326 | +// switch (selectorType) { | |
| 327 | +// case TAG: | |
| 328 | +// consumer.subscribe(topic, selectorExpress); | |
| 329 | +// break; | |
| 330 | +// case SQL92: | |
| 331 | +// consumer.subscribe(topic, MessageSelector.bySql(selectorExpress)); | |
| 332 | +// break; | |
| 333 | +// default: | |
| 334 | +// throw new IllegalArgumentException("Property 'selectorType' was wrong."); | |
| 335 | +// } | |
| 336 | +// | |
| 337 | +// switch (consumeMode) { | |
| 338 | +// case ORDERLY: | |
| 339 | +// consumer.setMessageListener(new DefaultMessageListenerOrderly()); | |
| 340 | +// break; | |
| 341 | +// case CONCURRENTLY: | |
| 342 | +// consumer.setMessageListener(new DefaultMessageListenerConcurrently()); | |
| 343 | +// break; | |
| 344 | +// default: | |
| 345 | +// throw new IllegalArgumentException("Property 'consumeMode' was wrong."); | |
| 346 | +// } | |
| 347 | +// | |
| 348 | +// // provide an entryway to custom setting RocketMQ consumer | |
| 349 | +// if (rocketMQListener instanceof AliyunRocketMQPushConsumerLifecycleListener) { | |
| 350 | +// ((AliyunRocketMQPushConsumerLifecycleListener) rocketMQListener).prepareStart(consumer); | |
| 351 | +// } | |
| 352 | +// | |
| 353 | +// } | |
| 354 | +// | |
| 355 | +//} | ... | ... |
src/main/java/org/apache/rocketmq/spring/starter/core/DefaultRocketMQListenerContainerConstants.java
| ... | ... | @@ -32,6 +32,20 @@ public final class DefaultRocketMQListenerContainerConstants { |
| 32 | 32 | public static final String PROP_ROCKETMQ_LISTENER = "rocketMQListener"; |
| 33 | 33 | public static final String PROP_OBJECT_MAPPER = "objectMapper"; |
| 34 | 34 | public static final String METHOD_DESTROY = "destroy"; |
| 35 | - /**生产者 add zwg*/ | |
| 36 | - public static final String PROP_ROCKETMQ_TEMPLATE = "rocketMQTemplate"; | |
| 35 | + public static final String PROP_ROCKETMQ_TEMPLATE = "rocketMQTemplate"; | |
| 36 | + public static final String PROP_ONS_Addr = "onsAddr"; | |
| 37 | + public static final String PROP_ACCESS_KEY = "accessKey"; | |
| 38 | + public static final String PROP_SECRET_KEY = "secretKey"; | |
| 39 | + /** | |
| 40 | + * 环境前缀 | |
| 41 | + */ | |
| 42 | + public static final String PROP_ENVIRONMENT_PREFIX = "environmentPrefix"; | |
| 43 | + /** | |
| 44 | + * 消息消费失败发送的主题 | |
| 45 | + */ | |
| 46 | + public final static String CONSUMEFAILED_TOPIC = "ZTEITS_RNT_CLOUD"; | |
| 47 | + /** | |
| 48 | + * 消息消费失败发送的tag | |
| 49 | + */ | |
| 50 | + public final static String CONSUMEFAILED_TAG = "ConsumeMsgFailed"; | |
| 37 | 51 | } | ... | ... |
src/main/java/org/apache/rocketmq/spring/starter/core/RocketMQTemplate.java
| ... | ... | @@ -17,54 +17,30 @@ |
| 17 | 17 | |
| 18 | 18 | package org.apache.rocketmq.spring.starter.core; |
| 19 | 19 | |
| 20 | -import com.aliyun.openservices.ons.api.MessageAccessor; | |
| 21 | -import com.aliyun.openservices.ons.api.OnExceptionContext; | |
| 22 | -import com.aliyun.openservices.ons.api.Producer; | |
| 23 | -import com.aliyun.openservices.ons.api.PropertyKeyConst; | |
| 24 | -import com.aliyun.openservices.ons.api.exception.ONSClientException; | |
| 25 | -import com.aliyun.openservices.shade.com.alibaba.rocketmq.common.message.MessageExt; | |
| 26 | -import com.fasterxml.jackson.core.JsonProcessingException; | |
| 27 | -import com.fasterxml.jackson.databind.ObjectMapper; | |
| 28 | 20 | import java.nio.charset.Charset; |
| 29 | -import java.util.Iterator; | |
| 30 | 21 | import java.util.Map; |
| 31 | -import java.util.Objects; | |
| 32 | -import java.util.Properties; | |
| 33 | 22 | import java.util.Map.Entry; |
| 23 | +import java.util.Objects; | |
| 34 | 24 | |
| 35 | -import lombok.Getter; | |
| 36 | -import lombok.Setter; | |
| 37 | -import lombok.extern.slf4j.Slf4j; | |
| 38 | -import org.apache.rocketmq.client.producer.DefaultMQProducer; | |
| 39 | -import org.apache.rocketmq.client.producer.MessageQueueSelector; | |
| 40 | -import org.apache.rocketmq.client.producer.SendCallback; | |
| 41 | -import org.apache.rocketmq.client.producer.SendResult; | |
| 42 | -import org.apache.rocketmq.client.producer.SendStatus; | |
| 43 | -import org.apache.rocketmq.client.producer.selector.SelectMessageQueueByHash; | |
| 44 | -import org.apache.rocketmq.common.message.MessageConst; | |
| 45 | -import org.apache.rocketmq.common.message.MessageQueue; | |
| 46 | 25 | import org.springframework.beans.factory.DisposableBean; |
| 47 | 26 | import org.springframework.beans.factory.InitializingBean; |
| 48 | -import org.springframework.messaging.Message; | |
| 49 | -import org.springframework.messaging.MessageHeaders; | |
| 50 | 27 | import org.springframework.messaging.MessagingException; |
| 51 | -import org.springframework.messaging.core.AbstractMessageSendingTemplate; | |
| 52 | -import org.springframework.messaging.core.MessagePostProcessor; | |
| 53 | -import org.springframework.messaging.support.MessageBuilder; | |
| 54 | -import org.springframework.util.Assert; | |
| 55 | -import org.springframework.util.MimeTypeUtils; | |
| 56 | -import org.springframework.util.StringUtils; | |
| 57 | 28 | |
| 58 | -@SuppressWarnings({"WeakerAccess", "unused"}) | |
| 29 | +import com.aliyun.openservices.ons.api.Message; | |
| 30 | +import com.aliyun.openservices.ons.api.Producer; | |
| 31 | +import com.aliyun.openservices.ons.api.SendCallback; | |
| 32 | +import com.aliyun.openservices.ons.api.SendResult; | |
| 33 | +import com.fasterxml.jackson.databind.ObjectMapper; | |
| 34 | + | |
| 35 | +import lombok.Getter; | |
| 36 | +import lombok.Setter; | |
| 37 | +import lombok.extern.slf4j.Slf4j; | |
| 38 | + | |
| 59 | 39 | @Slf4j |
| 60 | -public class RocketMQTemplate extends AbstractMessageSendingTemplate<String> implements InitializingBean, DisposableBean { | |
| 40 | +public class RocketMQTemplate implements InitializingBean, DisposableBean { | |
| 61 | 41 | |
| 62 | 42 | @Getter |
| 63 | 43 | @Setter |
| 64 | - private DefaultMQProducer defaultProducer; | |
| 65 | - | |
| 66 | - @Getter | |
| 67 | - @Setter | |
| 68 | 44 | private Producer aliyunProducer; |
| 69 | 45 | |
| 70 | 46 | @Setter |
| ... | ... | @@ -74,479 +50,252 @@ public class RocketMQTemplate extends AbstractMessageSendingTemplate<String> imp |
| 74 | 50 | @Getter |
| 75 | 51 | @Setter |
| 76 | 52 | private String charset = "UTF-8"; |
| 77 | - | |
| 78 | - @Getter | |
| 53 | + | |
| 54 | + /** | |
| 55 | + * 环境前缀 | |
| 56 | + */ | |
| 79 | 57 | @Setter |
| 80 | - private MessageQueueSelector messageQueueSelector = new SelectMessageQueueByHash(); | |
| 58 | + private String environmentPrefix; | |
| 81 | 59 | |
| 82 | 60 | /** |
| 83 | - * <p> Send message in synchronous mode. This method returns only when the sending procedure totally completes. | |
| 84 | - * Reliable synchronous transmission is used in extensive scenes, such as important notification messages, SMS | |
| 85 | - * notification, SMS marketing system, etc.. </p> | |
| 86 | - * | |
| 87 | - * <strong>Warn:</strong> this method has internal retry-mechanism, that is, internal implementation will retry | |
| 88 | - * {@link DefaultMQProducer#getRetryTimesWhenSendFailed} times before claiming failure. As a result, multiple | |
| 89 | - * messages may potentially delivered to broker(s). It's up to the application developers to resolve potential | |
| 90 | - * duplication issue. | |
| 91 | - * | |
| 92 | - * @param destination formats: `topicName:tags` | |
| 93 | - * @param message {@link org.springframework.messaging.Message} | |
| 61 | + * 同步发送消息 | |
| 62 | + * @param topic 消息主题, 最长不超过255个字符; 由a-z, A-Z, 0-9, 以及中划线"-"和下划线"_"构成. | |
| 63 | + * @param tag 消息标签, 请使用合法标识符, 尽量简短且见名知意 | |
| 64 | + * @param key 业务主键 | |
| 65 | + * @param payload 消息体, 消息体长度默认不超过4M, 具体请参阅集群部署文档描述. | |
| 66 | + * @param userProperties 添加用户自定义属性键值对; 该键值对在消费消费时可被获取.也可用于做SQL属性过滤 | |
| 67 | + * @param startDeliverTime 设置消息的定时投递时间(绝对时间),最大延迟时间为7天. | |
| 68 | + * </p> | |
| 69 | + * <ol> | |
| 70 | + * <li>延迟投递: 延迟3s投递, 设置为: System.currentTimeMillis() + 3000;</li> | |
| 71 | + * <li>定时投递: 2016-02-01 11:30:00投递, 设置为: new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse("2016-02-01 11:30:00").getTime()</li> | |
| 72 | + * </ol> | |
| 94 | 73 | * @return {@link SendResult} |
| 74 | + * 2018年3月23日 zhaowg | |
| 95 | 75 | */ |
| 96 | - public SendResult syncSend(String destination, Message<?> message) { | |
| 97 | - if (Objects.isNull(message) || Objects.isNull(message.getPayload())) { | |
| 98 | - log.info("syncSend failed. destination:{}, message is null ", destination); | |
| 99 | - throw new IllegalArgumentException("`message` and `message.payload` cannot be null"); | |
| 76 | + public SendResult syncSend(String topic,String tag,String keys,Object payload,Map<String, String> userProperties,Long startDeliverTime) { | |
| 77 | + if (Objects.isNull(topic) || Objects.isNull(payload)) { | |
| 78 | + log.info("同步消息发送失败,主题和消息不能为空"); | |
| 79 | + throw new IllegalArgumentException("同步消息发送失败,主题和消息不能为空"); | |
| 100 | 80 | } |
| 101 | 81 | |
| 102 | 82 | try { |
| 103 | - SendResult sendResult = new SendResult(); | |
| 104 | - long now = System.currentTimeMillis(); | |
| 105 | - if(aliyunProducer != null){ | |
| 106 | - //阿里云发送 | |
| 107 | - com.aliyun.openservices.ons.api.Message aliyunMsg = convertToAliyunRocketMsg(destination,message); | |
| 108 | - com.aliyun.openservices.ons.api.SendResult aliyunSendResult = aliyunProducer.send(aliyunMsg); | |
| 109 | - sendResult = convertAliyunSendResult(aliyunSendResult); | |
| 110 | - }else if(defaultProducer != null){ | |
| 111 | - org.apache.rocketmq.common.message.Message rocketMsg = convertToRocketMsg(destination, message); | |
| 112 | - sendResult = defaultProducer.send(rocketMsg); | |
| 113 | - }else{ | |
| 114 | - throw new RuntimeException("product为空,请检查配置文件是否配置:spring.rocketmq.aliyun,且值为true或false"); | |
| 115 | - } | |
| 83 | + long now = System.currentTimeMillis(); | |
| 84 | + | |
| 85 | + Message rocketMsg = new Message(environmentPrefix+"_"+topic, tag, keys, convertToRocketMsg(payload)); | |
| 86 | + if(userProperties!=null && !userProperties.isEmpty()){ | |
| 87 | + for (Entry<String, String> userProp : userProperties.entrySet()) { | |
| 88 | + rocketMsg.putUserProperties(userProp.getKey(), userProp.getValue()); | |
| 89 | + } | |
| 90 | + } | |
| 91 | + if(startDeliverTime!=null){ | |
| 92 | + //设置定时发送时间 | |
| 93 | + rocketMsg.setStartDeliverTime(startDeliverTime); | |
| 94 | + } | |
| 95 | + //阿里云发送 | |
| 96 | + SendResult sendResult = aliyunProducer.send(rocketMsg); | |
| 116 | 97 | long costTime = System.currentTimeMillis() - now; |
| 117 | - log.debug("send message cost: {} ms, msgId:{}", costTime, sendResult.getMsgId()); | |
| 98 | + log.debug("发送消息耗时: {} ms, msgId:{}", costTime, sendResult.getMessageId()); | |
| 118 | 99 | return sendResult; |
| 119 | 100 | } catch (Exception e) { |
| 120 | - log.info("syncSend failed. destination:{}, message:{} ", destination, message); | |
| 101 | + log.info("同步发送失败. topic:{}, message:{} ", topic, payload); | |
| 121 | 102 | throw new MessagingException(e.getMessage(), e); |
| 122 | 103 | } |
| 123 | 104 | } |
| 124 | 105 | |
| 125 | 106 | /** |
| 126 | - * Same to {@link #syncSend(String, Message)}. | |
| 127 | - * | |
| 128 | - * @param destination formats: `topicName:tags` | |
| 129 | - * @param payload the Object to use as payload | |
| 107 | + * Same to {@link #syncSend(String, String, String, Object, Map, Long)}. | |
| 108 | + * @param topic 消息主题, 最长不超过255个字符; 由a-z, A-Z, 0-9, 以及中划线"-"和下划线"_"构成. | |
| 109 | + * @param tag 消息标签, 请使用合法标识符, 尽量简短且见名知意 | |
| 110 | + * @param key 业务主键 | |
| 111 | + * @param payload 消息体, 消息体长度默认不超过4M, 具体请参阅集群部署文档描述. | |
| 130 | 112 | * @return {@link SendResult} |
| 113 | + * 2018年3月23日 zhaowg | |
| 131 | 114 | */ |
| 132 | - public SendResult syncSend(String destination, Object payload) { | |
| 133 | - Message<?> message = this.doConvert(payload, null, null); | |
| 134 | - return syncSend(destination, message); | |
| 115 | + public SendResult syncSend(String topic,String tag,String keys, Object payload) { | |
| 116 | + return syncSend(topic, tag, keys, payload, null, null); | |
| 135 | 117 | } |
| 136 | - | |
| 137 | - | |
| 138 | - /** | |
| 139 | - * Same to {@link #syncSend(String, Message)} with send orderly with hashKey by specified. | |
| 140 | - * | |
| 141 | - * @param destination formats: `topicName:tags` | |
| 142 | - * @param message {@link org.springframework.messaging.Message} | |
| 143 | - * @param hashKey use this key to select queue. for example: orderId, productId ... | |
| 144 | - * @return {@link SendResult} | |
| 145 | - */ | |
| 146 | - /*public SendResult syncSendOrderly(String destination, Message<?> message, String hashKey) { | |
| 147 | - if (Objects.isNull(message) || Objects.isNull(message.getPayload())) { | |
| 148 | - log.info("syncSendOrderly failed. destination:{}, message is null ", destination); | |
| 149 | - throw new IllegalArgumentException("`message` and `message.payload` cannot be null"); | |
| 150 | - } | |
| 151 | - | |
| 152 | - try { | |
| 153 | - long now = System.currentTimeMillis(); | |
| 154 | - org.apache.rocketmq.common.message.Message rocketMsg = convertToRocketMsg(destination, message); | |
| 155 | - //TODO | |
| 156 | - throw new RuntimeException("暂时未整合阿里云Producer,不要使用"); | |
| 157 | -// SendResult sendResult = producer.send(rocketMsg, messageQueueSelector, hashKey, timeout); | |
| 158 | -// long costTime = System.currentTimeMillis() - now; | |
| 159 | -// log.debug("send message cost: {} ms, msgId:{}", costTime, sendResult.getMsgId()); | |
| 160 | -// return sendResult; | |
| 161 | - } catch (Exception e) { | |
| 162 | - log.info("syncSendOrderly failed. destination:{}, message:{} ", destination, message); | |
| 163 | - throw new MessagingException(e.getMessage(), e); | |
| 164 | - } | |
| 165 | - }*/ | |
| 166 | - | |
| 167 | - | |
| 168 | 118 | /** |
| 169 | - * Same to {@link #syncSend(String, Object)} with send orderly with hashKey by specified. | |
| 170 | - * | |
| 171 | - * @param destination formats: `topicName:tags` | |
| 172 | - * @param payload the Object to use as payload | |
| 173 | - * @param hashKey use this key to select queue. for example: orderId, productId ... | |
| 119 | + * Same to {@link #syncSend(String, String, String, Object)}. | |
| 120 | + * @param topic 消息主题, 最长不超过255个字符; 由a-z, A-Z, 0-9, 以及中划线"-"和下划线"_"构成. | |
| 121 | + * @param tag 消息标签, 请使用合法标识符, 尽量简短且见名知意 | |
| 122 | + * @param payload 消息体, 消息体长度默认不超过4M, 具体请参阅集群部署文档描述. | |
| 174 | 123 | * @return {@link SendResult} |
| 124 | + * 2018年3月23日 zhaowg | |
| 175 | 125 | */ |
| 176 | -// public SendResult syncSendOrderly(String destination, Object payload, String hashKey) { | |
| 177 | -// Message<?> message = this.doConvert(payload, null, null); | |
| 178 | -// return syncSendOrderly(destination, message, hashKey); | |
| 179 | -// } | |
| 126 | + public SendResult syncSend(String topic,String tag, Object payload) { | |
| 127 | + return syncSend(topic, tag,null, payload); | |
| 128 | + } | |
| 180 | 129 | |
| 181 | 130 | /** |
| 182 | - * 将公共的sendCallBack转换为阿里云的sendCallBack | |
| 183 | - * @param sendCallback | |
| 184 | - * @return | |
| 131 | + * 异步发送消息 | |
| 132 | + * @param topic 消息主题, 最长不超过255个字符; 由a-z, A-Z, 0-9, 以及中划线"-"和下划线"_"构成. | |
| 133 | + * @param tag 消息标签, 请使用合法标识符, 尽量简短且见名知意 | |
| 134 | + * @param key 业务主键 | |
| 135 | + * @param payload 消息体, 消息体长度默认不超过4M, 具体请参阅集群部署文档描述. | |
| 136 | + * @param userProperties 添加用户自定义属性键值对; 该键值对在消费消费时可被获取.也可用于做SQL属性过滤 | |
| 137 | + * @param startDeliverTime 设置消息的定时投递时间(绝对时间),最大延迟时间为7天. | |
| 138 | + * </p> | |
| 139 | + * <ol> | |
| 140 | + * <li>延迟投递: 延迟3s投递, 设置为: System.currentTimeMillis() + 3000;</li> | |
| 141 | + * <li>定时投递: 2016-02-01 11:30:00投递, 设置为: new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse("2016-02-01 11:30:00").getTime()</li> | |
| 142 | + * </ol> | |
| 143 | + * @param sendCallback 发送完成要执行的回调函数 | |
| 185 | 144 | * 2018年3月23日 zhaowg |
| 186 | 145 | */ |
| 187 | - private com.aliyun.openservices.ons.api.SendCallback aliyunSendCallBackConvert(final SendCallback sendCallback) { | |
| 188 | - com.aliyun.openservices.ons.api.SendCallback aliyunSendCallBack = new com.aliyun.openservices.ons.api.SendCallback() { | |
| 189 | - | |
| 190 | - @Override | |
| 191 | - public void onSuccess(com.aliyun.openservices.ons.api.SendResult sendResult) { | |
| 192 | - sendCallback.onSuccess(convertAliyunSendResult(sendResult)); | |
| 193 | - } | |
| 194 | - | |
| 195 | - @Override | |
| 196 | - public void onException(OnExceptionContext context) { | |
| 197 | - sendCallback.onException(context.getException()); | |
| 198 | - } | |
| 199 | - }; | |
| 200 | - return aliyunSendCallBack; | |
| 201 | - } | |
| 202 | - /** | |
| 203 | - * <p> Send message to broker asynchronously. asynchronous transmission is generally used in response time sensitive | |
| 204 | - * business scenarios. </p> | |
| 205 | - * | |
| 206 | - * This method returns immediately. On sending completion, <code>sendCallback</code> will be executed. | |
| 207 | - * | |
| 208 | - * Similar to {@link #syncSend(String, Object)}, internal implementation would potentially retry up to {@link | |
| 209 | - * DefaultMQProducer#getRetryTimesWhenSendAsyncFailed} times before claiming sending failure, which may yield | |
| 210 | - * message duplication and application developers are the one to resolve this potential issue. | |
| 211 | - * | |
| 212 | - * @param destination formats: `topicName:tags` | |
| 213 | - * @param message {@link org.springframework.messaging.Message} | |
| 214 | - * @param sendCallback {@link SendCallback} | |
| 215 | - */ | |
| 216 | - public void asyncSend(String destination, Message<?> message, SendCallback sendCallback) { | |
| 217 | - if (Objects.isNull(message) || Objects.isNull(message.getPayload())) { | |
| 218 | - log.info("asyncSend failed. destination:{}, message is null ", destination); | |
| 219 | - throw new IllegalArgumentException("`message` and `message.payload` cannot be null"); | |
| 146 | + public void asyncSend(String topic,String tag,String keys,Object payload,Map<String, String> userProperties, | |
| 147 | + Long startDeliverTime,SendCallback sendCallback) { | |
| 148 | + if (Objects.isNull(topic) || Objects.isNull(payload)) { | |
| 149 | + log.info("异步消息发送失败,主题和消息不能为空"); | |
| 150 | + throw new IllegalArgumentException("异步消息发送失败,主题和消息不能为空"); | |
| 220 | 151 | } |
| 221 | - | |
| 222 | 152 | try { |
| 223 | - if(aliyunProducer != null){ | |
| 224 | - com.aliyun.openservices.ons.api.Message aliyunMsg = this.convertToAliyunRocketMsg(destination, message); | |
| 225 | - aliyunProducer.sendAsync(aliyunMsg, aliyunSendCallBackConvert(sendCallback)); | |
| 226 | - }else if(defaultProducer != null){ | |
| 227 | - org.apache.rocketmq.common.message.Message rocketMsg = convertToRocketMsg(destination, message); | |
| 228 | - defaultProducer.send(rocketMsg, sendCallback); | |
| 229 | - }else{ | |
| 230 | - throw new RuntimeException("product为空,请检查配置文件是否配置:spring.rocketmq.aliyun,且值为true或false"); | |
| 153 | + long now = System.currentTimeMillis(); | |
| 154 | + | |
| 155 | + Message rocketMsg = new Message(environmentPrefix+"_"+topic, tag, keys, convertToRocketMsg(payload)); | |
| 156 | + if(userProperties!=null && !userProperties.isEmpty()){ | |
| 157 | + for (Entry<String, String> userProp : userProperties.entrySet()) { | |
| 158 | + rocketMsg.putUserProperties(userProp.getKey(), userProp.getValue()); | |
| 159 | + } | |
| 160 | + } | |
| 161 | + if(startDeliverTime!=null){ | |
| 162 | + //设置定时发送时间 | |
| 163 | + rocketMsg.setStartDeliverTime(startDeliverTime); | |
| 231 | 164 | } |
| 165 | + //阿里云发送 | |
| 166 | + aliyunProducer.sendAsync(rocketMsg, sendCallback); | |
| 167 | + long costTime = System.currentTimeMillis() - now; | |
| 168 | + log.debug("发送消息耗时: {} ms", costTime); | |
| 232 | 169 | } catch (Exception e) { |
| 233 | - log.info("asyncSend failed. destination:{}, message:{} ", destination, message); | |
| 170 | + log.info("异步发送失败. topic:{}, message:{} ", topic, payload); | |
| 234 | 171 | throw new MessagingException(e.getMessage(), e); |
| 235 | 172 | } |
| 236 | 173 | } |
| 237 | - | |
| 238 | - /** | |
| 239 | - * Same to {@link #asyncSend(String, Message, SendCallback)}. | |
| 240 | - * | |
| 241 | - * @param destination formats: `topicName:tags` | |
| 242 | - * @param payload the Object to use as payload | |
| 243 | - * @param sendCallback {@link SendCallback} | |
| 174 | + /** | |
| 175 | + * Same to {@link #asyncSend(String, String, String, Object, Map, Long, SendCallback)}. | |
| 176 | + * @param topic 消息主题, 最长不超过255个字符; 由a-z, A-Z, 0-9, 以及中划线"-"和下划线"_"构成. | |
| 177 | + * @param tag 消息标签, 请使用合法标识符, 尽量简短且见名知意 | |
| 178 | + * @param key 业务主键 | |
| 179 | + * @param payload 消息体, 消息体长度默认不超过4M, 具体请参阅集群部署文档描述. | |
| 180 | + * @param sendCallback 发送完成要执行的回调函数 | |
| 181 | + * @return {@link SendResult} | |
| 182 | + * 2018年3月23日 zhaowg | |
| 244 | 183 | */ |
| 245 | - public void asyncSend(String destination, Object payload, SendCallback sendCallback) { | |
| 246 | - Message<?> message = this.doConvert(payload, null, null); | |
| 247 | - asyncSend(destination, message, sendCallback); | |
| 184 | + public void asyncSend(String topic,String tag,String keys, Object payload,SendCallback sendCallback) { | |
| 185 | + asyncSend(topic, tag, keys, payload, null, null,sendCallback); | |
| 248 | 186 | } |
| 249 | - | |
| 250 | - | |
| 251 | 187 | /** |
| 252 | - * Same to {@link #asyncSend(String, Message, SendCallback)} with send orderly with hashKey by specified. | |
| 253 | - * | |
| 254 | - * @param destination formats: `topicName:tags` | |
| 255 | - * @param message {@link org.springframework.messaging.Message} | |
| 256 | - * @param hashKey use this key to select queue. for example: orderId, productId ... | |
| 257 | - * @param sendCallback {@link SendCallback} | |
| 258 | - */ | |
| 259 | -// public void asyncSendOrderly(String destination, Message<?> message, String hashKey, SendCallback sendCallback) { | |
| 260 | -// if (Objects.isNull(message) || Objects.isNull(message.getPayload())) { | |
| 261 | -// log.info("asyncSendOrderly failed. destination:{}, message is null ", destination); | |
| 262 | -// throw new IllegalArgumentException("`message` and `message.payload` cannot be null"); | |
| 263 | -// } | |
| 264 | -// | |
| 265 | -// try { | |
| 266 | -// org.apache.rocketmq.common.message.Message rocketMsg = convertToRocketMsg(destination, message); | |
| 267 | -// //TODO zwg | |
| 268 | -// throw new RuntimeException("暂时未整合阿里云Producer,不要使用"); | |
| 269 | -// //producer.send(rocketMsg, messageQueueSelector, hashKey, sendCallback, timeout); | |
| 270 | -// } catch (Exception e) { | |
| 271 | -// log.info("asyncSendOrderly failed. destination:{}, message:{} ", destination, message); | |
| 272 | -// throw new MessagingException(e.getMessage(), e); | |
| 273 | -// } | |
| 274 | -// } | |
| 275 | - | |
| 276 | - /** | |
| 277 | - * Same to {@link #asyncSendOrderly(String, Message, String, SendCallback)}. | |
| 278 | - * | |
| 279 | - * @param destination formats: `topicName:tags` | |
| 280 | - * @param payload the Object to use as payload | |
| 281 | - * @param hashKey use this key to select queue. for example: orderId, productId ... | |
| 282 | - * @param sendCallback {@link SendCallback} | |
| 188 | + * Same to {@link #asyncSend(String, String, String, Object,SendCallback)}. | |
| 189 | + * @param topic 消息主题, 最长不超过255个字符; 由a-z, A-Z, 0-9, 以及中划线"-"和下划线"_"构成. | |
| 190 | + * @param tag 消息标签, 请使用合法标识符, 尽量简短且见名知意 | |
| 191 | + * @param payload 消息体, 消息体长度默认不超过4M, 具体请参阅集群部署文档描述. | |
| 192 | + * @param sendCallback 发送完成要执行的回调函数 | |
| 193 | + * @return {@link SendResult} | |
| 194 | + * 2018年3月23日 zhaowg | |
| 283 | 195 | */ |
| 284 | -// public void asyncSendOrderly(String destination, Object payload, String hashKey, SendCallback sendCallback) { | |
| 285 | -// Message<?> message = this.doConvert(payload, null, null); | |
| 286 | -// asyncSendOrderly(destination, message, hashKey, sendCallback); | |
| 287 | -// } | |
| 288 | - | |
| 196 | + public void asyncSend(String topic,String tag, Object payload,SendCallback sendCallback) { | |
| 197 | + asyncSend(topic, tag,null, payload,sendCallback); | |
| 198 | + } | |
| 289 | 199 | /** |
| 290 | - * Similar to <a href="https://en.wikipedia.org/wiki/User_Datagram_Protocol">UDP</a>, this method won't wait for | |
| 291 | - * acknowledgement from broker before return. Obviously, it has maximums throughput yet potentials of message loss. | |
| 292 | - * | |
| 293 | - * One-way transmission is used for cases requiring moderate reliability, such as log collection. | |
| 294 | - * | |
| 295 | - * @param destination formats: `topicName:tags` | |
| 296 | - * @param message {@link org.springframework.messaging.Message} | |
| 200 | + * 服务器不应答,无法保证消息是否成功到达服务器 | |
| 201 | + * @param topic 消息主题, 最长不超过255个字符; 由a-z, A-Z, 0-9, 以及中划线"-"和下划线"_"构成. | |
| 202 | + * @param tag 消息标签, 请使用合法标识符, 尽量简短且见名知意 | |
| 203 | + * @param key 业务主键 | |
| 204 | + * @param payload 消息体, 消息体长度默认不超过4M, 具体请参阅集群部署文档描述. | |
| 205 | + * @param userProperties 添加用户自定义属性键值对; 该键值对在消费消费时可被获取.也可用于做SQL属性过滤 | |
| 206 | + * @param startDeliverTime 设置消息的定时投递时间(绝对时间),最大延迟时间为7天. | |
| 207 | + * </p> | |
| 208 | + * <ol> | |
| 209 | + * <li>延迟投递: 延迟3s投递, 设置为: System.currentTimeMillis() + 3000;</li> | |
| 210 | + * <li>定时投递: 2016-02-01 11:30:00投递, 设置为: new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse("2016-02-01 11:30:00").getTime()</li> | |
| 211 | + * </ol> | |
| 212 | + * 2018年3月23日 zhaowg | |
| 297 | 213 | */ |
| 298 | - public void sendOneWay(String destination, Message<?> message) { | |
| 299 | - if (Objects.isNull(message) || Objects.isNull(message.getPayload())) { | |
| 300 | - log.info("sendOneWay failed. destination:{}, message is null ", destination); | |
| 301 | - throw new IllegalArgumentException("`message` and `message.payload` cannot be null"); | |
| 214 | + public void sendOneWay(String topic,String tag,String keys,Object payload,Map<String, String> userProperties, | |
| 215 | + Long startDeliverTime) { | |
| 216 | + if (Objects.isNull(topic) || Objects.isNull(payload)) { | |
| 217 | + log.info("sendOneWay消息发送失败,主题和消息不能为空"); | |
| 218 | + throw new IllegalArgumentException("sendOneWay消息发送失败,主题和消息不能为空"); | |
| 302 | 219 | } |
| 303 | - | |
| 304 | 220 | try { |
| 305 | - if(aliyunProducer !=null){ | |
| 306 | - //阿里云环境 | |
| 307 | - com.aliyun.openservices.ons.api.Message aliyunMsg = convertToAliyunRocketMsg(destination, message); | |
| 308 | - aliyunProducer.sendOneway(aliyunMsg); | |
| 309 | - }else if(defaultProducer != null){ | |
| 310 | - org.apache.rocketmq.common.message.Message rocketMsg = convertToRocketMsg(destination, message); | |
| 311 | - defaultProducer.sendOneway(rocketMsg); | |
| 312 | - }else{ | |
| 313 | - throw new RuntimeException("product为空,请检查配置文件是否配置:spring.rocketmq.aliyun,且值为true或false"); | |
| 314 | - } | |
| 221 | + long now = System.currentTimeMillis(); | |
| 315 | 222 | |
| 223 | + Message rocketMsg = new Message(environmentPrefix+"_"+topic, tag, keys, convertToRocketMsg(payload)); | |
| 224 | + if(userProperties!=null && !userProperties.isEmpty()){ | |
| 225 | + for (Entry<String, String> userProp : userProperties.entrySet()) { | |
| 226 | + rocketMsg.putUserProperties(userProp.getKey(), userProp.getValue()); | |
| 227 | + } | |
| 228 | + } | |
| 229 | + if(startDeliverTime!=null){ | |
| 230 | + //设置定时发送时间 | |
| 231 | + rocketMsg.setStartDeliverTime(startDeliverTime); | |
| 232 | + } | |
| 233 | + //阿里云发送 | |
| 234 | + aliyunProducer.sendOneway(rocketMsg); | |
| 235 | + long costTime = System.currentTimeMillis() - now; | |
| 236 | + log.debug("发送消息耗时: {} ms", costTime); | |
| 316 | 237 | } catch (Exception e) { |
| 317 | - log.info("sendOneWay failed. destination:{}, message:{} ", destination, message); | |
| 238 | + log.info("sendOneWay发送失败. topic:{}, message:{} ", topic, payload); | |
| 318 | 239 | throw new MessagingException(e.getMessage(), e); |
| 319 | 240 | } |
| 320 | 241 | } |
| 321 | - | |
| 322 | - /** | |
| 323 | - * Same to {@link #sendOneWay(String, Message)} | |
| 324 | - * | |
| 325 | - * @param destination formats: `topicName:tags` | |
| 326 | - * @param payload the Object to use as payload | |
| 242 | + /** | |
| 243 | + * Same to {@link #sendOneWay(String, String, String, Object, Map, Long)}. | |
| 244 | + * @param topic 消息主题, 最长不超过255个字符; 由a-z, A-Z, 0-9, 以及中划线"-"和下划线"_"构成. | |
| 245 | + * @param tag 消息标签, 请使用合法标识符, 尽量简短且见名知意 | |
| 246 | + * @param key 业务主键 | |
| 247 | + * @param payload 消息体, 消息体长度默认不超过4M, 具体请参阅集群部署文档描述. | |
| 248 | + * 2018年3月23日 zhaowg | |
| 327 | 249 | */ |
| 328 | - public void sendOneWay(String destination, Object payload) { | |
| 329 | - Message<?> message = this.doConvert(payload, null, null); | |
| 330 | - sendOneWay(destination, message); | |
| 250 | + public void sendOneWay(String topic,String tag,String keys, Object payload) { | |
| 251 | + sendOneWay(topic, tag, keys, payload, null, null); | |
| 331 | 252 | } |
| 332 | - | |
| 333 | 253 | /** |
| 334 | - * Same to {@link #sendOneWay(String, Message)} with send orderly with hashKey by specified. | |
| 335 | - * | |
| 336 | - * @param destination formats: `topicName:tags` | |
| 337 | - * @param message {@link org.springframework.messaging.Message} | |
| 338 | - * @param hashKey use this key to select queue. for example: orderId, productId ... | |
| 254 | + * Same to {@link #sendOneWay(String, String, String, Object)}. | |
| 255 | + * @param topic 消息主题, 最长不超过255个字符; 由a-z, A-Z, 0-9, 以及中划线"-"和下划线"_"构成. | |
| 256 | + * @param tag 消息标签, 请使用合法标识符, 尽量简短且见名知意 | |
| 257 | + * @param payload 消息体, 消息体长度默认不超过4M, 具体请参阅集群部署文档描述. | |
| 258 | + * 2018年3月23日 zhaowg | |
| 339 | 259 | */ |
| 340 | -// public void sendOneWayOrderly(String destination, Message<?> message, String hashKey) { | |
| 341 | -// if (Objects.isNull(message) || Objects.isNull(message.getPayload())) { | |
| 342 | -// log.info("sendOneWayOrderly failed. destination:{}, message is null ", destination); | |
| 343 | -// throw new IllegalArgumentException("`message` and `message.payload` cannot be null"); | |
| 344 | -// } | |
| 345 | -// | |
| 346 | -// try { | |
| 347 | -// //TODO zwg | |
| 348 | -// throw new RuntimeException("暂时未整合阿里云Producer,不要使用"); | |
| 349 | -// //org.apache.rocketmq.common.message.Message rocketMsg = convertToRocketMsg(destination, message); | |
| 350 | -// //producer.sendOneway(rocketMsg, messageQueueSelector, hashKey); | |
| 351 | -// } catch (Exception e) { | |
| 352 | -// log.info("sendOneWayOrderly failed. destination:{}, message:{}", destination, message); | |
| 353 | -// throw new MessagingException(e.getMessage(), e); | |
| 354 | -// } | |
| 355 | -// } | |
| 260 | + public void sendOneWay(String topic,String tag, Object payload) { | |
| 261 | + sendOneWay(topic, tag,null, payload); | |
| 262 | + } | |
| 356 | 263 | |
| 357 | - /** | |
| 358 | - * Same to {@link #sendOneWayOrderly(String, Message, String)} | |
| 359 | - * | |
| 360 | - * @param destination formats: `topicName:tags` | |
| 361 | - * @param payload the Object to use as payload | |
| 362 | - */ | |
| 363 | -// public void sendOneWayOrderly(String destination, Object payload, String hashKey) { | |
| 364 | -// Message<?> message = this.doConvert(payload, null, null); | |
| 365 | -// sendOneWayOrderly(destination, message, hashKey); | |
| 366 | -// } | |
| 367 | - | |
| 368 | 264 | @Override |
| 369 | 265 | public void afterPropertiesSet() throws Exception { |
| 370 | 266 | if(aliyunProducer != null){ |
| 371 | - log.info("开始启动阿里云环境生产者"); | |
| 267 | + log.info("开始启动阿里云[环境标识:"+environmentPrefix+"]生产者"); | |
| 372 | 268 | aliyunProducer.start(); |
| 373 | - }else if(defaultProducer != null){ | |
| 374 | - log.info("开始启动非阿里云环境生产者"); | |
| 375 | - defaultProducer.start(); | |
| 376 | - }else{ | |
| 377 | - throw new RuntimeException("product为空,请检查配置文件是否配置:spring.rocketmq.aliyun,且值为true或false"); | |
| 378 | 269 | } |
| 379 | 270 | } |
| 380 | 271 | |
| 381 | - protected void doSend(String destination, Message<?> message) { | |
| 382 | - SendResult sendResult = syncSend(destination, message); | |
| 383 | - log.debug("send message to `{}` finished. result:{}", destination, sendResult); | |
| 384 | - } | |
| 385 | 272 | /** |
| 386 | - * 转换阿里云返回对象 | |
| 387 | - * @param aliyunSendResult | |
| 273 | + * 转换对象为字节 | |
| 274 | + * @param msgObj | |
| 388 | 275 | * @return |
| 389 | 276 | * 2018年3月23日 zhaowg |
| 390 | 277 | */ |
| 391 | - private SendResult convertAliyunSendResult(com.aliyun.openservices.ons.api.SendResult aliyunSendResult) { | |
| 392 | - SendResult sendResult = new SendResult(); | |
| 393 | - sendResult.setMsgId(aliyunSendResult.getMessageId()); | |
| 394 | - MessageQueue messageQueue = new MessageQueue(aliyunSendResult.getTopic(), null, 0); | |
| 395 | - sendResult.setMessageQueue(messageQueue); | |
| 396 | - sendResult.setSendStatus(SendStatus.SEND_OK); | |
| 397 | - return sendResult; | |
| 398 | - } | |
| 399 | - /** | |
| 400 | - * 转换为阿里云发送的消息对象 | |
| 401 | - * @param destination formats: `topicName:tags` | |
| 402 | - * @param message {@link org.springframework.messaging.Message} | |
| 403 | - * @return | |
| 404 | - * 2018年3月23日 zhaowg | |
| 405 | - */ | |
| 406 | - private com.aliyun.openservices.ons.api.Message convertToAliyunRocketMsg(String destination, Message<?> message) { | |
| 407 | - Object payloadObj = message.getPayload(); | |
| 408 | - byte[] payloads; | |
| 409 | - | |
| 410 | - if (payloadObj instanceof String) { | |
| 411 | - payloads = ((String) payloadObj).getBytes(Charset.forName(charset)); | |
| 412 | - } else { | |
| 413 | - try { | |
| 414 | - String jsonObj = this.objectMapper.writeValueAsString(payloadObj); | |
| 415 | - payloads = jsonObj.getBytes(Charset.forName(charset)); | |
| 416 | - } catch (Exception e) { | |
| 417 | - throw new RuntimeException("convert to RocketMQ message failed.", e); | |
| 418 | - } | |
| 419 | - } | |
| 420 | - | |
| 421 | - String[] tempArr = destination.split(":", 2); | |
| 422 | - String topic = tempArr[0]; | |
| 423 | - String tags = ""; | |
| 424 | - if (tempArr.length > 1) { | |
| 425 | - tags = tempArr[1]; | |
| 426 | - } | |
| 427 | - | |
| 428 | - com.aliyun.openservices.ons.api.Message rocketMsg = new com.aliyun.openservices.ons.api.Message(topic, tags, payloads); | |
| 429 | - | |
| 430 | - MessageHeaders headers = message.getHeaders(); | |
| 431 | - if (Objects.nonNull(headers) && !headers.isEmpty()) { | |
| 432 | - Object keys = headers.get(MessageConst.PROPERTY_KEYS); | |
| 433 | - if (!StringUtils.isEmpty(keys)) { // if headers has 'KEYS', set rocketMQ message key | |
| 434 | - rocketMsg.setKey(keys.toString()); | |
| 435 | - } | |
| 436 | - | |
| 437 | - headers.entrySet().stream() | |
| 438 | - .filter(entry -> !Objects.equals(entry.getKey(), MessageConst.PROPERTY_KEYS) | |
| 439 | - && !Objects.equals(entry.getKey(), "FLAG") | |
| 440 | - && !Objects.equals(entry.getKey(), "WAIT_STORE_MSG_OK")) // exclude "KEYS", "FLAG", "WAIT_STORE_MSG_OK" | |
| 441 | - .forEach(entry -> { | |
| 442 | - rocketMsg.putUserProperties("USERS_" + entry.getKey(), String.valueOf(entry.getValue())); // add other properties with prefix "USERS_" | |
| 443 | - }); | |
| 444 | - | |
| 445 | - } | |
| 446 | - | |
| 447 | - return rocketMsg; | |
| 448 | - } | |
| 449 | - /** | |
| 450 | - * Convert spring message to rocketMQ message | |
| 451 | - * | |
| 452 | - * @param destination formats: `topicName:tags` | |
| 453 | - * @param message {@link org.springframework.messaging.Message} | |
| 454 | - * @return instance of {@link org.apache.rocketmq.common.message.Message} | |
| 455 | - */ | |
| 456 | - private org.apache.rocketmq.common.message.Message convertToRocketMsg(String destination, Message<?> message) { | |
| 457 | - Object payloadObj = message.getPayload(); | |
| 278 | + private byte[] convertToRocketMsg(Object msgObj) { | |
| 458 | 279 | byte[] payloads; |
| 459 | 280 | |
| 460 | - if (payloadObj instanceof String) { | |
| 461 | - payloads = ((String) payloadObj).getBytes(Charset.forName(charset)); | |
| 281 | + if (msgObj instanceof String) { | |
| 282 | + payloads = ((String) msgObj).getBytes(Charset.forName(charset)); | |
| 462 | 283 | } else { |
| 463 | 284 | try { |
| 464 | - String jsonObj = this.objectMapper.writeValueAsString(payloadObj); | |
| 285 | + String jsonObj = this.objectMapper.writeValueAsString(msgObj); | |
| 465 | 286 | payloads = jsonObj.getBytes(Charset.forName(charset)); |
| 466 | 287 | } catch (Exception e) { |
| 467 | 288 | throw new RuntimeException("convert to RocketMQ message failed.", e); |
| 468 | 289 | } |
| 469 | 290 | } |
| 470 | - | |
| 471 | - String[] tempArr = destination.split(":", 2); | |
| 472 | - String topic = tempArr[0]; | |
| 473 | - String tags = ""; | |
| 474 | - if (tempArr.length > 1) { | |
| 475 | - tags = tempArr[1]; | |
| 476 | - } | |
| 477 | - | |
| 478 | - org.apache.rocketmq.common.message.Message rocketMsg = new org.apache.rocketmq.common.message.Message(topic, tags, payloads); | |
| 479 | - | |
| 480 | - MessageHeaders headers = message.getHeaders(); | |
| 481 | - if (Objects.nonNull(headers) && !headers.isEmpty()) { | |
| 482 | - Object keys = headers.get(MessageConst.PROPERTY_KEYS); | |
| 483 | - if (!StringUtils.isEmpty(keys)) { // if headers has 'KEYS', set rocketMQ message key | |
| 484 | - rocketMsg.setKeys(keys.toString()); | |
| 485 | - } | |
| 486 | - | |
| 487 | - // set rocketMQ message flag | |
| 488 | - Object flagObj = headers.getOrDefault("FLAG", "0"); | |
| 489 | - int flag = 0; | |
| 490 | - try { | |
| 491 | - flag = Integer.parseInt(flagObj.toString()); | |
| 492 | - } catch (NumberFormatException e) { | |
| 493 | - // ignore | |
| 494 | - log.info("flag must be integer, flagObj:{}", flagObj); | |
| 495 | - } | |
| 496 | - rocketMsg.setFlag(flag); | |
| 497 | - | |
| 498 | - // set rocketMQ message waitStoreMsgOkObj | |
| 499 | - Object waitStoreMsgOkObj = headers.getOrDefault("WAIT_STORE_MSG_OK", "true"); | |
| 500 | - boolean waitStoreMsgOK = Boolean.TRUE.equals(waitStoreMsgOkObj); | |
| 501 | - rocketMsg.setWaitStoreMsgOK(waitStoreMsgOK); | |
| 502 | - | |
| 503 | - headers.entrySet().stream() | |
| 504 | - .filter(entry -> !Objects.equals(entry.getKey(), MessageConst.PROPERTY_KEYS) | |
| 505 | - && !Objects.equals(entry.getKey(), "FLAG") | |
| 506 | - && !Objects.equals(entry.getKey(), "WAIT_STORE_MSG_OK")) // exclude "KEYS", "FLAG", "WAIT_STORE_MSG_OK" | |
| 507 | - .forEach(entry -> { | |
| 508 | - rocketMsg.putUserProperty("USERS_" + entry.getKey(), String.valueOf(entry.getValue())); // add other properties with prefix "USERS_" | |
| 509 | - }); | |
| 510 | - | |
| 511 | - } | |
| 512 | - | |
| 513 | - return rocketMsg; | |
| 291 | + return payloads; | |
| 514 | 292 | } |
| 515 | 293 | |
| 516 | - @Override | |
| 517 | - protected Message<?> doConvert(Object payload, Map<String, Object> headers, MessagePostProcessor postProcessor) { | |
| 518 | - String content; | |
| 519 | - if (payload instanceof String) { | |
| 520 | - content = (String) payload; | |
| 521 | - } else { | |
| 522 | - // if payload not as string, use objectMapper change it. | |
| 523 | - try { | |
| 524 | - content = objectMapper.writeValueAsString(payload); | |
| 525 | - } catch (JsonProcessingException e) { | |
| 526 | - log.info("convert payload to String failed. payload:{}", payload); | |
| 527 | - throw new RuntimeException("convert to payload to String failed.", e); | |
| 528 | - } | |
| 529 | - } | |
| 530 | - | |
| 531 | - MessageBuilder<?> builder = MessageBuilder.withPayload(content); | |
| 532 | - if (headers != null) { | |
| 533 | - builder.copyHeaders(headers); | |
| 534 | - } | |
| 535 | - builder.setHeaderIfAbsent(MessageHeaders.CONTENT_TYPE, MimeTypeUtils.TEXT_PLAIN); | |
| 536 | - | |
| 537 | - Message<?> message = builder.build(); | |
| 538 | - if (postProcessor != null) { | |
| 539 | - message = postProcessor.postProcessMessage(message); | |
| 540 | - } | |
| 541 | - return message; | |
| 542 | - } | |
| 543 | 294 | |
| 544 | 295 | @Override |
| 545 | 296 | public void destroy() { |
| 546 | - if (Objects.nonNull(defaultProducer)) { | |
| 547 | - defaultProducer.shutdown(); | |
| 548 | - } | |
| 549 | 297 | if(Objects.nonNull(aliyunProducer)){ |
| 298 | + log.info("开始关闭阿里云[环境标识:"+environmentPrefix+"]生产者"); | |
| 550 | 299 | aliyunProducer.shutdown(); |
| 551 | 300 | } |
| 552 | 301 | } | ... | ... |
src/main/java/org/apache/rocketmq/spring/starter/enums/ConsumeMode.java
| ... | ... | @@ -19,12 +19,17 @@ package org.apache.rocketmq.spring.starter.enums; |
| 19 | 19 | |
| 20 | 20 | public enum ConsumeMode { |
| 21 | 21 | /** |
| 22 | - * receive asynchronously delivered messages concurrently | |
| 22 | + * 同时接收异步发送的消息 | |
| 23 | 23 | */ |
| 24 | 24 | CONCURRENTLY, |
| 25 | 25 | |
| 26 | 26 | /** |
| 27 | - * receive asynchronously delivered messages orderly. one queue, one thread | |
| 27 | + * 顺序接收消息,一个队列,一个线程 | |
| 28 | 28 | */ |
| 29 | - ORDERLY | |
| 29 | + ORDERLY, | |
| 30 | + | |
| 31 | + /** | |
| 32 | + * 批量接收发送的消息,允许自定义范围为[1, 32], 实际消费数量可能小于该值 | |
| 33 | + */ | |
| 34 | + BATCH | |
| 30 | 35 | } | ... | ... |
src/main/java/org/apache/rocketmq/spring/starter/enums/SelectorType.java
src/main/java/org/apache/rocketmq/spring/starter/utils/ExceptionUtil.java
0 → 100644
| 1 | +package org.apache.rocketmq.spring.starter.utils; | |
| 2 | + | |
| 3 | +import java.io.PrintWriter; | |
| 4 | +import java.io.StringWriter; | |
| 5 | + | |
| 6 | +public class ExceptionUtil { | |
| 7 | + | |
| 8 | + public static String getTrace(Throwable t) { | |
| 9 | + StringBuffer buffer = new StringBuffer(); | |
| 10 | + if(t==null){ | |
| 11 | + return ""; | |
| 12 | + } | |
| 13 | + StringWriter stringWriter = new StringWriter(); | |
| 14 | + PrintWriter writer = new PrintWriter(stringWriter); | |
| 15 | + t.printStackTrace(writer); | |
| 16 | + //设置堆栈信息 | |
| 17 | + buffer.append("堆栈信息为:" + stringWriter.getBuffer().toString()); | |
| 18 | + return buffer.toString(); | |
| 19 | + } | |
| 20 | + | |
| 21 | +} | ... | ... |
src/test/java/org/apache/rocketmq/spring/starter/RocketMQAutoConfigurationTests.java
| 1 | -/* | |
| 2 | - * Licensed to the Apache Software Foundation (ASF) under one or more | |
| 3 | - * contributor license agreements. See the NOTICE file distributed with | |
| 4 | - * this work for additional information regarding copyright ownership. | |
| 5 | - * The ASF licenses this file to You under the Apache License, Version 2.0 | |
| 6 | - * (the "License"); you may not use this file except in compliance with | |
| 7 | - * the License. You may obtain a copy of the License at | |
| 8 | - * | |
| 9 | - * http://www.apache.org/licenses/LICENSE-2.0 | |
| 10 | - * | |
| 11 | - * Unless required by applicable law or agreed to in writing, software | |
| 12 | - * distributed under the License is distributed on an "AS IS" BASIS, | |
| 13 | - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| 14 | - * See the License for the specific language governing permissions and | |
| 15 | - * limitations under the License. | |
| 16 | - */ | |
| 17 | - | |
| 18 | -package org.apache.rocketmq.spring.starter; | |
| 19 | - | |
| 20 | -import com.fasterxml.jackson.databind.ObjectMapper; | |
| 21 | -import org.apache.rocketmq.spring.starter.annotation.RocketMQMessageListener; | |
| 22 | -import org.apache.rocketmq.spring.starter.core.DefaultRocketMQListenerContainer; | |
| 23 | -import org.apache.rocketmq.spring.starter.core.RocketMQListener; | |
| 24 | -import org.apache.rocketmq.spring.starter.core.RocketMQTemplate; | |
| 25 | -import org.apache.rocketmq.spring.starter.enums.ConsumeMode; | |
| 26 | -import org.apache.rocketmq.spring.starter.enums.SelectorType; | |
| 27 | -import org.apache.rocketmq.client.producer.DefaultMQProducer; | |
| 28 | -import org.apache.rocketmq.common.protocol.heartbeat.MessageModel; | |
| 29 | -import org.junit.After; | |
| 30 | -import org.junit.Test; | |
| 31 | -import org.springframework.beans.factory.support.BeanDefinitionBuilder; | |
| 32 | -import org.springframework.boot.test.util.EnvironmentTestUtils; | |
| 33 | -import org.springframework.context.annotation.AnnotationConfigApplicationContext; | |
| 34 | - | |
| 35 | -import static org.assertj.core.api.Assertions.assertThat; | |
| 36 | - | |
| 37 | -public class RocketMQAutoConfigurationTests { | |
| 38 | - | |
| 39 | - private static final String TEST_CONSUMER_GROUP = "my_consumer"; | |
| 40 | - | |
| 41 | - private static final String TEST_TOPIC = "test-topic"; | |
| 42 | - | |
| 43 | - private AnnotationConfigApplicationContext context; | |
| 44 | - | |
| 45 | - @Test | |
| 46 | - public void rocketMQTemplate() { | |
| 47 | - | |
| 48 | - load("spring.rocketmq.nameServer=127.0.0.1:9876", | |
| 49 | - "spring.rocketmq.producer.group=my_group", | |
| 50 | - "spring.rocketmq.producer.send-msg-timeout=30000", | |
| 51 | - "spring.rocketmq.producer.retry-times-when-send-async-failed=1", | |
| 52 | - "spring.rocketmq.producer.compress-msg-body-over-howmuch=1024", | |
| 53 | - "spring.rocketmq.producer.max-message-size=10240", | |
| 54 | - "spring.rocketmq.producer.retry-another-broker-when-not-store-ok=true", | |
| 55 | - "spring.rocketmq.producer.retry-times-when-send-failed=1"); | |
| 56 | - | |
| 57 | - assertThat(this.context.containsBean("rocketMQMessageObjectMapper")).isTrue(); | |
| 58 | - assertThat(this.context.containsBean("mqProducer")).isTrue(); | |
| 59 | - assertThat(this.context.containsBean("rocketMQTemplate")).isTrue(); | |
| 60 | - assertThat(this.context.getBeansOfType(DefaultRocketMQListenerContainer.class)).isEmpty(); | |
| 61 | - | |
| 62 | - RocketMQTemplate rocketMQTemplate = this.context.getBean(RocketMQTemplate.class); | |
| 63 | - ObjectMapper objectMapper = this.context.getBean("rocketMQMessageObjectMapper", ObjectMapper.class); | |
| 64 | - assertThat(rocketMQTemplate.getObjectMapper()).isEqualTo(objectMapper); | |
| 65 | - | |
| 66 | - DefaultMQProducer defaultMQProducer = rocketMQTemplate.getProducer(); | |
| 67 | - | |
| 68 | - assertThat(defaultMQProducer.getNamesrvAddr()).isEqualTo("127.0.0.1:9876"); | |
| 69 | - assertThat(defaultMQProducer.getProducerGroup()).isEqualTo("my_group"); | |
| 70 | - assertThat(defaultMQProducer.getSendMsgTimeout()).isEqualTo(30000); | |
| 71 | - assertThat(defaultMQProducer.getRetryTimesWhenSendAsyncFailed()).isEqualTo(1); | |
| 72 | - assertThat(defaultMQProducer.getCompressMsgBodyOverHowmuch()).isEqualTo(1024); | |
| 73 | - assertThat(defaultMQProducer.getMaxMessageSize()).isEqualTo(10240); | |
| 74 | - assertThat(defaultMQProducer.isRetryAnotherBrokerWhenNotStoreOK()).isTrue(); | |
| 75 | - assertThat(defaultMQProducer.getRetryTimesWhenSendFailed()).isEqualTo(1); | |
| 76 | - } | |
| 77 | - | |
| 78 | - @Test | |
| 79 | - public void enableProducer() { | |
| 80 | - load(); | |
| 81 | - assertThat(this.context.containsBean("mqProducer")).isFalse(); | |
| 82 | - assertThat(this.context.containsBean("rocketMQTemplate")).isFalse(); | |
| 83 | - closeContext(); | |
| 84 | - | |
| 85 | - load("spring.rocketmq.nameServer=127.0.0.1:9876"); | |
| 86 | - assertThat(this.context.containsBean("mqProducer")).isFalse(); | |
| 87 | - assertThat(this.context.containsBean("rocketMQTemplate")).isFalse(); | |
| 88 | - closeContext(); | |
| 89 | - | |
| 90 | - load("spring.rocketmq.producer.group=my_group"); | |
| 91 | - assertThat(this.context.containsBean("mqProducer")).isFalse(); | |
| 92 | - assertThat(this.context.containsBean("rocketMQTemplate")).isFalse(); | |
| 93 | - closeContext(); | |
| 94 | - | |
| 95 | - load("spring.rocketmq.nameServer=127.0.0.1:9876", "spring.rocketmq.producer.group=my_group"); | |
| 96 | - assertThat(this.context.containsBean("mqProducer")).isTrue(); | |
| 97 | - assertThat(this.context.containsBean("rocketMQTemplate")).isEqualTo(true); | |
| 98 | - assertThat(this.context.getBeansOfType(DefaultRocketMQListenerContainer.class)).isEmpty(); | |
| 99 | - } | |
| 100 | - | |
| 101 | - @Test | |
| 102 | - public void enableConsumer() { | |
| 103 | - load(); | |
| 104 | - assertThat(this.context.getBeansOfType(DefaultRocketMQListenerContainer.class)).isEmpty(); | |
| 105 | - closeContext(); | |
| 106 | - | |
| 107 | - load("spring.rocketmq.nameServer=127.0.0.1:9876"); | |
| 108 | - assertThat(this.context.getBeansOfType(DefaultRocketMQListenerContainer.class)).isEmpty(); | |
| 109 | - closeContext(); | |
| 110 | - | |
| 111 | - load(false); | |
| 112 | - this.context.registerBeanDefinition("myListener", | |
| 113 | - BeanDefinitionBuilder.rootBeanDefinition(MyListener.class).getBeanDefinition()); | |
| 114 | - this.context.refresh(); | |
| 115 | - assertThat(this.context.getBeansOfType(DefaultRocketMQListenerContainer.class)).isEmpty(); | |
| 116 | - closeContext(); | |
| 117 | - | |
| 118 | - load(false, "spring.rocketmq.nameServer=127.0.0.1:9876"); | |
| 119 | - this.context.registerBeanDefinition("myListener", | |
| 120 | - BeanDefinitionBuilder.rootBeanDefinition(MyListener.class).getBeanDefinition()); | |
| 121 | - this.context.refresh(); | |
| 122 | - assertThat(this.context.getBeansOfType(DefaultRocketMQListenerContainer.class)).isNotEmpty(); | |
| 123 | - assertThat(this.context.containsBean(DefaultRocketMQListenerContainer.class.getName() + "_1")).isTrue(); | |
| 124 | - assertThat(this.context.containsBean("mqProducer")).isFalse(); | |
| 125 | - assertThat(this.context.containsBean("rocketMQTemplate")).isFalse(); | |
| 126 | - | |
| 127 | - } | |
| 128 | - | |
| 129 | - @Test | |
| 130 | - public void listenerContainer() { | |
| 131 | - load(false, "spring.rocketmq.nameServer=127.0.0.1:9876"); | |
| 132 | - BeanDefinitionBuilder beanBuilder = BeanDefinitionBuilder.rootBeanDefinition(MyListener.class); | |
| 133 | - this.context.registerBeanDefinition("myListener", beanBuilder.getBeanDefinition()); | |
| 134 | - this.context.refresh(); | |
| 135 | - | |
| 136 | - assertThat(this.context.getBeansOfType(DefaultRocketMQListenerContainer.class)).isNotEmpty(); | |
| 137 | - assertThat(this.context.containsBean(DefaultRocketMQListenerContainer.class.getName() + "_1")).isTrue(); | |
| 138 | - | |
| 139 | - DefaultRocketMQListenerContainer listenerContainer = | |
| 140 | - this.context.getBean(DefaultRocketMQListenerContainer.class.getName() + "_1", | |
| 141 | - DefaultRocketMQListenerContainer.class); | |
| 142 | - ObjectMapper objectMapper = this.context.getBean("rocketMQMessageObjectMapper", ObjectMapper.class); | |
| 143 | - assertThat(listenerContainer.getObjectMapper()).isEqualTo(objectMapper); | |
| 144 | - assertThat(listenerContainer.getConsumeMode()).isEqualTo(ConsumeMode.CONCURRENTLY); | |
| 145 | - assertThat(listenerContainer.getSelectorType()).isEqualTo(SelectorType.TAG); | |
| 146 | - assertThat(listenerContainer.getSelectorExpress()).isEqualTo("*"); | |
| 147 | - assertThat(listenerContainer.getConsumerGroup()).isEqualTo(TEST_CONSUMER_GROUP); | |
| 148 | - assertThat(listenerContainer.getTopic()).isEqualTo(TEST_TOPIC); | |
| 149 | - assertThat(listenerContainer.getNameServer()).isEqualTo("127.0.0.1:9876"); | |
| 150 | - assertThat(listenerContainer.getMessageModel()).isEqualTo(MessageModel.CLUSTERING); | |
| 151 | - assertThat(listenerContainer.getConsumeThreadMax()).isEqualTo(1); | |
| 152 | - } | |
| 153 | - | |
| 154 | - @After | |
| 155 | - public void closeContext() { | |
| 156 | - if (this.context != null) { | |
| 157 | - this.context.close(); | |
| 158 | - } | |
| 159 | - } | |
| 160 | - | |
| 161 | - @RocketMQMessageListener(consumerGroup = TEST_CONSUMER_GROUP, topic = TEST_TOPIC, consumeThreadMax = 1) | |
| 162 | - private static class MyListener implements RocketMQListener<String> { | |
| 163 | - | |
| 164 | - @Override | |
| 165 | - public void onMessage(String message) { | |
| 166 | - System.out.println(message); | |
| 167 | - } | |
| 168 | - } | |
| 169 | - | |
| 170 | - private void load(boolean refresh, String... environment) { | |
| 171 | - AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); | |
| 172 | - ctx.register(RocketMQAutoConfiguration.class); | |
| 173 | - EnvironmentTestUtils.addEnvironment(ctx, environment); | |
| 174 | - if (refresh) { | |
| 175 | - ctx.refresh(); | |
| 176 | - } | |
| 177 | - this.context = ctx; | |
| 178 | - } | |
| 179 | - | |
| 180 | - private void load(String... environment) { | |
| 181 | - load(true, environment); | |
| 182 | - } | |
| 183 | -} | |
| 184 | - | |
| 1 | +///* | |
| 2 | +// * Licensed to the Apache Software Foundation (ASF) under one or more | |
| 3 | +// * contributor license agreements. See the NOTICE file distributed with | |
| 4 | +// * this work for additional information regarding copyright ownership. | |
| 5 | +// * The ASF licenses this file to You under the Apache License, Version 2.0 | |
| 6 | +// * (the "License"); you may not use this file except in compliance with | |
| 7 | +// * the License. You may obtain a copy of the License at | |
| 8 | +// * | |
| 9 | +// * http://www.apache.org/licenses/LICENSE-2.0 | |
| 10 | +// * | |
| 11 | +// * Unless required by applicable law or agreed to in writing, software | |
| 12 | +// * distributed under the License is distributed on an "AS IS" BASIS, | |
| 13 | +// * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| 14 | +// * See the License for the specific language governing permissions and | |
| 15 | +// * limitations under the License. | |
| 16 | +// */ | |
| 17 | +// | |
| 18 | +//package org.apache.rocketmq.spring.starter; | |
| 19 | +// | |
| 20 | +//import com.fasterxml.jackson.databind.ObjectMapper; | |
| 21 | +//import org.apache.rocketmq.spring.starter.annotation.RocketMQMessageListener; | |
| 22 | +//import org.apache.rocketmq.spring.starter.core.DefaultRocketMQListenerContainer; | |
| 23 | +//import org.apache.rocketmq.spring.starter.core.RocketMQListener; | |
| 24 | +//import org.apache.rocketmq.spring.starter.core.RocketMQTemplate; | |
| 25 | +//import org.apache.rocketmq.spring.starter.enums.ConsumeMode; | |
| 26 | +//import org.apache.rocketmq.spring.starter.enums.SelectorType; | |
| 27 | +//import org.apache.rocketmq.client.producer.DefaultMQProducer; | |
| 28 | +//import org.apache.rocketmq.common.protocol.heartbeat.MessageModel; | |
| 29 | +//import org.junit.After; | |
| 30 | +//import org.junit.Test; | |
| 31 | +//import org.springframework.beans.factory.support.BeanDefinitionBuilder; | |
| 32 | +//import org.springframework.boot.test.util.EnvironmentTestUtils; | |
| 33 | +//import org.springframework.context.annotation.AnnotationConfigApplicationContext; | |
| 34 | +// | |
| 35 | +//import static org.assertj.core.api.Assertions.assertThat; | |
| 36 | +// | |
| 37 | +//public class RocketMQAutoConfigurationTests { | |
| 38 | +// | |
| 39 | +// private static final String TEST_CONSUMER_GROUP = "my_consumer"; | |
| 40 | +// | |
| 41 | +// private static final String TEST_TOPIC = "test-topic"; | |
| 42 | +// | |
| 43 | +// private AnnotationConfigApplicationContext context; | |
| 44 | +// | |
| 45 | +// @Test | |
| 46 | +// public void rocketMQTemplate() { | |
| 47 | +// | |
| 48 | +// load("spring.rocketmq.nameServer=127.0.0.1:9876", | |
| 49 | +// "spring.rocketmq.producer.group=my_group", | |
| 50 | +// "spring.rocketmq.producer.send-msg-timeout=30000", | |
| 51 | +// "spring.rocketmq.producer.retry-times-when-send-async-failed=1", | |
| 52 | +// "spring.rocketmq.producer.compress-msg-body-over-howmuch=1024", | |
| 53 | +// "spring.rocketmq.producer.max-message-size=10240", | |
| 54 | +// "spring.rocketmq.producer.retry-another-broker-when-not-store-ok=true", | |
| 55 | +// "spring.rocketmq.producer.retry-times-when-send-failed=1"); | |
| 56 | +// | |
| 57 | +// assertThat(this.context.containsBean("rocketMQMessageObjectMapper")).isTrue(); | |
| 58 | +// assertThat(this.context.containsBean("mqProducer")).isTrue(); | |
| 59 | +// assertThat(this.context.containsBean("rocketMQTemplate")).isTrue(); | |
| 60 | +// assertThat(this.context.getBeansOfType(DefaultRocketMQListenerContainer.class)).isEmpty(); | |
| 61 | +// | |
| 62 | +// RocketMQTemplate rocketMQTemplate = this.context.getBean(RocketMQTemplate.class); | |
| 63 | +// ObjectMapper objectMapper = this.context.getBean("rocketMQMessageObjectMapper", ObjectMapper.class); | |
| 64 | +// assertThat(rocketMQTemplate.getObjectMapper()).isEqualTo(objectMapper); | |
| 65 | +// | |
| 66 | +// DefaultMQProducer defaultMQProducer = rocketMQTemplate.getProducer(); | |
| 67 | +// | |
| 68 | +// assertThat(defaultMQProducer.getNamesrvAddr()).isEqualTo("127.0.0.1:9876"); | |
| 69 | +// assertThat(defaultMQProducer.getProducerGroup()).isEqualTo("my_group"); | |
| 70 | +// assertThat(defaultMQProducer.getSendMsgTimeout()).isEqualTo(30000); | |
| 71 | +// assertThat(defaultMQProducer.getRetryTimesWhenSendAsyncFailed()).isEqualTo(1); | |
| 72 | +// assertThat(defaultMQProducer.getCompressMsgBodyOverHowmuch()).isEqualTo(1024); | |
| 73 | +// assertThat(defaultMQProducer.getMaxMessageSize()).isEqualTo(10240); | |
| 74 | +// assertThat(defaultMQProducer.isRetryAnotherBrokerWhenNotStoreOK()).isTrue(); | |
| 75 | +// assertThat(defaultMQProducer.getRetryTimesWhenSendFailed()).isEqualTo(1); | |
| 76 | +// } | |
| 77 | +// | |
| 78 | +// @Test | |
| 79 | +// public void enableProducer() { | |
| 80 | +// load(); | |
| 81 | +// assertThat(this.context.containsBean("mqProducer")).isFalse(); | |
| 82 | +// assertThat(this.context.containsBean("rocketMQTemplate")).isFalse(); | |
| 83 | +// closeContext(); | |
| 84 | +// | |
| 85 | +// load("spring.rocketmq.nameServer=127.0.0.1:9876"); | |
| 86 | +// assertThat(this.context.containsBean("mqProducer")).isFalse(); | |
| 87 | +// assertThat(this.context.containsBean("rocketMQTemplate")).isFalse(); | |
| 88 | +// closeContext(); | |
| 89 | +// | |
| 90 | +// load("spring.rocketmq.producer.group=my_group"); | |
| 91 | +// assertThat(this.context.containsBean("mqProducer")).isFalse(); | |
| 92 | +// assertThat(this.context.containsBean("rocketMQTemplate")).isFalse(); | |
| 93 | +// closeContext(); | |
| 94 | +// | |
| 95 | +// load("spring.rocketmq.nameServer=127.0.0.1:9876", "spring.rocketmq.producer.group=my_group"); | |
| 96 | +// assertThat(this.context.containsBean("mqProducer")).isTrue(); | |
| 97 | +// assertThat(this.context.containsBean("rocketMQTemplate")).isEqualTo(true); | |
| 98 | +// assertThat(this.context.getBeansOfType(DefaultRocketMQListenerContainer.class)).isEmpty(); | |
| 99 | +// } | |
| 100 | +// | |
| 101 | +// @Test | |
| 102 | +// public void enableConsumer() { | |
| 103 | +// load(); | |
| 104 | +// assertThat(this.context.getBeansOfType(DefaultRocketMQListenerContainer.class)).isEmpty(); | |
| 105 | +// closeContext(); | |
| 106 | +// | |
| 107 | +// load("spring.rocketmq.nameServer=127.0.0.1:9876"); | |
| 108 | +// assertThat(this.context.getBeansOfType(DefaultRocketMQListenerContainer.class)).isEmpty(); | |
| 109 | +// closeContext(); | |
| 110 | +// | |
| 111 | +// load(false); | |
| 112 | +// this.context.registerBeanDefinition("myListener", | |
| 113 | +// BeanDefinitionBuilder.rootBeanDefinition(MyListener.class).getBeanDefinition()); | |
| 114 | +// this.context.refresh(); | |
| 115 | +// assertThat(this.context.getBeansOfType(DefaultRocketMQListenerContainer.class)).isEmpty(); | |
| 116 | +// closeContext(); | |
| 117 | +// | |
| 118 | +// load(false, "spring.rocketmq.nameServer=127.0.0.1:9876"); | |
| 119 | +// this.context.registerBeanDefinition("myListener", | |
| 120 | +// BeanDefinitionBuilder.rootBeanDefinition(MyListener.class).getBeanDefinition()); | |
| 121 | +// this.context.refresh(); | |
| 122 | +// assertThat(this.context.getBeansOfType(DefaultRocketMQListenerContainer.class)).isNotEmpty(); | |
| 123 | +// assertThat(this.context.containsBean(DefaultRocketMQListenerContainer.class.getName() + "_1")).isTrue(); | |
| 124 | +// assertThat(this.context.containsBean("mqProducer")).isFalse(); | |
| 125 | +// assertThat(this.context.containsBean("rocketMQTemplate")).isFalse(); | |
| 126 | +// | |
| 127 | +// } | |
| 128 | +// | |
| 129 | +// @Test | |
| 130 | +// public void listenerContainer() { | |
| 131 | +// load(false, "spring.rocketmq.nameServer=127.0.0.1:9876"); | |
| 132 | +// BeanDefinitionBuilder beanBuilder = BeanDefinitionBuilder.rootBeanDefinition(MyListener.class); | |
| 133 | +// this.context.registerBeanDefinition("myListener", beanBuilder.getBeanDefinition()); | |
| 134 | +// this.context.refresh(); | |
| 135 | +// | |
| 136 | +// assertThat(this.context.getBeansOfType(DefaultRocketMQListenerContainer.class)).isNotEmpty(); | |
| 137 | +// assertThat(this.context.containsBean(DefaultRocketMQListenerContainer.class.getName() + "_1")).isTrue(); | |
| 138 | +// | |
| 139 | +// DefaultRocketMQListenerContainer listenerContainer = | |
| 140 | +// this.context.getBean(DefaultRocketMQListenerContainer.class.getName() + "_1", | |
| 141 | +// DefaultRocketMQListenerContainer.class); | |
| 142 | +// ObjectMapper objectMapper = this.context.getBean("rocketMQMessageObjectMapper", ObjectMapper.class); | |
| 143 | +// assertThat(listenerContainer.getObjectMapper()).isEqualTo(objectMapper); | |
| 144 | +// assertThat(listenerContainer.getConsumeMode()).isEqualTo(ConsumeMode.CONCURRENTLY); | |
| 145 | +// assertThat(listenerContainer.getSelectorType()).isEqualTo(SelectorType.TAG); | |
| 146 | +// assertThat(listenerContainer.getSelectorExpress()).isEqualTo("*"); | |
| 147 | +// assertThat(listenerContainer.getConsumerGroup()).isEqualTo(TEST_CONSUMER_GROUP); | |
| 148 | +// assertThat(listenerContainer.getTopic()).isEqualTo(TEST_TOPIC); | |
| 149 | +// assertThat(listenerContainer.getNameServer()).isEqualTo("127.0.0.1:9876"); | |
| 150 | +// assertThat(listenerContainer.getMessageModel()).isEqualTo(MessageModel.CLUSTERING); | |
| 151 | +// assertThat(listenerContainer.getConsumeThreadMax()).isEqualTo(1); | |
| 152 | +// } | |
| 153 | +// | |
| 154 | +// @After | |
| 155 | +// public void closeContext() { | |
| 156 | +// if (this.context != null) { | |
| 157 | +// this.context.close(); | |
| 158 | +// } | |
| 159 | +// } | |
| 160 | +// | |
| 161 | +// @RocketMQMessageListener(consumerGroup = TEST_CONSUMER_GROUP, topic = TEST_TOPIC, consumeThreadMax = 1) | |
| 162 | +// private static class MyListener implements RocketMQListener<String> { | |
| 163 | +// | |
| 164 | +// @Override | |
| 165 | +// public void onMessage(String message) { | |
| 166 | +// System.out.println(message); | |
| 167 | +// } | |
| 168 | +// } | |
| 169 | +// | |
| 170 | +// private void load(boolean refresh, String... environment) { | |
| 171 | +// AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); | |
| 172 | +// ctx.register(RocketMQAutoConfiguration.class); | |
| 173 | +// EnvironmentTestUtils.addEnvironment(ctx, environment); | |
| 174 | +// if (refresh) { | |
| 175 | +// ctx.refresh(); | |
| 176 | +// } | |
| 177 | +// this.context = ctx; | |
| 178 | +// } | |
| 179 | +// | |
| 180 | +// private void load(String... environment) { | |
| 181 | +// load(true, environment); | |
| 182 | +// } | |
| 183 | +//} | |
| 184 | +// | ... | ... |