RocketMQ整合Spring基礎Java實戰

1.RocketMQ安裝

  1. 首先需要安裝maven工具,因爲RocketMq是使用java代碼實現的,官方的工程使用maven構建,所以需要現在本地安裝maven工具

  2. 下載 RocketMq 壓縮包,將壓縮文件解壓到想要安裝的目錄

    #我的是MAC環境,所以這裏以mac環境爲例
    #解壓並進入安裝目錄
    cd /Users/kangning/apache/rocketmq/
    unzip rocketmq-all-4.4.0-source-release.zip
    
  3. 使用maven編譯下載的源文件

    #進入文件目錄
    cd rocketmq-all-4.4.0/
    #對源文件進行編譯
    mvn -Prelease-all -DskipTests clean install -U
    
  4. 啓動Name Server

    #進入變異完的目錄
    cd distribution/target/apache-rocketmq
    #啓動Name Server
    nohup sh bin/mqnamesrv &
    #查看是否啓動 成功
    tail -f ~/logs/rocketmqlogs/namesrv.log
    #出現:**The Name Server boot success...** 說明成功
    
  5. 啓動Broker

    #啓動Broker
    nohup sh bin/mqbroker -n localhost:9876 &
    #查看是否啓動成功
    tail -f ~/logs/rocketmqlogs/broker.log 
    #出現 **The broker[%s, 172.30.30.233:10911] boot success...**	說明啓動成功
    
  6. 關閉服務

    #關閉broker
    sh bin/mqshutdown broker
    #出現如下則成功:**The mqbroker(36695) is running... Send shutdown request to mqbroker(36695) OK**
    #關閉nameserver
    sh bin/mqshutdown namesrv
    #出現如下則成功:**The mqnamesrv(36664) is running... Send shutdown request to mqnamesrv(36664) OK**
    

2.RocketMQ客戶端

  1. 進入rocketmq-externals項目GitHub地址,選擇對應的rocketmq-console分支,如下圖,可以看到對應的代碼,將代碼clone到本地。因爲只需要分支的代碼,所以下載對應的分支就可以
    $ git clone -b release-rocketmq-console-1.0.0 https://github.com/apache/rocketmq-externals.git
    

選擇對應的rocketmq-console分支

  1. 進入項目文件夾並修改配置文件

    cd rocketmq-externals/rocketmq-console/
    vi src/main/resources/application.properties
    

    配置文件內容:

    #管理後臺訪問上下文路徑,默認爲空,如果填寫,一定要前面加“/”,後面不要加,否則啓動報錯
    server.contextPath=/rocketmq
    #訪問端口
    server.port=8080
    #spring.application.index=true
    spring.application.name=rocketmq-console
    spring.http.encoding.charset=UTF-8
    spring.http.encoding.enabled=true
    spring.http.encoding.force=true
    #logback配置文件路徑
    logging.config=classpath:logback.xml
    #if this value is empty,use env value rocketmq.config.namesrvAddr
    NAMESRV_ADDR | now, you can set it in ops page.default
    localhost:9876
    #Name Server地址,修改成你自己的服務地址
    rocketmq.config.namesrvAddr=10.0.74.198:9876;10.0.74.199:9876
    #if you use rocketmq version < 3.5.8, rocketmq.config.isVIPChannel
    should be false.default true
    rocketmq.config.isVIPChannel=
    #rocketmq-console's data path:dashboard/monitor
    rocketmq.config.dataPath=/tmp/rocketmq-console/data
    #set it false if you don't want use dashboard.default true
    rocketmq.config.enableDashBoardCollect=true
    
  2. 編譯jar包並啓動客戶端命令

    mvn clean package -Dmaven.test.skip=true
    java -jar target/rocketmq-console-ng-1.0.0.jar
    
  3. 訪問路徑本地路徑:http://localhost:8080/rocketmq 即可在頁面操作

3.發送/接收消息

