WebSphere MQ Java 应用开发简单实例(下篇:绑定模式开发)(client mode和binding mode)

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/MePlusPlus/article/details/52847683
         <!--一个博主专栏付费入口结束-->
        <link rel="stylesheet" href="https://csdnimg.cn/release/phoenix/template/css/ck_htmledit_views-d284373521.css">
                                    <div id="content_views" class="markdown_views">
                <!-- flowchart 箭头图标 勿删 -->
                <svg xmlns="http://www.w3.org/2000/svg" style="display: none;">
                    <path stroke-linecap="round" d="M5,0 0,2.5 5,5z" id="raphael-marker-block" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);"></path>
                </svg>
                                        <p><em>* MQ服务器的配置参加上篇*</em></p>

4-绑定模式连接

Java应用程序必须和MQ服务器安装在同一个机器上,通过进程间通信机制,不通过TCP/IP进行通信,减少网络开销。
MQ提供32和64位版本的MQ JNI库,默认在/opt/mqm/java/lib/和/opt/mqm/java/lib64/目录下:
mqjbnd.so: 该库为应用提供绑定模式连接MQ;

修改代码:其实变动更小,只要将主机地址和端口去掉即可,因为绑定模式不需要网络通信,此外也不需要TCP通道参数。

 
 
  • 1
  • 2
  • 3
  • 4
  • 5
import java.io.IOException;
import com.ibm.mq.MQEnvironment;
import com.ibm.mq.MQException;
import com.ibm.mq.MQGetMessageOptions;
import com.ibm.mq.MQMessage;
import com.ibm.mq.MQPutMessageOptions;
import com.ibm.mq.MQQueue;
import com.ibm.mq.MQQueueManager;
import com.ibm.mq.constants.CMQC;
import com.ibm.mq.constants.MQConstants;

public class MQTest2 {

    public static void main(String[] args) throws MQException, IOException 
    {
        //发送消息给队列
        put();

        //从队列读取消息
        get();
    }

    static void put() throws MQException, IOException
    {
        //配置MQ服务器连接参数

        //用户名和密码
        MQEnvironment.userID = "mquser1";
        MQEnvironment.password = "mqtest2016";
        //设置应用名称,方便服务器MQ 查看应用连接
        MQEnvironment.properties.put(MQConstants.APPNAME_PROPERTY, "MQ Test By Java");

        //设置绑定模式通信
        MQEnvironment.properties.put(CMQC.TRANSPORT_PROPERTY,CMQC.TRANSPORT_MQSERIES_BINDINGS);

        //创建实例,连接队列管理器
        MQQueueManager queueManager = new MQQueueManager("JAVA.QUEUE.MANAGER.1");

        //以可写的方式访问队列管理器已定义的队列QUEUE1,当然也可以创建队列
        MQQueue putQueue = queueManager.accessQueue("QUEUE1", CMQC.MQOO_OUTPUT);

        //新建并发送消息给队列
        MQMessage myMessage = new MQMessage();
        String name = "MePlusPlus's 博客2";
        myMessage.writeUTF(name);

        //使用默认的消息选项
        MQPutMessageOptions pmo = new MQPutMessageOptions();
        //发送消息
        putQueue.put(myMessage, pmo);
        putQueue.close();

        //断开连接
        queueManager.disconnect();
    }

    static void get() throws MQException, IOException
    {
        //配置MQ服务器连接参数
        MQEnvironment.userID = "mquser1";
        MQEnvironment.password = "mqtest2016";
        //设置应用名称,方便服务器MQ 查看应用连接
        MQEnvironment.properties.put(MQConstants.APPNAME_PROPERTY, "MQ Test By Java");
        MQEnvironment.properties.put(CMQC.TRANSPORT_PROPERTY, CMQC.TRANSPORT_MQSERIES_BINDINGS);

        //创建实例,连接队列管理器
        MQQueueManager queueManager = new MQQueueManager("JAVA.QUEUE.MANAGER.1");

        //以可读的方式访问队列管理器已定义的队列QUEUE1
        MQQueue getQueue = queueManager.accessQueue("QUEUE1", CMQC.MQOO_INPUT_AS_Q_DEF);

        //从队列读取消息
        MQMessage theMessage = new MQMessage();
        MQGetMessageOptions gmo = new MQGetMessageOptions();
        getQueue.get(theMessage, gmo);

        String name = theMessage.readUTF();

        System.out.println(name);
        getQueue.close();

        //断开连接
        queueManager.disconnect();
    }
}

 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
编译运行:
# cd /home/mq
# /home/jdk1.8.0_102/bin/javac -cp /opt/mqm/java/lib/com.ibm.mq.allclient.jar  MQTest2.java
# /home/jdk1.8.0_102/bin/java   -cp /opt/mqm/java/lib/com.ibm.mq.allclient.jar:/home/mq  MQTest2

