jms queue,topic发送和接收
说明:这次博客内容共分为三部分,第一部分为背景说明以及环境创建,第二部分为jms queue发送和接收,三部分jms topic 的发送和接收
第一部分:背景
我们使用的消息服务的提供者是Tibco.Tibco也是jms标准制定参与者之一,它的API符合JMS的规范,所以看完本博客之后,如果使用其他厂商的JMS产品只需要替换一下实现类即可.
因为版权问题我在这里就不在上传Tibco软件了,有兴趣的的朋友可以去搜索一下(Tibco在国内使用的比较少,资源会少一些)
首先假设我们已经搭建好了jms服务(搭建服务也很简单,下载Tibco软件,安装Tibco软件就OK了),
1.使用Tibco 的EMS客户端登录EMS(我的Tibco装在了本机上,默认的端口号是7222,端口号可以在配置文件中修改)
输入命令:c localhost:7222
输入用户名:admin
输入密码:*
如图1.1所示:
注意:如果你的EMS是首次使用,默认用户名是admin也是最高权限的用户,没有密码(密码什么都不输入直接”Enter”)
修改密码可以使用命令:set password admin 123456;(命令解释:将用户admin的密码设置为123456;修改密码也可以使用这个命令)

图1.1说明:自上往下,第一个红线是tibco EMS 的客户端名称,第二个红线是输入的链接URL的三个是用户名,第四个是密码.输入正确之后显示的旧是图1.1的内容
2.创建用户
创建用户
create user TEST TEST password=TEST2016
说明:创建用户名为TEST,用户说明为TEST,密码为TEST2016
create user BW TEST password=BW2016
说明:创建用户名为BW,用户说明为TEST,密码为BW2016
创建两个用户:TEST用户作为生产者;BW用户作为消费者
3.创建,队列以及赋权限:
创建队列
create queue TEST.OUT
说明:创建队列TEST.OUT
队列设置
setprop queue TEST.OUT secure,maxmsgs=30000,overflowPolicy=rejectIncoming;(一般队列的常见属性)
说明:设置队列TEST.OUT的属性,最大消息数量,消息超过队列深度的处理等
队列使用权
grant queue TEST.OUT TEST all
grant queue TEST.OUT BW all
说明:把队列的所有使用权限赋给TEST和BW
4.创建topic,durable和赋权限
创建topic
create topic TEST.PUB.COMMONINFO
topic权限
grant topic TEST.PUB.COMMONINFO TEST subscribe,publish,durable,use_durable
说明:把主题TEST.PUB.COMMONINFO的使用权限赋给TEST
创建Topic接收者 durable
create durable TEST.PUB.COMMONINFO TEST.SUB.BW clientid=BW-TOPICSUB-TEST
说明:创建主题的接收者durable:
durableName=TEST.SUB.BW
clientid=BW-TOPICSUB-TEST
Topic权限
grant topic TEST.PUB.COMMONINFO BW subscribe,use durable
EMS还有很多命令,你可以在客户端输入"help"自己查看
做完以上工作我们写代码需要的信息如下:
URL=tcp://localhost:7222
userName=TEST, password=TEST2016
userName=BW, password=BW2016
queueName=TEST.OUT
topicName=TEST.PUB.COMMONINFO
durableName=TEST.SUB.BW
clientid=BW-TOPICSUB-TEST
啰嗦了半天终于准备就绪了;实际开发时作为外围系统以上的东西都不需要自己做,直接找消息服务器的同事们要就行了,他们来做这些工作.看了半天是不是觉得很坑大笑大笑大笑
第二部分:jms queue的发送和接收
在这里就不啰嗦了直接上代码,重要的地方看代码注释:
在多说一句:程序需导入要以下两个jar
jms.jar:jms的标准接口由Java提供
tibjms.jar:Tibco的实现,由Tibco提供,如果你的消息服务器是其他厂商提供,你需要替换这个jar
这两个jar在博客最后会提供下载链接
JMS queue发送
package com.jms.queue;
import javax.jms.JMSException;
import javax.jms.Queue;
import javax.jms.QueueConnection;
import javax.jms.QueueConnectionFactory;
import javax.jms.QueueSender;
import javax.jms.QueueSession;
import javax.jms.Session;
import javax.jms.TextMessage;
import com.tibco.tibjms.TibjmsQueueConnectionFactory;
public class TestQueueSender {
public static void main(String[] args) {
String serviceURL = "tcp://localhost:7222";
String userName = "TEST";
String password = "TEST2016";
String queueName = "TEST.OUT";
QueueConnection connection = null;
QueueSession session = null;
QueueSender sender = null;
/*
* 创建QueueConnectionFactory;
* 我使用的是Tibco所以用TibjmsQueueConnectionFactory类,
* 其他厂商的替换就OK了
* 无论是哪个厂商的消息服务都视线了JMS的接口
*/
QueueConnectionFactory factory= new TibjmsQueueConnectionFactory(serviceURL);;
try {
//创建connection
connection = factory.createQueueConnection(userName,password);
/*
* 创建session
* connection.createQueueSession(boolean,int)
* 该方法有两个参数,第一个表示开启事务,
* 当为true时,表示开启事务,此时会忽略第二个参数
* 第二个参数为消息的确认方式有三个合法值
* Session.AUTO_ACKNOWLEDGE 1:自动确认
* Session.CLIENT_ACKNOWLEDGE 2:手动确认(自己调方法确认message.acknowledge())
* Session.DUPS_OK_ACKNOWLEDGE 3
*/
session = connection.createQueueSession(false,Session.AUTO_ACKNOWLEDGE);
//创建queue
Queue queue = session.createQueue(queueName);
//创建queue生产者
sender = session.createSender(queue);
/*
* 创建text消息
* 所有的消息都是Message的子类
* Message没有消息体
* 根据需求可以选择Message或其子类
* 本示例选择TextMessage
* Message提供了很多的set方法,但是并不都是让用户使用的,
* 有些是服务提供者使用的,我们可以调用但并不起作用,具体可以查看Message API
*/
TextMessage message = session.createTextMessage();
//添加自定义的消息属性abc=123
message.setStringProperty("abc", "123");
//添加消息体
message.setText("这是一个测试消息");
//发送消息
sender.send(message);
} catch (JMSException e) {
e.printStackTrace();
}finally{
//释放资源
if(sender != null){
try {
sender.close();
} catch (JMSException e) {
e.printStackTrace();
}
}
if(session != null){
try {
session.close();
} catch (JMSException e) {
e.printStackTrace();
}
}
if(connection !=null){
try {
connection.close();
} catch (JMSException e) {
e.printStackTrace();
}
}
}
}
}
jms Queue 接收
接收有两种方式:一种用while(true);另一种用MessageListener
下面是代码,因为代码的前半部分和queue发送时是一样的,我就不在谢注释了.
public static void rv(){
String serviceURL = "tcp://localhost:7222";
String userName = "BW";
String password = "BW2016";
String queueName = "TEST.OUT";
QueueConnection connection = null;
QueueSession session = null;
QueueReceiver rv = null;
QueueConnectionFactory factory= new TibjmsQueueConnectionFactory(serviceURL);
try {
connection = factory.createQueueConnection(userName,password);
session = connection.createQueueSession(false,Session.AUTO_ACKNOWLEDGE);
Queue queue = session.createQueue(queueName);
//创建消息消费者
rv = session.createReceiver(queue);
//*************用Listener方式处理消息*******************//
//以MessageListener的方式接收消息
rv.setMessageListener(new MessageListener(){
@Override
public void onMessage(Message message) {
/*
* 此处可以对收到的消息进行处理
* 可以先判断message的实际类型(TextMessage或其他)
* 强制转换后根据业务需求自己处理
* 需要注意的是:当onMessage()方法执行完之前消息不会被消费掉
*/
System.out.println(message);
}
});
/*
* 开始接收消息,只有执行了connection.start()方法,消息才被接收,
* 否则消息有监听,但不能接收
* 该方法一定要在rv.setMessageListener之后调用
* 如果在之前调用,可能会有消息丢失
*/
connection.start();
//*************END*************//
/*
//*************用循环的方式接收消息*************
//接收消息
connection.start();
while(true){
//当没有消息时receive()方法会阻塞线程
Message message = rv.receive();
//此处谢自己的消息处理逻辑
System.out.println(message);
}
//*************END*************
*/
} catch (JMSException e) {
e.printStackTrace();
}finally{
//释放资源
if(rv != null){
try {
rv.close();
} catch (JMSException e) {
e.printStackTrace();
}
}
if(session != null){
try {
session.close();
} catch (JMSException e) {
e.printStackTrace();
}
}
if(connection !=null){
try {
connection.close();
} catch (JMSException e) {
e.printStackTrace();
}
}
}
}
注意:一个session只能创建一个监听,就算你创建多个QueueReceiver并添加多个MessageListener也只有一个在工作;
两种接收方式不能共存,你只能选择一种;
第三部分:topic的发送和接收
topic发送
topic的发送和queue的发送一样,只需类不同,代码中我就不在写注释了
代码:
public static void topicPub(){
String serviceURL = "tcp://localhost:7222";
String userName = "TEST";
String password = "TEST2016";
String TopicName = "TEST.PUB.COMMONINFO";
TopicConnection connection = null;
TopicSession session = null;
TopicPublisher pub = null;
TopicConnectionFactory factory= new TibjmsTopicConnectionFactory(serviceURL);;
try {
connection = factory.createTopicConnection(userName,password);
session = connection.createTopicSession(false,Session.AUTO_ACKNOWLEDGE);
Topic Topic = session.createTopic(TopicName);
pub = session.createPublisher(Topic);
TextMessage message = session.createTextMessage();
message.setStringProperty("abc", "123");
message.setText("这是一个测试消息");
pub.publish(message);
} catch (JMSException e) {
e.printStackTrace();
}finally{
//释放资源
if(pub != null){
try {
pub.close();
} catch (JMSException e) {
e.printStackTrace();
}
}
if(session != null){
try {
session.close();
} catch (JMSException e) {
e.printStackTrace();
}
}
if(connection !=null){
try {
connection.close();
} catch (JMSException e) {
e.printStackTrace();
}
}
}
}
topic订阅
这里使用的是durable的方式订阅topic,和queue一样也有两种方式,我这里只写其中的一种,
package com.exe;
import javax.jms.BytesMessage;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.Session;
import javax.jms.TextMessage;
import javax.jms.Topic;
import javax.jms.TopicConnection;
import javax.jms.TopicConnectionFactory;
import javax.jms.TopicSession;
import javax.jms.TopicSubscriber;
import com.tibco.tibjms.TibjmsTopicConnectionFactory;
public class TibcoSUB {
public static void main(String[] args) {
//服务器地址,多个地址用";"分割
String url = "tcp://localhost:7222";
//注册用户名
String user = "BW";
//注册用户密码
String password = "BW2016";
//tibco和durable信息
String tibcoName = "TEST.PUB.COMMONINFO";
String clientID = "BW-TOPICSUB-TEST";
String durableName = "TEST.SUB.BW";
//以上信息由ESB项目组提供
//消息服务连接
TopicConnection connection = null;
//消息服务会话
TopicSession session = null;
//订阅
TopicSubscriber sub = null;
//消息对象
Message message = null;
try {
//建立连接工厂
TopicConnectionFactory tf = new TibjmsTopicConnectionFactory(url,clientID);
//建立连接
connection = tf.createTopicConnection(user, password);
//建立会话
session = connection.createTopicSession(false, Session.AUTO_ACKNOWLEDGE);
//获取topic对象
Topic topic = session.createTopic(tibcoName);
sub = session.createDurableSubscriber(topic,durableName);
//开始接收操作
connection.start();
while(true){
message = sub.receive();
if(message == null){
break;
}
//message有很多实现类,根据实际类型转换
if(message instanceof BytesMessage){
System.out.println(message);
}if(message instanceof TextMessage){
System.out.println(message);
}
}
} catch (JMSException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}finally {
if(sub != null){
try {
sub.close();
} catch (JMSException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
}
if(session != null){
try {
session.close();
} catch (JMSException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
}
if(connection != null){
try {
connection.close();
} catch (JMSException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
}
}
}
}
至此代码已经写完了,在下面会有jar下载地址,以后有时间可以给大家洗一洗ESB(企业服务总线)的开发,当然也是用的Tibco软件