首先需要在客戶端創建消息隊列:TestQueue

   1. 生產者代碼實現
  1. 創建生產者代理對象
    /**
     * @author kangning Date: 2019-04-22 Time: 15:50
     * @version $Id$
     */
    public class CommonDemoProderProxy {
    
        private static final Logger logger = LoggerFactory.getLogger(CommonDemoProderProxy.class);
    
        private DefaultMQProducer defaultMQProducer;
    
        private String nameSrv;
    
        private String groupName;
    
        private String instanceName;
    
        private int retryTimes;
    
        public CommonDemoProderProxy(String nameSrv, String groupName, String instanceName, int retryTimes) {
            try {
                this.nameSrv = nameSrv;
                this.groupName = groupName;
                this.instanceName = instanceName;
                this.retryTimes = retryTimes;
                //新建生產者對象
                this.defaultMQProducer = new DefaultMQProducer(groupName);
                //設置nameserver
                this.defaultMQProducer.setNamesrvAddr(nameSrv);
                //設置實例名稱
                this.defaultMQProducer.setInstanceName(instanceName);
                //設置失敗重試次數
                this.defaultMQProducer.setRetryTimesWhenSendFailed(retryTimes);
                //啓動實例
                this.defaultMQProducer.start();
            } catch (MQClientException e) {
                logger.error("init rocket produce error", e);
            }
        }
    
        /**
         * 實際調用生產者發送消息的接口
         * @param message
         * @return
         * @throws InterruptedException
         * @throws RemotingException
         * @throws MQClientException
         * @throws MQBrokerException
         */
        public SendResult sendMsg(Message message) throws InterruptedException, RemotingException, MQClientException, MQBrokerException {
            return defaultMQProducer.send(message);
        }
    
    
        public DefaultMQProducer getDefaultMQProducer() {
            return defaultMQProducer;
        }
    
        public void setDefaultMQProducer(DefaultMQProducer defaultMQProducer) {
            this.defaultMQProducer = defaultMQProducer;
        }
    
        public String getNameSrv() {
            return nameSrv;
        }
    
        public void setNameSrv(String nameSrv) {
            this.nameSrv = nameSrv;
        }
    
        public String getGroupName() {
            return groupName;
        }
    
        public void setGroupName(String groupName) {
            this.groupName = groupName;
        }
    
        public String getInstanceName() {
            return instanceName;
        }
    
        public void setInstanceName(String instanceName) {
            this.instanceName = instanceName;
        }
    
        public int getRetryTimes() {
            return retryTimes;
        }
    
        public void setRetryTimes(int retryTimes) {
            this.retryTimes = retryTimes;
        }
    
        @Override
        public String toString() {
            return "CommonDemoProderProxy{" +
                "defaultMQProducer=" + defaultMQProducer +
                ", nameSrv='" + nameSrv + '\'' +
                ", groupName='" + groupName + '\'' +
                '}';
        }
    }
    
    
  2. 配置生產者代理信息
    	<bean id="commonDemoProderProxy" class="com.kangning.demo.framework.mq.CommonDemoProderProxy">
            <constructor-arg name="groupName" value="${rocketmq.group}"/>
            <constructor-arg name="nameSrv" value="${rocketmq.namespace}"/>
            <constructor-arg name="instanceName" value="${rocketmq.instanceName}"/>
            <constructor-arg name="retryTimes" value="${rocketmq.retryTimes}"/>
        </bean>
    
  3. 添加基礎生產者抽象類
    /**
     * @author kangning Date: 2019-04-22 Time: 16:39
     * @version $Id$
     */
    public abstract class BaseCommonProducer<T> {
    
        private static final Logger logger = LoggerFactory.getLogger(BaseCommonProducer.class);
    
        @Autowired
        private CommonDemoProderProxy commonDemoProderProxy;
    
        private String topicName;
    
        public SendResult sendMsg(T object){
            Message message = new Message(this.getTopicName(), JSONObject.toJSONString(object).getBytes());
            try {
                return commonDemoProderProxy.sendMsg(message);
            } catch (InterruptedException | RemotingException | MQClientException | MQBrokerException e) {
                logger.error("send rocketMq msg error", e);
                e.printStackTrace();
            }
            return null;
        }
    
        public String getTopicName() {
            return topicName;
        }
    
        public void setTopicName(String topicName) {
            this.topicName = topicName;
        }
    }
    
  4. 添加具體生產者實現類
    /**
     * @author kangning Date: 2019-04-22 Time: 16:57
     * @version $Id$
     */
    public class TestProducer extends BaseCommonProducer<RegionInfo> {
    }
    
  5. 配置具體生產者信息
        <bean id="testProducer" class="com.kangning.demo.rocketmq.producer.TestProducer">
            <property name="topicName" value="TestQueue"/>
        </bean>
    
   2. 消費者代碼實現
  1. 創建消費者公共抽象類(用於規範共有的業務邏輯以及接收到消息之後回調接口處理消息)
    /**
     * @author kangning Date: 2019-04-22 Time: 16:39
     * @version $Id$
     */
    public abstract class BaseCommonConsumer<T> {
    
        private static final Logger logger = LoggerFactory.getLogger(BaseCommonConsumer.class);
    
        public abstract boolean receive(MessageExt messageExt);
    }
    
    
  2. 添加具體的消費者實現
    
    /**
     * @author kangning Date: 2019-04-22 Time: 17:09
     * @version $Id$
     */
    public class TestConsumer extends BaseCommonConsumer<RegionInfo> {
    	@Override
     	public boolean receive(MessageExt messageExt) {
    	   String msgStr = new String(messageExt.getBody());
           RegionInfo regionInfo = JSONObject.parseObject(msgStr,RegionInfo.class);
            System.out.println(regionInfo.getRegionCN());
            return true;
        }
    }
    
  3. 配置消費者bean
    <bean id="testConsumer" class="com.kangning.demo.rocketmq.consumer.TestConsumer"/>
    
  4. 添加消費者代理類
    /**
     * @author kangning Date: 2019-04-22 Time: 17:17
     * @version $Id$
     */
    public class CommonDemoConsumerProxy {
    
        private static final Logger logger = LoggerFactory.getLogger(CommonDemoConsumerProxy.class);
    
        private final Map<String, BaseCommonConsumer> topics;
    
        private String nameSrv;
    
        private String groupName;
    
        private DefaultMQPushConsumer defaultMQPushConsumer;
    
        private String messageModel;
    
        private int reconsumeTimes;
    
        public CommonDemoConsumerProxy(Map<String, BaseCommonConsumer> topics, String nameSrv, String groupName, String messageModel, int reconsumeTimes) {
    
            //檢查消息隊列配置
            if (CollectionUtils.isEmpty(topics)){
                logger.error("no topic={} for group", groupName);
                topics = new HashMap<>(0);
            }
            this.topics = topics;
            this.nameSrv = nameSrv;
            this.groupName = groupName;
            this.defaultMQPushConsumer = new DefaultMQPushConsumer();
            this.messageModel = messageModel;
            this.reconsumeTimes = reconsumeTimes;
    
            MessageModel enumMessageModel = null;
            if (StringUtils.isNoneBlank(this.messageModel)){
                enumMessageModel = EnumUtils.getEnum(MessageModel.class, this.messageModel);
            }
            //初始化消費者信息
            initConsumer(topics, nameSrv, groupName, enumMessageModel, reconsumeTimes);
        }
    
        private void initConsumer(Map<String, BaseCommonConsumer> topics,String nameSrv, String groupName, MessageModel messageModel, int reconsumeTimes) {
            try {
                //設置nameserver
                this.defaultMQPushConsumer.setNamesrvAddr(nameSrv);
                //設置消費者組
                this.defaultMQPushConsumer.setConsumerGroup(groupName);
                //設置啓動時消費起始點
                this.defaultMQPushConsumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_FIRST_OFFSET);
                //設置消費失敗重試次數
                this.defaultMQPushConsumer.setMaxReconsumeTimes(reconsumeTimes);
                //設置消費模式
                if (messageModel == null){
                    //默認集羣模式
                    this.defaultMQPushConsumer.setMessageModel(MessageModel.CLUSTERING);
                }else {
                    this.defaultMQPushConsumer.setMessageModel(messageModel);
                }
                //訂閱消費隊列
                for (Entry<String, BaseCommonConsumer> entry : topics.entrySet()){
                    this.defaultMQPushConsumer.subscribe(entry.getKey(), "*");
                }
                //註冊回調接口
                this.defaultMQPushConsumer.registerMessageListener(new MessageListenerConcurrently() {
                    //消費消息
                    @Override
                    public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs, ConsumeConcurrentlyContext context) {
                        for (MessageExt messageExt : msgs){
                            //獲取消息隊列對應的具體消費者
                            BaseCommonConsumer baseCommonConsumer = topics.get(messageExt.getTopic());
                            if (baseCommonConsumer == null){
                                logger.error("no topic={} for service", messageExt.getTopic());
                            }
                            try {
                                //調用回調接口receive處理消息
                                if (baseCommonConsumer== null || !baseCommonConsumer.receive(messageExt)){
                                    //返回消費失敗
                                    return ConsumeConcurrentlyStatus.RECONSUME_LATER;
                                }
                            } catch (Exception var6) {
                                logger.error("consumer message error", var6);
                                return ConsumeConcurrentlyStatus.RECONSUME_LATER;
                            }
                        }
                        //返回消費成功
                        return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
                    }
                });
                //啓動消費者實例
                this.defaultMQPushConsumer.start();
            } catch (MQClientException e) {
                logger.error("init rocket consumer error", e);
            }
        }
    
        public Map<String, BaseCommonConsumer> getTopics() {
            return topics;
        }
    
        public String getNameSrv() {
            return nameSrv;
        }
    
        public void setNameSrv(String nameSrv) {
            this.nameSrv = nameSrv;
        }
    
        public String getGroupName() {
            return groupName;
        }
    
        public void setGroupName(String groupName) {
            this.groupName = groupName;
        }
    
        public DefaultMQPushConsumer getDefaultMQPushConsumer() {
            return defaultMQPushConsumer;
        }
    
        public void setDefaultMQPushConsumer(DefaultMQPushConsumer defaultMQPushConsumer) {
            this.defaultMQPushConsumer = defaultMQPushConsumer;
        }
    
        public String getMessageModel() {
            return messageModel;
        }
    
        public void setMessageModel(String messageModel) {
            this.messageModel = messageModel;
        }
    
        public int getReconsumeTimes() {
            return reconsumeTimes;
        }
    
        public void setReconsumeTimes(int reconsumeTimes) {
            this.reconsumeTimes = reconsumeTimes;
        }
    
        @Override
        public String toString() {
            return "CommonDemoConsumerProxy{" +
                "topics=" + topics +
                ", nameSrv='" + nameSrv + '\'' +
                ", groupName='" + groupName + '\'' +
                ", defaultMQPushConsumer=" + defaultMQPushConsumer +
                ", messageModel='" + messageModel + '\'' +
                ", reconsumeTimes=" + reconsumeTimes +
                '}';
        }
    }
    
    
  5. 配置消費者代理對象信息
    <bean id="commonDemoConsumerProxy" class="com.kangning.demo.framework.mq.CommonDemoConsumerProxy">
            <constructor-arg name="groupName" value="TestGroup"/>
            <constructor-arg name="nameSrv" value="${rocketmq.namespace}"/>
            <constructor-arg name="topics">
                <map>
                    <entry key="TestQueue" value-ref="testConsumer"/>
                </map>
            </constructor-arg>
            <!--配置參照: org.apache.rocketmq.common.protocol.heartbeat.MessageModel-->
            <constructor-arg name="messageModel" value="CLUSTERING"/>
            <constructor-arg name="reconsumeTimes" value="3"/>
        </bean>
    

到這裏一個簡單的RocketMQ就基本實現了,啓動項目,發送消息即可收到信息

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章