RocketMQ與OpenMessaging

寫在前面

注意,本章寫在前面的東西比較多,這都是爲了後面的OpenMessaging 與 RocketMq 結合做準備。

1。OpenMessaging 是啥東西。這是一種新興的理論,可以說是理論吧,因爲他並沒有新技術的產生,更像是一種總結,統一管理的概念。大概意思就是,現在消息隊列產品太多了比如,rocketMQ,rabbitMq,kafaka,****啥的,每一種消息發佈產品都有侷限性,比如語言,平臺,消息規範,序列化啥的。爲了避免這種問題,阿里的高級架構師,就提出需要統一度量衡,並率先在自家產品RocketMq 的身上提供的具體的實現,不過這種實現由於提出不久,所以功能比較單一,不是很強大。

2。System.getenv("OMS_RMQ_DIRECT_NAME_SRV"),寫在 環境變量裏面無效。這是由於shell子進程的問題。eclipse(其他軟件同理)也是一個子進程,當先開啓eclipse,後新增變量的時候,由於讀取環境變量不刷新,導致讀取不到,一般的做法是關閉eclipse,然後再開啓即可。注意,是關閉在開啓,而不是重啓。因爲重啓的話,進程並沒有銷燬,新建的過程,導致環境變量也不會重新讀取。具體System.getProperties("")與System.getenv(""),有啥區別,請自行百度。

3。請自行了結RocketMq的基礎知識,這裏不做過多解釋。

正文開始:

pom.xml:

<dependency>
			<groupId>org.apache.rocketmq</groupId>
			<artifactId>rocketmq-client</artifactId>
 <version>4.5.0</version>
		</dependency>
<dependency>
    <groupId>org.apache.rocketmq</groupId>
    <artifactId>rocketmq-openmessaging</artifactId>
    <version>4.5.0</version>
</dependency>

