java factory mode_WebSphere MQ Java 应用开发简单实例(下篇)(client mode和binding mode)...

本文详细介绍了如何使用Java实现WebSphere MQ的绑定模式连接,包括配置MQ环境、编写Java代码以及解决遇到的权限问题。在绑定模式下,Java应用程序与MQ服务器在同一机器上,通过本地通信而非TCP/IP。文章还提供了代码示例,演示了如何发送和接收消息,并解释了MQEnvironment类中关键属性的作用。
摘要由CSDN通过智能技术生成

* MQ服务器的配置参加上篇*

4-绑定模式连接

Java应用程序必须和MQ服务器安装在同一个机器上,通过进程间通信机制,不通过TCP/IP进行通信,减少网络开销。

MQ提供32和64位版本的MQ JNI库,默认在/opt/mqm/java/lib/和/opt/mqm/java/lib64/目录下:

mqjbnd.so: 该库为应用提供绑定模式连接MQ;

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

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();

}

}

编译运行:

# 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

出现以下错误:

Exception in thread "main" com.ibm.mq.MQException: MQJE001: 完成代码为 '2',原因为 '2495'。

at com.ibm.mq.MQSESSION.(MQSESSION.java:2065)

at com.ibm.mq.MQSESSION.getSession(MQSESSION.java:2105)

at com.ibm.mq.MQManagedConnectionJ11.(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.(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.(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.(LocalMQ.java:1318)

at com.ibm.mq.jmqi.local.LocalServer.(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.(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

很明显,上述错误,是因为找不到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

再次出错

Exception in thread "main" com.ibm.mq.MQException: MQJE001: 完成代码为 '2',原因为 '2035'。

at com.ibm.mq.MQManagedConnectionJ11.(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.(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.(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();

}

}

编译运行:

# 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

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属性)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值