出现以下错误:

 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

Exception in thread "main" com.ibm.mq.MQException: MQJE001: 完成代码为 '2',原因为 '2495'。
    at com.ibm.mq.MQSESSION.<init>(MQSESSION.java:2065)
    at com.ibm.mq.MQSESSION.getSession(MQSESSION.java:2105)
    at com.ibm.mq.MQManagedConnectionJ11.<init>(MQManagedConnectionJ11.java:210)
    at com.ibm.mq.MQBindingsManagedConnectionFactoryJ11._createManagedConnection(MQBindingsManagedConnectionFactoryJ11.java:187)
    at com.ibm.mq.MQBindingsManagedConnectionFactoryJ11.createManagedConnection(MQBindingsManagedConnectionFactoryJ11.java:233)
    at com.ibm.mq.StoredManagedConnection.<init>(StoredManagedConnection.java:96)
    at com.ibm.mq.MQSimpleConnectionManager.allocateConnection(MQSimpleConnectionManager.java:194)
    at com.ibm.mq.MQQueueManagerFactory.obtainBaseMQQueueManager(MQQueueManagerFactory.java:767)
    at com.ibm.mq.MQQueueManagerFactory.procure(MQQueueManagerFactory.java:715)
    at com.ibm.mq.MQQueueManagerFactory.constructQueueManager(MQQueueManagerFactory.java:678)
    at com.ibm.mq.MQQueueManagerFactory.createQueueManager(MQQueueManagerFactory.java:148)
    at com.ibm.mq.MQQueueManager.<init>(MQQueueManager.java:675)
    at MQTest2.put(MQTest2.java:38)
    at MQTest2.main(MQTest2.java:18)
Caused by: com.ibm.mq.jmqi.local.LocalMQ$3: CC=2;RC=2495;AMQ8598: 未能装入 WebSphere MQ 本机 JNI 库“'mqjbnd'”。
    at com.ibm.mq.jmqi.local.LocalMQ.loadLib(LocalMQ.java:1236)
    at com.ibm.mq.jmqi.local.LocalMQ$1.run(LocalMQ.java:280)
    at java.security.AccessController.doPrivileged(Native Method)
    at com.ibm.mq.jmqi.local.LocalMQ.initialise_inner(LocalMQ.java:268)
    at com.ibm.mq.jmqi.local.LocalMQ.initialise(LocalMQ.java:231)
    at com.ibm.mq.jmqi.local.LocalMQ.<init>(LocalMQ.java:1318)
    at com.ibm.mq.jmqi.local.LocalServer.<init>(LocalServer.java:229)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
    at com.ibm.mq.jmqi.JmqiEnvironment.getInstance(JmqiEnvironment.java:672)
    at com.ibm.mq.jmqi.JmqiEnvironment.getMQI(JmqiEnvironment.java:606)
    at com.ibm.mq.MQSESSION.<init>(MQSESSION.java:2058)
    ... 13 more
Caused by: java.lang.UnsatisfiedLinkError: no mqjbnd in java.library.path
    at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1867)
    at java.lang.Runtime.loadLibrary0(Runtime.java:870)
    at java.lang.System.loadLibrary(System.java:1122)
    at com.ibm.mq.jmqi.local.LocalMQ.loadLib(LocalMQ.java:1208)
    ... 26 more

 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
很明显,上述错误,是因为找不到MQ JNI库,libmqjbnd.so,重新运行,指明该库位置(注意本机是64位操作系统)
# /home/jdk1.8.0_102/bin/java  -Djava.library.path=/opt/mqm/java/lib64  -cp /opt/mqm/java/lib/com.ibm.mq.allclient.jar:/home/mq  MQTest2

再次出错

 
 
  • 1
  • 2
  • 3
  • 4

Exception in thread "main" com.ibm.mq.MQException: MQJE001: 完成代码为 '2',原因为 '2035'。
    at com.ibm.mq.MQManagedConnectionJ11.<init>(MQManagedConnectionJ11.java:251)
    at com.ibm.mq.MQBindingsManagedConnectionFactoryJ11._createManagedConnection(MQBindingsManagedConnectionFactoryJ11.java:187)
    at com.ibm.mq.MQBindingsManagedConnectionFactoryJ11.createManagedConnection(MQBindingsManagedConnectionFactoryJ11.java:233)
    at com.ibm.mq.StoredManagedConnection.<init>(StoredManagedConnection.java:96)
    at com.ibm.mq.MQSimpleConnectionManager.allocateConnection(MQSimpleConnectionManager.java:194)
    at com.ibm.mq.MQQueueManagerFactory.obtainBaseMQQueueManager(MQQueueManagerFactory.java:767)
    at com.ibm.mq.MQQueueManagerFactory.procure(MQQueueManagerFactory.java:715)
    at com.ibm.mq.MQQueueManagerFactory.constructQueueManager(MQQueueManagerFactory.java:678)
    at com.ibm.mq.MQQueueManagerFactory.createQueueManager(MQQueueManagerFactory.java:148)
    at com.ibm.mq.MQQueueManager.<init>(MQQueueManager.java:675)
    at MQTest2.put(MQTest2.java:38)
    at MQTest2.main(MQTest2.java:18)

