IBM MQ學(xué)習(xí)
作者: yaohao 發(fā)表日期: 2006-08-17 17:08 文章屬性: 轉(zhuǎn)載 復(fù)制鏈接?
?
找了好長(zhǎng)時(shí)間只找到這篇!
一.MQ基本操作
????? MQ中有幾個(gè)很重要的組件:隊(duì)列管理器(QueueManager)、隊(duì)列(Queue)和通道(Channel)。其基本的操作方法如下:
????? 創(chuàng)建隊(duì)列管理器
????? crtmqm –q QMgrName
????? -q是指創(chuàng)建缺省的隊(duì)列管理器
????? 刪除隊(duì)列管理器
????? dltmqm QmgrName
????? 啟動(dòng)隊(duì)列管理器
????? strmqm QmgrName
????? 如果是啟動(dòng)默認(rèn)的隊(duì)列管理器,可以不帶其名字
????? 停止隊(duì)列管理器
????? endmqm QmgrName 受控停止
????? endmqm –i QmgrName 立即停止
????? endmqm –p QmgrName 強(qiáng)制停止
????? 顯示隊(duì)列管理器
????? dspmq –m QmgrName
????? 運(yùn)行MQSeries命令
????? runmqsc QmgrName
????? 如果是默認(rèn)隊(duì)列管理器,可以不帶其名字
????? 往隊(duì)列中放消息
????? amqsput QName QmgrName
????? 如果隊(duì)列是默認(rèn)隊(duì)列管理器中的隊(duì)列,可以不帶其隊(duì)列管理器的名字
????? 從隊(duì)列中取出消息
????? amqsget QName QmgrName
????? 如果隊(duì)列是默認(rèn)隊(duì)列管理器中的隊(duì)列,可以不帶其隊(duì)列管理器的名字
????? 啟動(dòng)通道
????? runmqchl –c ChlName –m QmgrName
????? 啟動(dòng)偵聽(tīng)
????? runmqlsr –t TYPE –p PORT –m QMgrName
????? 停止偵聽(tīng)
????? endmqlsr -m QmgrName
????? MQSeries命令
????? 定義死信隊(duì)列
????? DEFINE QLOCAL(QNAME) DEFPSIST(YES) REPLACE
????? 設(shè)定隊(duì)列管理器的死信隊(duì)列
????? ALTER QMGR DEADQ(QNAME)
????? 定義本地隊(duì)列
????? DEFINE QL(QNAME) REPLACE
????? 定義別名隊(duì)列
????? DEFINE QALIAS(QALIASNAME) TARGQ(QNAME)
????? 遠(yuǎn)程隊(duì)列定義
????? DEFINE QREMOTE(QRNAME) +
????? RNAME(AAA) RQMNAME(QMGRNAME) +
????? XMITQ(QTNAME)
????? 定義模型隊(duì)列
????? DEFINE QMODEL(QNAME) DEFTYPE(TEMPDYN)
????? 定義本地傳輸隊(duì)列
????? DEFINE QLOCAL(QTNAME) USAGE(XMITQ) DEFPSIST(YES) +
????? INITQ(SYSTEM.CHANNEL.INITQ)+
????? PROCESS(PROCESSNAME) REPLACE
????? 創(chuàng)建進(jìn)程定義
????? DEFINE PROCESS(PRONAME) +
????? DESCR(‘STRING’)+
????? APPLTYPE(WINDOWSNT)+
????? APPLICID(’ runmqchl -c SDR_TEST -m QM_ TEST’)
????? 其中APPLTYPE的值可以是:CICS、UNIX、WINDOWS、WINDOWSNT等
????? 創(chuàng)建發(fā)送方通道
????? DEFINE CHANNEL(SDRNAME) CHLTYPE(SDR)+
????? CONNAME(‘100.100.100.215(1418)’) XMITQ(QTNAME) REPLACE
????? 其中CHLTYPE可以是:SDR、SVR、RCVR、RQSTR、CLNTCONN、SVRCONN、CLUSSDR和CLUSRCVR。
????? 創(chuàng)建接收方通道
????? DEFINE CHANNEL(SDR_ TEST) CHLTYPE(RCVR) REPLACE
????? 創(chuàng)建服務(wù)器連接通道
????? DEFINE CHANNEL(SVRCONNNAME) CHLTYPE(SVRCONN) REPLACE
????? 顯示隊(duì)列的所有屬性
????? DISPLAY QUEUE(QNAME) [ALL]
????? 顯示隊(duì)列的所選屬性
????? DISPLAY QUEUE(QNAME) DESCR GET PUT
????? DISPLAY QUEUE(QNAME)MAXDEPTH CURDEPTH
????? 顯示隊(duì)列管理器的所有屬性
????? DISPLAY QMGR [ALL]
????? 顯示進(jìn)程定義
????? DISPLAY PROCESS(PRONAME)
????? 更改屬性
????? ALTER QMGR DESCR(‘NEW DESCRIPTION’)
????? ALTER QLOCAL(QNAME) PUT(DISABLED)
????? ALTER QALIAS(QNAME) TARGQ(TARGQNAME)
????? 刪除隊(duì)列
????? DELETE QLOCAL(QNAME)
????? DELETE QREMOTE(QRNAME)
????? 清除隊(duì)列中的所有消息
????? CLEAR QLOCAL(QNAME)
????? 二.配置一個(gè)能夠通信的遠(yuǎn)程連接
????? 以上講述了MQ的基本命令操作,但只知道這些是沒(méi)有實(shí)際意義的。MQ的最終目的是實(shí)現(xiàn)遠(yuǎn)程通信,所以下面就以一個(gè)具體的例子來(lái)說(shuō)明如何實(shí)現(xiàn)遠(yuǎn)程連接。這個(gè)例子的目的是建立可以實(shí)現(xiàn)消息傳遞的一對(duì)MQ服務(wù)器,它們分別基于NT和UNIX平臺(tái)。
????? 首先在NT端建一隊(duì)列管理器
????? crtmqm –q QM_NT
????? 啟動(dòng)隊(duì)列管理器
????? strmqm QM_NT
????? 運(yùn)行MQ控制臺(tái)命令
????? runmqsc QM_NT
????? 創(chuàng)建死信隊(duì)列
????? DEFINE QL(NT.DEADQ) DEFPSIST(YES) REPLACE
????? 更改隊(duì)列管理器屬性,設(shè)置其死信隊(duì)列
????? ALTER QMGR DEADQ(NT.DEADQ)
????? 創(chuàng)建進(jìn)程定義
????? DEFINE PROCESS(P_NT)+
????? APPLTYPE(WINDOWSNT)+
????? APPLICID(’ runmqchl -c SDR_NT -m QM_NT’)
????? 創(chuàng)建本地傳輸隊(duì)列
????? DEFINE QL(QT_NT) USAGE(XMITQ) DEFPSIST(YES) +
????? INITQ(SYSTEM.CHANNEL.INITQ)+
????? PROCESS(P_NT) REPLACE
????? 創(chuàng)建遠(yuǎn)程隊(duì)列定義,對(duì)應(yīng)于UNIX機(jī)器上的本地隊(duì)列Q_UNIX,傳輸隊(duì)列為QT_NT
????? DEFINE QREMOTE(QR_NT)+
????? RNAME(Q_UNIX) RQMNAME(QM_UNIX)+
????? XMITQ(QT_NT)
????? 創(chuàng)建發(fā)送方通道,其傳輸隊(duì)列為QT_NT,遠(yuǎn)程主機(jī)地址為10.10.10.2,偵聽(tīng)端口為1414
????? DEFINE CHANNEL(SDR_NT) CHLTYPE(SDR)+
????? CONNAME(‘10.10.10.2(1414)’) XMITQ(QT_NT) REPLACE
????? 創(chuàng)建服務(wù)器連接通道
????? DEFINE CHANNEL(S_NT) CHLTYPE(SVRCONN) REPLACE
????? 在UNIX端創(chuàng)建隊(duì)列管理器
????? crtmqm –q QM_UNIX
????? 啟動(dòng)隊(duì)列管理器
????? strmqm QM_UNIX
????? 添加偵聽(tīng)程序
????? 修改/etc/services文件,加入一行:
????? MQSeries 1414/tcp #MQSeries channel listener
????? 修改/etc/inetd.conf文件,加入一行(啟動(dòng)偵聽(tīng)程序)
????? MQSeries stream tcp nowait mqm /usr/lpp/mqm/bin/amqcrsta amqcrsta –m
????? QM_UNIX
????? 運(yùn)行以下命令,以使修改起作用
????? refresh –s inetd
????? 運(yùn)行MQ控制臺(tái)命令
????? runmqsc QM_UNIX
????? 創(chuàng)建死信隊(duì)列
????? DEFINE QL(UNIX.DEADQ) DEFPSIST(YES) REPLACE
????? 更改隊(duì)列管理器屬性,設(shè)置其死信隊(duì)列
????? ALTER QMGR DEADQ(UNIX.DEADQ)
????? 創(chuàng)建接收方通道,其名字必須與遠(yuǎn)程發(fā)送方相同
????? DEFINE CHANNEL(SDR_NT) CHLTYPE(RCVR) REPLACE
????? 創(chuàng)建本地隊(duì)列
????? DEFINE QL(Q_UNIX) DEFPSIST(YES) REPLACE
????? 創(chuàng)建服務(wù)器連接通道
????? DEFINE CHANNEL(S_UNIX) CHLTYPE(SVRCONN) REPLACE
????? 經(jīng)過(guò)以上操作之后,遠(yuǎn)程連接的配置工作完成。接下來(lái)需要驗(yàn)證配置是否正確。
????? 在NT端啟動(dòng)發(fā)送方通道
????? runmqchl –c SDR_NT –m QM_NT 或 start chl(SDR_NT)
????? 從NT端發(fā)送消息到UNIX端
????? amqsput QR_NT QM_NT
????? 在UNIX端接收消息
????? /usr/mqm/samp/bin/amqsget Q_UNIX QM_UNIX
????? 若能收到消息,說(shuō)明配置成功。
????? 另,在NT下一般情況下在建立隊(duì)列管理器時(shí)會(huì)自動(dòng)建立偵聽(tīng)器,啟動(dòng)隊(duì)列管理器時(shí)則會(huì)自動(dòng)啟動(dòng)偵聽(tīng)程序。當(dāng)然也可以手動(dòng)配置偵聽(tīng)程序。
????? 修改\winnt\system32\drivers\etc\services文件,在文件中加入一行:
????? MQSeries 1414/tcp #MQSeries channel listener
????? 啟動(dòng)偵聽(tīng)程序
????? runmqlsr –t tcp –p 1414 –m QM_NT
????? 以上說(shuō)明了怎樣建立簡(jiǎn)單的單向傳輸網(wǎng)絡(luò)。消息從NT端傳送到UNIX端。建立從UNIX端到NT端的遠(yuǎn)程連接和以上相仿,要建立雙向的傳輸網(wǎng)絡(luò)也是同樣的道理。
????? 三.配置JNDI
????? 用JMS實(shí)現(xiàn)消息的發(fā)送和接收時(shí),經(jīng)常會(huì)用到JNDI。因?yàn)镴NDI這種方式比較靈活,對(duì)于編程也比較簡(jiǎn)單。
????? 在安裝了MQSeries Client for
????? Java之后,在\java\bin目錄下找到JMSAdmin.config文件。該文件主要用來(lái)說(shuō)明Context的存儲(chǔ)方式及存儲(chǔ)地址,對(duì)應(yīng)于文件中的兩個(gè)參數(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,如果使用它就必須安裝一個(gè)LDAP服務(wù)器。com.sun.jndi.fscontext.RefFSContextFactory用于文件系統(tǒng)上下文,它只需要使用者提供存放上下文的文件路徑。com.ibm.ejs.ns.jndi.CNInitialContextFactory是專門為 websphere提供的,它需要和websphere的CosNaming資源庫(kù)一起使用。
????? PROVIDER_URL表示會(huì)話初始上下文的URL,由JMSAdmin
????? tool實(shí)現(xiàn)的所有JNDI操作的根。它和INITIAL_CONTEXT_FACTORY一一對(duì)應(yīng)。
????? ldap://hostname/contextname 用于LDAP
????? file:[drive:]/pathname 用于文件系統(tǒng)上下文
????? iiop://hostname[:port]/[?TargetContext=ctx] 用于訪問(wèn)websphere
????? CosNaming名稱空間
????? 最后還有一個(gè)參數(shù)SECURITY_AUTHENTICATION,用于說(shuō)明JNDI是否把安全性憑證傳遞給了您使用的服務(wù)供應(yīng)商。只有當(dāng)使用了LDAP服務(wù)供應(yīng)商時(shí),才使用此參數(shù)。此參數(shù)有三個(gè)值,none(匿名認(rèn)證)、simple(簡(jiǎn)單認(rèn)證)和CRAM-MD5認(rèn)證機(jī)制。如果沒(méi)有提供有效值,缺省值為none。
????? 確認(rèn)配置文件之后,可以在\java\bin目錄下啟動(dòng)JMSAdmin控制臺(tái)。也可以在任何目錄下用下面的命令來(lái)啟動(dòng)控制臺(tái):
????? JMSAdmin –cfg MQ_JAVA_INSTALL_PATH\java\bin\JMSAdmin.config
????? 其中MQ_JAVA_INSTALL_PATH為MQSeries Client for Java安裝的根目錄。
????? 若啟動(dòng)失敗,則好好檢查一下您的環(huán)境變量是否設(shè)置正確。根據(jù)我個(gè)人的經(jīng)驗(yàn),除了把com.ibm.mq.jar和com.ibm.mqjms.jar加入到環(huán)境變量外,還要把fscontext.jar和providerutil.jar加入到環(huán)境變量。
????? 進(jìn)入JMSAdmin控制臺(tái)后,您可以自由定義sub context。對(duì)于子上下文的操作,主要有一下命令:
????? display ctx
????? define ctx(ctxname)
????? change ctx(ctxname)
????? change ctx(=up)
????? change ctx(=init)
????? delete ctx(ctxname)
????? 當(dāng)然,在這里的主要任務(wù)并非是用來(lái)定義sub context,而是用來(lái)定義以下幾個(gè)對(duì)象:
????? MQQueueConnectionFactory
????? MQTopicConnectionFactory
????? MQQueue
????? MQTopic
????? (還有其它的一些對(duì)象,如MQXAQueueConnectionFactory等,不常用到,在此不作說(shuō)明。)
????? 可以使用很多動(dòng)詞來(lái)操縱目錄名稱空間中的受管理對(duì)象。ALTER、DEFINE、DISPLAY、DELETE、COPY和MOVE,它們的用法都算比較簡(jiǎn)單,這里只列舉一二以作說(shuō)明。
????? 例一:定義一QueueConnectionFactory,連接主機(jī)10.10.10.18,端口1414
????? DEFINE QCF(EXAMPLEQCF)+
????? DESC(Example Queue Connection Factory)+
????? TRAN(CLIENT)+
????? HOST(10.10.10.18)+
????? QMGR(QM_EXAMPLE)+
????? CHAN(S_EXAMPLE)+
????? PORT(1414)+
????? CCSID(1381)
????? 例二:定義一Queue,其對(duì)應(yīng)于MQ中的Q_EXAMPLE
????? DEFINE Q(EXAMPLEQL)+
????? DESC(Local queue)+
????? QMGR(QM_EXAMPLE)+
????? QUEUE(Q_EXAMPLE)+
????? CCSID(1381)
????? 四.用JMS實(shí)現(xiàn)MQ編程
????? 上面我們說(shuō)明了怎樣用JMSAdmin
????? Tool定義MQ對(duì)象的上下文。我們的最終目的是要用JMS來(lái)實(shí)現(xiàn)MQ編程,以實(shí)現(xiàn)在程序中對(duì)MQ隊(duì)列進(jìn)行收、發(fā)消息。所以,下面我們將重點(diǎn)討論一下MQ的JMS實(shí)現(xiàn)。
????? 如果您對(duì)JMS編程很熟悉,那么您也就會(huì)用JMS來(lái)實(shí)現(xiàn)MQ編程,因?yàn)橛肑MS來(lái)編寫(xiě)MQ程序與編寫(xiě)一般的JMS程序沒(méi)有太大的差別。舉個(gè)例子,當(dāng)我們想發(fā)送一條消息到MQ的隊(duì)列中,再?gòu)脑撽?duì)列中取回消息時(shí),我們編程時(shí)主要有四個(gè)步驟。首先我們要初始化在程序中要用到的對(duì)象,然后才可以發(fā)送消息到隊(duì)列中去,再就是收取消息了,最后要清除那些永久對(duì)象。這些都和普通的JMS程序相當(dāng)。程序的源代碼如下:
????? import java.util.Hashtable;
????? import javax.jms.*;
????? import javax.naming.*;
????? import javax.naming.directory.*;
????? public class sample {
????? 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);
????? Queue q1=null;
????? 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);
????? connection.start();
????? }
????? 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 {
????? queueSession.close();
????? connection.close();
????? }
????? public static void main(String[] args){
????? String rec;
????? sample sp = new sample();
????? try {
????? sp.sampleInit();
????? sp.sendMessageOut("Hello World!");
????? java.lang.Thread.sleep(4000);
????? rec=sp.receiveMessage();
????? System.out.println("Receive text is : "+rec);
????? sp.sampleClose();
????? }catch(Exception e) {
????? e.printStackTrace();
????? }
????? }
????? }
????? 五.遠(yuǎn)程管理
????? MQ在WINDOWS平臺(tái)下具有圖形化管理界面,但在UNIX平臺(tái)下卻只能通過(guò)命令行來(lái)進(jìn)行操作。這樣就給使用者帶來(lái)很大的不便。我們都希望能通過(guò)圖形界面來(lái)進(jìn)行管理配置。為了實(shí)現(xiàn)我們的想法,我們就必須建立遠(yuǎn)程管理。
????? 實(shí)現(xiàn)遠(yuǎn)程管理有以下幾個(gè)步驟:
????? 1.被管理隊(duì)列管理器上的命令隊(duì)列SYSTEM.ADMIN.COMMAND.QUEUE存在并可用。對(duì)于MQ 2版本應(yīng)執(zhí)行
????? amqscoma.tst 腳本來(lái)創(chuàng)建。
????? 2.使用strmqcsv命令來(lái)啟動(dòng)被管理隊(duì)列管理器上的命令服務(wù)器。
????? 3.確定被管理隊(duì)列管理器上的服務(wù)器連接通道SYSTEM.ADMIN.SVRCONN是否存在,如果不存在則創(chuàng)建它。
????? 4.一般Unix、Linux平臺(tái)中MQ默認(rèn)的字符集為819,而Windows平臺(tái)為1381,所以你必須改變其字符集,使兩邊的字符集相同。一般改被管理的字符集。
????? 5.如果被管理隊(duì)列管理器上的操作用戶與管理隊(duì)列管理器上的操作用戶不同,那么你首先要確認(rèn)管理隊(duì)列管理器上的操作用戶在被管理隊(duì)列管理器上存在并且有管理MQ的權(quán)限,再者,你需要修改服務(wù)器連接通道SYSTEM.ADMIN.SVRCONN的MCAUSER屬性為管理隊(duì)列管理器上的操作用戶。
????? 6.啟動(dòng)被管理隊(duì)列管理器上的偵聽(tīng)器。
????? 做完這些工作之后,直接在管理隊(duì)列管理器的MQ管理工具中顯示被管理隊(duì)列管理器即可。然后你就可以象操作本地隊(duì)列管理器一樣,在被管理隊(duì)列管理器上定義你需要的MQ對(duì)象。
????? 六.通道維護(hù)
????? 在配置遠(yuǎn)程連接的時(shí)候,我們?cè)?jīng)創(chuàng)建過(guò)進(jìn)程定義。那我們?yōu)槭裁匆?chuàng)建進(jìn)程定義呢?這就涉及MQ通道維護(hù)的概念。
????? 通道長(zhǎng)時(shí)間沒(méi)有消息觸發(fā)就會(huì)自動(dòng)斷開(kāi)連接,不再保持運(yùn)行狀態(tài)。時(shí)間的長(zhǎng)短可以由自己設(shè)定,默認(rèn)值為6000秒。消息請(qǐng)求再次來(lái)臨的時(shí)候,就必須再次啟動(dòng)通道。有些通道,如服務(wù)器連接通道、接收方通道等是自動(dòng)觸發(fā)啟動(dòng)的。當(dāng)消息請(qǐng)求發(fā)送到通道后,通道立即啟動(dòng),進(jìn)入運(yùn)行狀態(tài)。但也有一些通道不會(huì)自動(dòng)啟動(dòng),最典型的就是發(fā)送方通道。當(dāng)有消息請(qǐng)求需要使用通道進(jìn)行消息傳遞的時(shí)候,發(fā)送方通道也不會(huì)自動(dòng)啟動(dòng)并把消息發(fā)送到遠(yuǎn)程隊(duì)列,而是把消息留在了與其相關(guān)聯(lián)的傳輸隊(duì)列中。
????? 但是,在實(shí)際應(yīng)用中我們又不可能每過(guò)一段時(shí)間去啟動(dòng)一次通道,或當(dāng)有消息來(lái)再去啟動(dòng)通道。那應(yīng)該怎么辦?首先我們創(chuàng)建一個(gè)進(jìn)程定義,這個(gè)進(jìn)程定義的目的就是用來(lái)啟動(dòng)發(fā)送方通道。然后我們?cè)趥鬏旉?duì)列的進(jìn)程名稱屬性欄指定剛才定義的進(jìn)程定義名稱,再把觸發(fā)器控制開(kāi)關(guān)打開(kāi)。這樣,當(dāng)有消息進(jìn)入傳輸隊(duì)列后,傳輸隊(duì)列的觸發(fā)器會(huì)啟動(dòng)觸發(fā)執(zhí)行指定的進(jìn)程,從而啟動(dòng)發(fā)送方通道,把消息傳輸?shù)竭h(yuǎn)程隊(duì)列中去。
?