apache官網的openmessaging demo相信大家都看了(http://rocketmq.apache.org/docs/openmessaging-example/),

但由於版本問題,所以運行不成功,這裏做一些解釋,及部分源碼解讀。

生產者:

OpenMeassageProducer.java

package org.equaker.cache.rocketmq;

import java.nio.charset.Charset;

import io.openmessaging.Future;
import io.openmessaging.FutureListener;
import io.openmessaging.Message;
import io.openmessaging.MessagingAccessPoint;
import io.openmessaging.internal.DefaultKeyValue;
import io.openmessaging.internal.MessagingAccessPointAdapter;
import io.openmessaging.producer.Producer;
import io.openmessaging.producer.SendResult;

public class OpenMeassageProducer {
	 public static void main(String[] args) {

		 
		 DefaultKeyValue defaultKeyValue = new DefaultKeyValue();
		 
		 final MessagingAccessPoint messagingAccessPoint =
				 MessagingAccessPointAdapter.getMessagingAccessPoint("oms:rocketmq://ip:9876/topic-1",defaultKeyValue);
		        final Producer producer = messagingAccessPoint.createProducer();
		        
		        messagingAccessPoint.startup();
		        System.out.printf("MessagingAccessPoint startup OK%n");

		        producer.startup();
		        
		        System.out.printf("Producer startup OK%n");

		        {
		        	Message message = producer.createBytesMessage("OMS_HELLO_TOPIC", "OMS_HELLO_BODY".getBytes(Charset.forName("UTF-8")));
		            SendResult sendResult = producer.send(message);
		            System.out.printf("Send sync message OK, msgId: %s%n", sendResult.messageId());
		        }

		        {
		            final Future<SendResult> result = producer.sendAsync(producer.createBytesMessage("OMS_HELLO_TOPIC", "OMS_HELLO_BODY".getBytes(Charset.forName("UTF-8"))));
		           
		            result.addListener(new FutureListener<SendResult>() {
						
						@Override
						public void operationComplete(Future<SendResult> future) {
							System.out.printf("Send async message OK, msgId: %s%n", future.get().messageId());
						}
					});
		        }

		        {
		            producer.sendOneway(producer.createBytesMessage("OMS_HELLO_TOPIC", "OMS_HELLO_BODY".getBytes(Charset.forName("UTF-8"))));
		            System.out.printf("Send oneway message OK%n");
		        }

		        producer.shutdown();
		        messagingAccessPoint.shutdown();
	    }
}

運行官網demo或者本文提供的demo的時候,可能會出現,

The OMS driver URL [openmessaging:rocketmq://ip:9876] is illegal,

name server is null,please set it

大概就是這個意思吧,我們可以看到源碼裏面的規範。

 OpenMessaging的協議以oms開頭,並不是官網提供的openmessaging,uri總共分爲四部分,

例如:oms:rocketmq://127.0.0.1:9876/topic-1

第一部分oms,這一部分指定openmessaging協議,一般不會改變,類似http,jdbc啥的。

第二部分rocketmq,指定具體的消息隊列產品,目前市場上,好像也只有rocketmq,提供了openmessaging的部分實現。等其他消息隊列產品提供實現的時候,會提供協議的。

第三部分127.0.0.1:9876,就是簡單的消息隊列產品地址了,這個沒啥解釋的。

第四部分/topic-1,一個域信息,相當於,做一個分類的作用。

所以,粗出現上述異常的時候,請先檢查自己的url地址。

當url沒有問題的時候,還有一個坑等着你呢。來,我們接着看源碼。

1,創建producer對象。

接着源碼走,創建生產者實現類。

再走,實例化父類AbstractOMSProducer。

最後的源碼,

總結:當創建消息生產者Producer的時候,他會讀取系統環境變量OMS_RMQ_DIRECT_NAME_SRV,如果爲true,就會設置name server,我們知道rocketmq必須要設置name server的,他起到一個路由的作用。

所以必須設置環境變量,

我的設置如下:

記得關閉,重啓eclipse。

這下子,消息生產者可以運行成功了。接下來就是消費者了。

 消費者:

 

消費者-1:

OpenMessagingPullConsumer.java

package org.equaker.cache.rocketmq;

import io.openmessaging.Message;
import io.openmessaging.MessagingAccessPoint;
import io.openmessaging.OMSBuiltinKeys;
import io.openmessaging.consumer.PullConsumer;
import io.openmessaging.internal.DefaultKeyValue;
import io.openmessaging.internal.MessagingAccessPointAdapter;
import io.openmessaging.rocketmq.domain.NonStandardKeys;

public class OpenMessagingPullConsumer {
	public static void main(String[] args) {
		
		DefaultKeyValue defaultKeyValue = new DefaultKeyValue();
		defaultKeyValue.put(NonStandardKeys.CONSUMER_GROUP, "consume1");
		defaultKeyValue.put(OMSBuiltinKeys.CONSUMER_ID,"1");
		defaultKeyValue.put(OMSBuiltinKeys.REGION,"OMS_HELLO_TOPIC");
		//defaultKeyValue.put(OMSBuiltinKeys.OPERATION_TIMEOUT, );
		final MessagingAccessPoint messagingAccessPoint = MessagingAccessPointAdapter
				.getMessagingAccessPoint("oms:rocketmq://***:9876/topic-1", defaultKeyValue);

		final PullConsumer consumer = messagingAccessPoint
				.createPullConsumer(defaultKeyValue);
        //設置topic
		consumer.attachQueue("OMS_HELLO_TOPIC",defaultKeyValue);
		messagingAccessPoint.startup();
		System.out.printf("MessagingAccessPoint startup OK%n");

		
		System.out.printf("Consumer startup OK%n");
		consumer.startup();
		
		Integer count = 0;
        //輪詢,獲取message
		while(true) {
			System.out.println("輪詢:"+ count++);
			Message message = consumer.receive();
		
			if (message != null) {
				
				System.out.println("body:>>>"+new String(message.getBody(byte[].class)));
				String msgId = message.sysHeaders().getString(Message.BuiltinKeys.MESSAGE_ID);
				System.out.printf("Received one message: %s%n", msgId);
				consumer.ack(msgId);
			}
		}
		
		
//		consumer.shutdown();
//		messagingAccessPoint.shutdown();
	}
}

這是官網PullConsumer的例子,

這裏的運行只需要注意幾個小問題即可,首先沒有設置customer group的話,會報異常,但是這個customer group 不是

defaultKeyValue.put(NonStandardKeys.CONSUMER_GROUP, "consume1");

而是,

defaultKeyValue.put(OMSBuiltinKeys.CONSUMER_ID,"1");

我們看一下源碼

顯然,沒有設置customer_id的話會報異常。 至於他參數解析的過程涉及到參數的命名規範問題。

規則就在這裏了,就是會根據屬性反射調用set方法。醜陋的代碼總會有的。

 一定要注意設置

consumer.attachQueue("OMS_HELLO_TOPIC",defaultKeyValue);

相當於訂閱話題。不然,鬼知道你要哪樣的信息。

消費者-2:

OpenMessagingPushConsumer.java

package org.equaker.cache.rocketmq;

import io.openmessaging.Message;
import io.openmessaging.MessagingAccessPoint;
import io.openmessaging.OMS;
import io.openmessaging.OMSBuiltinKeys;
import io.openmessaging.consumer.MessageListener;
import io.openmessaging.consumer.PushConsumer;
import io.openmessaging.internal.DefaultKeyValue;
import io.openmessaging.internal.MessagingAccessPointAdapter;
import io.openmessaging.rocketmq.domain.NonStandardKeys;

public class OpenMessagingPushConsumer {
	
	public static void main(String[] args) {
		
		DefaultKeyValue defaultKeyValue = new DefaultKeyValue();
		defaultKeyValue.put(NonStandardKeys.CONSUMER_GROUP, "consume1");
		defaultKeyValue.put(OMSBuiltinKeys.CONSUMER_ID,"1");
		defaultKeyValue.put(OMSBuiltinKeys.REGION,"OMS_HELLO_TOPIC");
		
        final MessagingAccessPoint messagingAccessPoint = MessagingAccessPointAdapter
            .getMessagingAccessPoint("oms:rocketmq://127.0.0.1:9876/topic-1",defaultKeyValue);

        final PushConsumer consumer = messagingAccessPoint.
            createPushConsumer(OMS.newKeyValue().put(NonStandardKeys.CONSUMER_GROUP, "OMS_CONSUMER"));

        messagingAccessPoint.startup();
        System.out.printf("MessagingAccessPoint startup OK%n");

        Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
            @Override
            public void run() {
                consumer.shutdown();
                messagingAccessPoint.shutdown();
            }
        }));
        
        consumer.attachQueue("OMS_HELLO_TOPIC", new MessageListener() {
            @Override
            public void onReceived(Message message, Context context) {
            	System.out.println("body:>>>"+new String(message.getBody(byte[].class)));
                System.out.printf("Received one message: %s%n", message.sysHeaders().getString(Message.BuiltinKeys.MESSAGE_ID));
                context.ack();
            }
        });
        consumer.startup();
        System.out.printf("Consumer Started.%n");
    }
}

這個 也就比 pullConsumer 多了一個消息監聽器,不用採用輪詢的方式查詢消息。其他注意信息,參考PullConsumer

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