隨著計算機網(wǎng)絡(luò)和分布式應(yīng)用的不斷發(fā)展,遠程消息傳遞越來越成為應(yīng)用系統(tǒng)中不可缺少的組成部分。商業(yè)消息中間件的出現(xiàn)保證了消息傳輸?shù)目煽啃裕咝屎桶踩裕瑫r也減少了系統(tǒng)的開發(fā)周期。目前應(yīng)用最多的消息中間件產(chǎn)品為IBM MQSeries。本文就針對MQ的基本操作與配置進行詳細的闡述,希望對讀者有所幫助。 |
MQ中有幾個很重要的組件:隊列管理器(QueueManager)、隊列(Queue)和通道(Channel)。其基本的操作方法如下: |
如果是啟動默認(rèn)的隊列管理器,可以不帶其名字 |
如果隊列是默認(rèn)隊列管理器中的隊列,可以不帶其隊列管理器的名字 |
如果隊列是默認(rèn)隊列管理器中的隊列,可以不帶其隊列管理器的名字 |
runmqchl –c ChlName –m QmgrName |
runmqlsr –t TYPE –p PORT –m QMgrName |
DEFINE QLOCAL(QNAME) DEFPSIST(YES) REPLACE |
DEFINE QALIAS(QALIASNAME) TARGQ(QNAME) |
RNAME(AAA) RQMNAME(QMGRNAME) + |
DEFINE QMODEL(QNAME) DEFTYPE(TEMPDYN) |
DEFINE QLOCAL(QTNAME) USAGE(XMITQ) DEFPSIST(YES) + |
INITQ(SYSTEM.CHANNEL.INITQ)+ |
PROCESS(PROCESSNAME) REPLACE |
DEFINE PROCESS(PRONAME) + |
APPLICID(’ runmqchl -c SDR_TEST -m QM_ TEST’) |
其中APPLTYPE的值可以是:CICS、UNIX、WINDOWS、WINDOWSNT等 |
DEFINE CHANNEL(SDRNAME) CHLTYPE(SDR)+ |
CONNAME(‘100.100.100.215(1418)’) XMITQ(QTNAME) REPLACE |
其中CHLTYPE可以是:SDR、SVR、RCVR、RQSTR、CLNTCONN、SVRCONN、CLUSSDR和CLUSRCVR。 |
DEFINE CHANNEL(SDR_ TEST) CHLTYPE(RCVR) REPLACE |
DEFINE CHANNEL(SVRCONNNAME) CHLTYPE(SVRCONN) REPLACE |
DISPLAY QUEUE(QNAME) [ALL] |
DISPLAY QUEUE(QNAME) DESCR GET PUT |
DISPLAY QUEUE(QNAME)MAXDEPTH CURDEPTH |
ALTER QMGR DESCR(‘NEW DESCRIPTION’) |
ALTER QLOCAL(QNAME) PUT(DISABLED) |
ALTER QALIAS(QNAME) TARGQ(TARGQNAME) |
以上講述了MQ的基本命令操作,但只知道這些是沒有實際意義的。MQ的最終目的是實現(xiàn)遠程通信,所以下面就以一個具體的例子來說明如何實現(xiàn)遠程連接。這個例子的目的是建立可以實現(xiàn)消息傳遞的一對MQ服務(wù)器,它們分別基于NT和UNIX平臺。 |
DEFINE QL(NT.DEADQ) DEFPSIST(YES) REPLACE |
ALTER QMGR DEADQ(NT.DEADQ) |
APPLICID(’ runmqchl -c SDR_NT -m QM_NT’) |
DEFINE QL(QT_NT) USAGE(XMITQ) DEFPSIST(YES) + |
INITQ(SYSTEM.CHANNEL.INITQ)+ |
創(chuàng)建遠程隊列定義,對應(yīng)于UNIX機器上的本地隊列Q_UNIX,傳輸隊列為QT_NT |
RNAME(Q_UNIX) RQMNAME(QM_UNIX)+ |
創(chuàng)建發(fā)送方通道,其傳輸隊列為QT_NT,遠程主機地址為10.10.10.2,偵聽端口為1414 |
DEFINE CHANNEL(SDR_NT) CHLTYPE(SDR)+ |
CONNAME(‘10.10.10.2(1414)’) XMITQ(QT_NT) REPLACE |
DEFINE CHANNEL(S_NT) CHLTYPE(SVRCONN) REPLACE |
MQSeries 1414/tcp #MQSeries channel listener |
修改/etc/inetd.conf文件,加入一行(啟動偵聽程序) |
MQSeries stream tcp nowait mqm /usr/lpp/mqm/bin/amqcrsta amqcrsta –m QM_UNIX |
DEFINE QL(UNIX.DEADQ) DEFPSIST(YES) REPLACE |
ALTER QMGR DEADQ(UNIX.DEADQ) |
創(chuàng)建接收方通道,其名字必須與遠程發(fā)送方相同 |
DEFINE CHANNEL(SDR_NT) CHLTYPE(RCVR) REPLACE |
DEFINE QL(Q_UNIX) DEFPSIST(YES) REPLACE |
DEFINE CHANNEL(S_UNIX) CHLTYPE(SVRCONN) REPLACE |
經(jīng)過以上操作之后,遠程連接的配置工作完成。接下來需要驗證配置是否正確。 |
runmqchl –c SDR_NT –m QM_NT 或 start chl(SDR_NT) |
/usr/mqm/samp/bin/amqsget Q_UNIX QM_UNIX |
另,在NT下一般情況下在建立隊列管理器時會自動建立偵聽器,啟動隊列管理器時則會自動啟動偵聽程序。當(dāng)然也可以手動配置偵聽程序。 |
修改\winnt\system32\drivers\etc\services文件,在文件中加入一行: |
MQSeries 1414/tcp #MQSeries channel listener |
runmqlsr –t tcp –p 1414 –m QM_NT |
以上說明了怎樣建立簡單的單向傳輸網(wǎng)絡(luò)。消息從NT端傳送到UNIX端。建立從UNIX端到NT端的遠程連接和以上相仿,要建立雙向的傳輸網(wǎng)絡(luò)也是同樣的道理。 |
用JMS實現(xiàn)消息的發(fā)送和接收時,經(jīng)常會用到JNDI。因為JNDI這種方式比較靈活,對于編程也比較簡單。 |
在安裝了MQSeries Client for Java之后,在\java\bin目錄下找到JMSAdmin.config文件。該文件主要用來說明Context的存儲方式及存儲地址,對應(yīng)于文件中的兩個參數(shù)INITIAL_CONTEXT_FACTORY和PROVIDER_URL。典型的JMSAdmin.config文件內(nèi)容如下: |
#INITIAL_CONTEXT_FACTORY=com.sun.jndi.ldap.LdapCtxFactory |
INITIAL_CONTEXT_FACTORY=com.sun.jndi.fscontext.RefFSContextFactory |
#INITIAL_CONTEXT_FACTORY=com.ibm.ejs.ns.jndi.CNInitialContextFactory |
#PROVIDER_URL=ldap://polaris/o=ibm,c=us |
PROVIDER_URL=file:/d:/temp |
#PROVIDER_URL=iiop://localhost/ |
SECURITY_AUTHENTICATION=none |
INITIAL_CONTEXT_FACTORY表示JMSAdmin Tool使用的服務(wù)提供商。當(dāng)前有三種受支持的值。com.sun.jndi.ldap.LdapCtxFactory用于LDAP,如果使用它就必須安裝一個LDAP服務(wù)器。com.sun.jndi.fscontext.RefFSContextFactory用于文件系統(tǒng)上下文,它只需要使用者提供存放上下文的文件路徑。com.ibm.ejs.ns.jndi.CNInitialContextFactory是專門為websphere提供的,它需要和websphere的CosNaming資源庫一起使用。 |
PROVIDER_URL表示會話初始上下文的URL,由JMSAdmin tool實現(xiàn)的所有JNDI操作的根。它和INITIAL_CONTEXT_FACTORY一一對應(yīng)。 |
ldap://hostname/contextname 用于LDAP |
file:[drive:]/pathname 用于文件系統(tǒng)上下文 |
iiop://hostname[:port]/[?TargetContext=ctx] 用于訪問websphere CosNaming名稱空間 |
最后還有一個參數(shù)SECURITY_AUTHENTICATION,用于說明JNDI是否把安全性憑證傳遞給了您使用的服務(wù)供應(yīng)商。只有當(dāng)使用了LDAP服務(wù)供應(yīng)商時,才使用此參數(shù)。此參數(shù)有三個值,none(匿名認(rèn)證)、simple(簡單認(rèn)證)和CRAM-MD5認(rèn)證機制。如果沒有提供有效值,缺省值為none。 |
確認(rèn)配置文件之后,可以在\java\bin目錄下啟動JMSAdmin控制臺。也可以在任何目錄下用下面的命令來啟動控制臺: |
JMSAdmin –cfg MQ_JAVA_INSTALL_PATH\java\bin\JMSAdmin.config |
其中MQ_JAVA_INSTALL_PATH為MQSeries Client for Java安裝的根目錄。 |
若啟動失敗,則好好檢查一下您的環(huán)境變量是否設(shè)置正確。根據(jù)我個人的經(jīng)驗,除了把com.ibm.mq.jar和com.ibm.mqjms.jar加入到環(huán)境變量外,還要把fscontext.jar和providerutil.jar加入到環(huán)境變量。 |
進入JMSAdmin控制臺后,您可以自由定義sub context。對于子上下文的操作,主要有一下命令: |
當(dāng)然,在這里的主要任務(wù)并非是用來定義sub context,而是用來定義以下幾個對象: |
(還有其它的一些對象,如MQXAQueueConnectionFactory等,不常用到,在此不作說明。) |
可以使用很多動詞來操縱目錄名稱空間中的受管理對象。ALTER、DEFINE、DISPLAY、DELETE、COPY和MOVE,它們的用法都算比較簡單,這里只列舉一二以作說明。 |
例一:定義一QueueConnectionFactory,連接主機10.10.10.18,端口1414 |
DESC(Example Queue Connection Factory)+ |
例二:定義一Queue,其對應(yīng)于MQ中的Q_EXAMPLE |
上面我們說明了怎樣用JMSAdmin Tool定義MQ對象的上下文。我們的最終目的是要用JMS來實現(xiàn)MQ編程,以實現(xiàn)在程序中對MQ隊列進行收、發(fā)消息。所以,下面我們將重點討論一下MQ的JMS實現(xiàn)。 |
如果您對JMS編程很熟悉,那么您也就會用JMS來實現(xiàn)MQ編程,因為用JMS來編寫MQ程序與編寫一般的JMS程序沒有太大的差別。舉個例子,當(dāng)我們想發(fā)送一條消息到MQ的隊列中,再從該隊列中取回消息時,我們編程時主要有四個步驟。首先我們要初始化在程序中要用到的對象,然后才可以發(fā)送消息到隊列中去,再就是收取消息了,最后要清除那些永久對象。這些都和普通的JMS程序相當(dāng)。程序的源代碼如下: |
import java.util.Hashtable; |
import javax.naming.directory.*; |
protected QueueConnectionFactory factory=null; |
protected QueueConnection connection; |
protected QueueSession queueSession; |
protected TextMessage outMessage; |
protected QueueSender queueSender; |
protected QueueReceiver queueReceiver; |
public static final String qcfLookup="EXAMPLEQCF"; |
public static final String qLookup="EXAMPLEQL"; |
public static final String icf = "com.sun.jndi.fscontext.RefFSContextFactory"; |
public String url ="file:/d:/temp"; |
public void sampleInit() throws Exception { |
Hashtable environment = new Hashtable(); |
environment.put(Context.INITIAL_CONTEXT_FACTORY, icf); |
environment.put(Context.PROVIDER_URL, url); |
environment.put(Context.REFERRAL, "throw"); |
Context ctx=new InitialDirContext(environment); |
factory = (QueueConnectionFactory)ctx.lookup(qcfLookup); |
q1=(Queue)ctx.lookup(qLookup); |
connection = factory.createQueueConnection(); |
queueSession = connection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE); |
queueSender = queueSession.createSender(q1); |
queueSender.setDeliveryMode(DeliveryMode.NON_PERSISTENT); |
outMessage = queueSession.createTextMessage(); |
queueReceiver = queueSession.createReceiver(q1); |
public void sendMessageOut(String message) throws JMSException { |
outMessage.setText(message); |
queueSender.send(outMessage); |
public String receiveMessage() throws Exception{ |
return ((TextMessage)queueReceiver.receive()).getText(); |
public void sampleClose() throws JMSException { |
public static void main(String[] args){ |
sample sp = new sample(); |
sp.sendMessageOut("Hello World!"); |
java.lang.Thread.sleep(4000); |
System.out.println("Receive text is : "+rec); |
MQ在WINDOWS平臺下具有圖形化管理界面,但在UNIX平臺下卻只能通過命令行來進行操作。這樣就給使用者帶來很大的不便。我們都希望能通過圖形界面來進行管理配置。為了實現(xiàn)我們的想法,我們就必須建立遠程管理。 |
1.被管理隊列管理器上的命令隊列SYSTEM.ADMIN.COMMAND.QUEUE存在并可用。對于MQ 2版本應(yīng)執(zhí)行 amqscoma.tst 腳本來創(chuàng)建。 |
2.使用strmqcsv命令來啟動被管理隊列管理器上的命令服務(wù)器。 |
3.確定被管理隊列管理器上的服務(wù)器連接通道SYSTEM.ADMIN.SVRCONN是否存在,如果不存在則創(chuàng)建它。 |
4.一般Unix、Linux平臺中MQ默認(rèn)的字符集為819,而Windows平臺為1381,所以你必須改變其字符集,使兩邊的字符集相同。一般改被管理的字符集。 |
5.如果被管理隊列管理器上的操作用戶與管理隊列管理器上的操作用戶不同,那么你首先要確認(rèn)管理隊列管理器上的操作用戶在被管理隊列管理器上存在并且有管理MQ的權(quán)限,再者,你需要修改服務(wù)器連接通道SYSTEM.ADMIN.SVRCONN的MCAUSER屬性為管理隊列管理器上的操作用戶。 |
做完這些工作之后,直接在管理隊列管理器的MQ管理工具中顯示被管理隊列管理器即可。然后你就可以象操作本地隊列管理器一樣,在被管理隊列管理器上定義你需要的MQ對象。 |
在配置遠程連接的時候,我們曾經(jīng)創(chuàng)建過進程定義。那我們?yōu)槭裁匆?chuàng)建進程定義呢?這就涉及MQ通道維護的概念。 |
通道長時間沒有消息觸發(fā)就會自動斷開連接,不再保持運行狀態(tài)。時間的長短可以由自己設(shè)定,默認(rèn)值為6000秒。消息請求再次來臨的時候,就必須再次啟動通道。有些通道,如服務(wù)器連接通道、接收方通道等是自動觸發(fā)啟動的。當(dāng)消息請求發(fā)送到通道后,通道立即啟動,進入運行狀態(tài)。但也有一些通道不會自動啟動,最典型的就是發(fā)送方通道。當(dāng)有消息請求需要使用通道進行消息傳遞的時候,發(fā)送方通道也不會自動啟動并把消息發(fā)送到遠程隊列,而是把消息留在了與其相關(guān)聯(lián)的傳輸隊列中。 |
但是,在實際應(yīng)用中我們又不可能每過一段時間去啟動一次通道,或當(dāng)有消息來再去啟動通道。那應(yīng)該怎么辦?首先我們創(chuàng)建一個進程定義,這個進程定義的目的就是用來啟動發(fā)送方通道。然后我們在傳輸隊列的進程名稱屬性欄指定剛才定義的進程定義名稱,再把觸發(fā)器控制開關(guān)打開。這樣,當(dāng)有消息進入傳輸隊列后,傳輸隊列的觸發(fā)器會啟動觸發(fā)執(zhí)行指定的進程,從而啟動發(fā)送方通道,把消息傳輸?shù)竭h程隊列中去。 |
也許你會說你已經(jīng)理解了MQ,包括基本概念、配置、管理以及程序的編寫,那么恭喜你。我也希望如此。不過MQ也許并非如此簡單,因本人水平有限,也只能到此為止,希望大家再接再厲。順便說一句,如果有什么好想法,千萬別忘了告訴我一聲。 |
|