···

    很明显,表明MQ访问的权限错误,说明在绑定模式下,MQ未能充分授权,可能是队列管理器、通道或者队列对象。

    经过搜索和阅读文档,发现如下几种方式,尝试了以下方法,最终通过最后一种方法解决:
    第一种尝试(**该方法不起效果**):仔细检查服务器端队列管理器和通道等配置发现,

> DEFINE CHANNEL(JAVA.CLIENT.CHANNEL1) CHLTYPE(SVRCONN) TRPTYPE(TCP)

> SET CHLAUTH(JAVA.CLIENT.CHANNEL1) TYPE(ADDRESSMAP) ADDRESS('127.0.0.1') MCAUSER('mquser1')

    这里的channel配置是针对IP地址进行过滤和限制访问的,建立的TCP通道,因此需要新增另一种类型的通道。
    需要新建一个通道,非TCP通道,命名为JAVA.CLIENT.CHANNEL2
    此外发现错误:少配置了 channel的参数,加入代码:
    MQEnvironment.channel = "JAVA.CLIENT.CHANNEL2";

    # su - mqm
    ~ cd /opt/mqm/bin
    ~ source setmqenv -s
    启动脚本执行器,进行设置
    ~ runmqsc JAVA.QUEUE.MANAGER.1
        DEFINE CHANNEL(JAVA.CLIENT.CHANNEL2) CHLTYPE(SVRCONN) 
        SET CHLAUTH('JAVA.CLINET.CHANNEL2') TYPE(USERMAP) ACTION(ADD) CLNTUSER('mquser1') USERSRC(MAP) MCAUSER('mquser1')


    **仍然出错,其实通过绑定模式,不需要通道参数,因为它不通过网络进行通信,是利用进程间通信机制进行消息传递,上述方法无法解决**

    第二种方法:(**该方法有效**)
    在寻找文档和查找MQ Java API文档以后,发现了以下说明,进而找到解决方法,主要是因为执行MQTest2时,
    需要切换到特定用户,本文定义队列管理器和队列时授权给mquser1。

    此外,在类 com.ibm.mq.MQEnvironment的
    [文档](https://www.ibm.com/support/knowledgecenter/SSFKSJ_7.5.0/com.ibm.mq.javadoc.doc/WMQJavaClasses/com/ibm/mq/MQEnvironment.html)
    中有该表述:

> All the methods and attributes of this class apply to the WebSphere MQ classes for Java client connections,

> but only enableTracing(), disableTracing(), properties, version_notice, userID, connOptions and connTag apply to bindings connections.

    翻译出来,很简单,对于绑定模式,MQEnvironment类中只有 enableTracing(), disableTracing(), properties,
    version_notice, userID, connOptions and connTag 这几个方法和属性有效,所以不用设置通道,主机名等属性,
    此外,properties里面很多key也就是重写了类中方法和属性而已。

    因此需要修改MQTest2.java文件,删除不必要的属性,修改后的代码如下:

```java

import java.io.IOException;
import com.ibm.mq.MQEnvironment;
import com.ibm.mq.MQException;
import com.ibm.mq.MQGetMessageOptions;
import com.ibm.mq.MQMessage;
import com.ibm.mq.MQPutMessageOptions;
import com.ibm.mq.MQQueue;
import com.ibm.mq.MQQueueManager;
import com.ibm.mq.constants.CMQC;
import com.ibm.mq.constants.MQConstants;

public class MQTest2 {

    public static void main(String[] args) throws MQException, IOException 
    {
        //发送消息给队列
        put();

        //从队列读取消息
        get();
    }

    static void put() throws MQException, IOException
    {
        //设置应用名称,方便服务器MQ 查看应用连接
        MQEnvironment.properties.put(MQConstants.APPNAME_PROPERTY, "MQ Test By Java");

        //设置绑定模式通信
        MQEnvironment.properties.put(CMQC.TRANSPORT_PROPERTY,CMQC.TRANSPORT_MQSERIES_BINDINGS);

        //创建实例,连接队列管理器
        MQQueueManager queueManager = new MQQueueManager("JAVA.QUEUE.MANAGER.1");

        //以可写的方式访问队列管理器已定义的队列QUEUE1,当然也可以创建队列
        MQQueue putQueue = queueManager.accessQueue("QUEUE1", CMQC.MQOO_OUTPUT);

        //新建并发送消息给队列
        MQMessage myMessage = new MQMessage();
        String name = "MePlusPlus's 博客2";
        myMessage.writeUTF(name);

        //使用默认的消息选项
        MQPutMessageOptions pmo = new MQPutMessageOptions();
        //发送消息
        putQueue.put(myMessage, pmo);
        putQueue.close();

        //断开连接
        queueManager.disconnect();
    }

    static void get() throws MQException, IOException
    {

        //设置应用名称,方便服务器MQ 查看应用连接
        MQEnvironment.properties.put(MQConstants.APPNAME_PROPERTY, "MQ Test By Java");
        MQEnvironment.properties.put(CMQC.TRANSPORT_PROPERTY, CMQC.TRANSPORT_MQSERIES_BINDINGS);

        //创建实例,连接队列管理器
        MQQueueManager queueManager = new MQQueueManager("JAVA.QUEUE.MANAGER.1");

        //以可读的方式访问队列管理器已定义的队列QUEUE1
        MQQueue getQueue = queueManager.accessQueue("QUEUE1", CMQC.MQOO_INPUT_AS_Q_DEF);

        //从队列读取消息
        MQMessage theMessage = new MQMessage();
        MQGetMessageOptions gmo = new MQGetMessageOptions();
        getQueue.get(theMessage, gmo);

        String name = theMessage.readUTF();

        System.out.println(name);
        getQueue.close();

        //断开连接
        queueManager.disconnect();
    }
}

 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
编译运行:
# cd /home/mq
# /home/jdk1.8.0_102/bin/javac  -cp /opt/mqm/java/lib/com.ibm.mq.allclient.jar:/home/mq  MQTest2.java
切换到mquser1执行:(**这个是关键**)
# su - mquser1
~ /home/jdk1.8.0_102/bin/java  -Djava.library.path=/opt/mqm/java/lib64  -cp /opt/mqm/java/lib/com.ibm.mq.allclient.jar:/home/mq  MQTest2

 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

5-MQEnvironment类中的userID和password属性作用初探

MQEnvironment类中的userID和password属性:用来认证MQ应用的用户身份。
如果设置了securityExit属性,应用特定的安全验证流程,则userID和password属性将不起作用被忽略;
默认情况下,如果userID为空时,将默认发送JRE 属性(user.name)作为该属性值;如果设置了,则发送设置值;

此外,目前SecurityExit该接口已经过期,对于绑定模式(binding mode),SecurityExit接口不支持。

因此,userID和password表明应用身份,要和MQ服务器端的安全设置配合使用,本文的示例程序中并没有用上该属性。

上述MQ设置:
SET AUTHREC PROFILE(QUEUE1) OBJTYPE(QUEUE) PRINCIPAL('mquser1') AUTHADD(PUT,GET)
principal属性表明 用户mquser1对于该队列管理器中的队列具有put,get权限。

SET AUTHREC OBJTYPE(QMGR) PRINCIPAL('mquser1') AUTHADD(CONNECT)
principal属性表明mquser1对于队列管理器具有连接的权限

DEFINE CHANNEL(JAVA.CLIENT.CHANNEL1) CHLTYPE(SVRCONN) TRPTYPE(TCP)
SET CHLAUTH(JAVA.CLIENT.CHANNEL1) TYPE(ADDRESSMAP) ADDRESS('127.0.0.1') MCAUSER('mquser1')
这条很重要,表明通过IP地址进行连接过滤,表明127.0.0.1这台机器可以通过通道JAVA.CLIENT.CHANNEL1,并以mquser1的身份访问队列管理器。
也就是说127.0.0.1这台机器无需传递任何身份信息。


那么该userID和password作用有哪些?
实验:对于上述实例中的TCP方式访问的代码,1.不设置该属性,正常运行;2.设置为mquser1和正确的password,正常运行;
3.设置mquser1和不设置password属性,正常运行
4.设置为mquser1和错误的密码无法访问 5.设置不存在的用户mquser2,也无法访问; 6.添加用户mquser2,正常运行
说明MQ服务器对于应用传递过来的userID和password属性并没有忽略,而是一种方式在验证,从上看出是以验证操作系统用户的方式在验证。

此外配合MQ的权限设置,可以
SET CHLAUTH(' generic-channel-name ') TYPE (USERMAP) CLNTUSER(client-user-name) USERSRC(MAP) MCAUSER(user)
通过用户映射,将应用传递过来的userID(也就是client-user-name) 映射成 系统的user(MCAUSER属性)

MQ 安全机制是很复杂的主题,本文未继续深究,对于该属性的安全验证机制,如有新见解,欢迎留言和赐教~~

 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
            <link href="https://csdnimg.cn/release/phoenix/mdeditor/markdown_views-526ced5128.css" rel="stylesheet">
                </div>
</article>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值