ActiveMQ + Camel 實現訊息路由

iteye_401發表於2013-06-06
本文的目的是在 broker 端實現訊息的路由分發,通俗點講就是,根據訊息的特徵將訊息分發到不同的 queue 或者 topic 上。要實現訊息路由,最簡單的方式是在 activemq 提供的 xml 配置檔案下面構建路由規則。
所使用的版本:
  • ActiveMQ 5.6.0
  • Camel 2.9.2
在 ActiveMQ 的每個發行版的 conf 目錄下包含了很多的示例 xml 配置檔案,它們是對 ActiveMQ 重要 feature 的配置舉例,比如使用jdbc作持久化機制時針對不同資料庫的配置、如何進行許可權配置、如何配置 network broker 等等。在研究ActiveMQ的某項特徵時,參考下這裡面的配置會節省很多時間。本文將要實現的功能用到了 conf 目錄下的 activemq.xml 和 camel.xml 兩個檔案。
activemq.xml 是啟動 broker 時預設的配置檔案。如果要使用 camel,我們首先需要將 activemq.xml 中的 “import camel.xml” 的那行註釋去掉。
      <import resource="camel.xml"/>
camel.xml 中的 camelContext 中包含了一個簡單的路由規則:
<route>
        <description>Example Camel Route</description>
        <from uri="activemq:example.A"/>
        <to uri="activemq:example.B"/>
</route>
 
其中 uri 的格式為 activemq:[queue:|topic:]destinationName 在不指定 queue/topic 的情況下,預設為 queue。
它實現的功能很簡單:所有傳送到佇列 example.A 上的訊息都將轉發到佇列 example.B。
camel允許我們在activemq的broker端根據Message的特徵實現路由分發。為此,我們需要一種可以描述路由規則的語言,而camel支援很多這樣的語言(http://camel.apache.org/languages.html)。我選用了 Bean language,這種語言允許我們通過在bean中定義的過濾方法(返回型別為boolean)對訊息進行過濾。並且,可以用spring下bean的定義方式,在xml檔案下注冊這個bean。
import javax.jms.JMSException;
import org.apache.camel.Body;
import org.apache.camel.Header;

public class CamelBean {
	public boolean isEven(@Header("JMSType")String jmsType) throws JMSException {
		return "even".equals(jmsType);
	}
	
	public boolean isOdd(@Header("JMSType")String jmsType) throws JMSException {
		return "odd".equals(jmsType);
	}
	
	public boolean matchBody(@Body String body) {
		if (body.contains("aaa"))
			return true;
		return false;
	}
}
 
我在CamelBean中示例了三種過濾方法。 isEven和isOdd都是通過訊息頭的JMSType作判斷的,而matchBody方法則是檢查實際的訊息體中是否包含“aaa”關鍵字。
為了使用這個bean,我需要將該類打到jar包裡,然後放到activemq主目錄的lib路徑下面。
下一步要做的就是在camel.xml檔案下注冊這個bean。
<bean id="camelBean" class="com.example.activemq.CamelBean"></bean>
最後,也是最關鍵的部分,即將這個bean與camel的路由機制關聯。為此我們需要在 route下面使用 filter。配置如下:
 <route>
            <description>Example Camel Route</description>
            <from uri="activemq:example.A"/>
		<filter>
		    <method ref="camelBean" method="isEven" />
		    <to uri="activemq:example.even"/>
		</filter>
		<filter>
		    <method ref="camelBean" method="isOdd" />
		    <to uri="activemq:example.odd"/>
		</filter>
		<filter>
		    <method ref="camelBean" method="matchBody" />
		    <to uri="activemq:example.aaa"/>
		</filter>
 </route>
 
這段配置實現的功能是:
檢查訊息頭的JMSType值,如果是“even”就將訊息的一個副本傳送到example.even佇列(odd,情況同理);如果檢查訊息內容發現“aaa”關鍵字,則傳送一個訊息副本到example.aaa佇列。注意,同一份訊息是可能會被分發到多個佇列的。
這種配置下,每個訊息到達broker後,broker端要做多次檢查,次數取決於filter的個數。因此,如果filter很多,而且broker接收到的訊息量很大的話,效能上會有一定的影響。
附:建立併傳送訊息的部分示例程式碼:
private void sendMessage() {
		try {
			Queue queue = session.createQueue("example.A");
			final MessageProducer producer = session.createProducer(queue);
			producer.setDeliveryMode(DeliveryMode.PERSISTENT);
			
			TextMessage message = session.createTextMessage("aaabbbbb");
			
			if (ai.incrementAndGet() %2 == 0) {
				message.setJMSType("even");
			} else {
				message.setJMSType("odd");
			}
			
			producer.send(message);
			producer.close();
//			session.close();
		} catch (JMSException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

 

相關文章