ActiveMQ消息队列,一对一推送,一对多订阅
生产者:推送消息方,主要负责给用户推送消息。(ActiveMQ接口)
消费者:接收消息方,主要查看推送过来的消息。(用户)
ActiveMQ安装非常简单,在此我就不发了,安装完ActiveMQ后,进入网址 http://localhost:8161/admin/ ,登录管理后台,默认用户名:admin 密码:admin 到此结束,开始写代码。
写代码之前,还需要开启ActiveMQ服务,在安装文件夹里,打开bin文件夹,运行服务,如果是32位则选用32,64选64的bin。开启服务后,就可以快乐的copy代码了。
一、
①、一对一推送消息(Queue模式)生产者代码: ↓
1 public class Sender { 2 3 public static void main(String[] args) throws JMSException, InterruptedException { 4 // ConnectionFactory :连接工厂,JMS 用它创建连接 5 //61616是ActiveMQ默认端口 6 ConnectionFactory connectionFactory = new ActiveMQConnectionFactory( 7 ActiveMQConnection.DEFAULT_USER, 8 ActiveMQConnection.DEFAULT_PASSWORD, 9 "tcp://localhost:61616"); 10 11 // Connection :JMS 客户端到JMS Provider 的连接 12 Connection connection = connectionFactory.createConnection(); 13 14 connection.start(); 15 // Session: 一个发送或接收消息的线程 16 Session session = connection.createSession(true, Session.AUTO_ACKNOWLEDGE); 17 18 // Destination :消息的目的地;消息发送给谁. 19 Destination destination = session.createQueue("my-queue"); 20 21 // MessageProducer:消息发送者 22 MessageProducer producer = session.createProducer(destination); 23 24 // 设置不持久化,可以更改 25 producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT); 26 27 for(int i=0;i<10;i++){ 28 //创建文本消息 29 TextMessage message = session.createTextMessage("hello.I am producer, this is a test message"+i); 30 31 Thread.sleep(1000); 32 //发送消息 33 producer.send(message); 34 } 35 36 session.commit(); 37 session.close(); 38 connection.close(); 39 } 40 41 }
②、消费者代码(Queue模式)接收发送过来的消息: ↓
1 // ConnectionFactory :连接工厂,JMS 用它创建连接 2 private static ConnectionFactory connectionFactory = new ActiveMQConnectionFactory(ActiveMQConnection.DEFAULT_USER, 3 ActiveMQConnection.DEFAULT_PASSWORD, "tcp://localhost:61616"); 4 5 public static void main(String[] args) throws JMSException { 6 // Connection :JMS 客户端到JMS Provider 的连接 7 final Connection connection = connectionFactory.createConnection(); 8 9 connection.start(); 10 // Session: 一个发送或接收消息的线程 11 final Session session = connection.createSession(true, Session.AUTO_ACKNOWLEDGE); 12 // Destination :消息的目的地;消息送谁那获取. 13 Destination destination = session.createQueue("my-queue"); 14 // 消费者,消息接收者 15 MessageConsumer consumer1 = session.createConsumer(destination); 16 17 consumer1.setMessageListener(new MessageListener() { 18 @Override 19 public void onMessage(Message msg) { 20 21 try { 22 23 TextMessage message = (TextMessage)msg ; 24 System.out.println("consumerOne收到消息: "+message.getText()); 25 session.commit(); 26 } catch (JMSException e) { 27 e.printStackTrace(); 28 } 29 30 } 31 }); 32 }
运行之后控制台不会退出一直监听消息库,对于消息发送者的十条信息,控制输出:
consumerOne收到消息: hello.I am producer, this is a test message0
consumerOne收到消息: hello.I am producer, this is a test message1
consumerOne收到消息: hello.I am producer, this is a test message2
consumerOne收到消息: hello.I am producer, this is a test message3
consumerOne收到消息: hello.I am producer, this is a test message4
consumerOne收到消息: hello.I am producer, this is a test message5
consumerOne收到消息: hello.I am producer, this is a test message6
consumerOne收到消息: hello.I am producer, this is a test message7
consumerOne收到消息: hello.I am producer, this is a test message8
consumerOne收到消息: hello.I am producer, this is a test message9
如果此时另外一个线程也存在消费者监听该Queue,则两者交换输出。(注:Queue仅使用于 1V1 ,发送推送消息给个人)
二、
①、一对多订阅推送消息(Topic模式)生产者代码: ↓
1 package com.ym.admin.config; 2 3 import javax.jms.Connection; 4 import javax.jms.ConnectionFactory; 5 import javax.jms.DeliveryMode; 6 import javax.jms.Destination; 7 import javax.jms.JMSException; 8 import javax.jms.MapMessage; 9 import javax.jms.MessageProducer; 10 import javax.jms.Session; 11 import javax.jms.TextMessage; 12 13 import org.apache.activemq.ActiveMQConnection; 14 import org.apache.activemq.ActiveMQConnectionFactory; 15 16 //发送消息 17 public class Sender { 18 public static void main(String[] args) throws JMSException, InterruptedException { 19 // ConnectionFactory :连接工厂,JMS 用它创建连接 20 //61616是ActiveMQ默认端口 21 ConnectionFactory connectionFactory = new ActiveMQConnectionFactory( 22 "admin", 23 "admin", 24 "tcp://localhost:61616"); 25 26 // Connection :JMS 客户端到JMS Provider 的连接 27 Connection connection = connectionFactory.createConnection(); 28 connection.start(); 29 // Session: 一个发送或接收消息的线程 30 Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); //自动确认 31 32 // Destination :消息的目的地;消息发送给谁. 33 //Destination destination = session.createQueue("my-queue"); 34 Destination destination = session.createTopic("STOCKS.myTopic"); //创建topic myTopic 35 // MessageProducer:消息发送者 36 MessageProducer producer = session.createProducer(destination); 37 38 // 设置不持久化,可以更改 39 producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT); 40 41 for(int i=0;i<3;i++){ 42 //创建文本消息 43 TextMessage message = session.createTextMessage("j"+i); 44 //发送消息 45 System.out.println("发送消息成功:"+i); 46 producer.send(message); 47 } 48 49 session.close(); 50 connection.close(); 51 } 52 }
②、消费者代码(Topic模式)接收发送过来的消息: ↓
1 package com.ym.admin.config; 2 3 import javax.jms.Connection; 4 import javax.jms.ConnectionFactory; 5 import javax.jms.ConnectionMetaData; 6 import javax.jms.Destination; 7 import javax.jms.JMSException; 8 import javax.jms.MapMessage; 9 import javax.jms.Message; 10 import javax.jms.MessageConsumer; 11 import javax.jms.MessageListener; 12 import javax.jms.Session; 13 import javax.jms.TextMessage; 14 import javax.jms.Topic; 15 16 import org.apache.activemq.ActiveMQConnection; 17 import org.apache.activemq.ActiveMQConnectionFactory; 18 import org.springframework.jms.support.JmsUtils; 19 import org.springframework.util.StringUtils; 20 21 //接收订阅 22 public class Receiver { 23 private static ConnectionFactory connectionFactory = new ActiveMQConnectionFactory("admin", 24 "admin", "tcp://localhost:61616"); 25 public static void main(String[] args) { 26 27 // Connection :JMS 客户端到JMS Provider 的连接 28 try { 29 final Connection connection = connectionFactory.createConnection(); 30 connection.setClientID("anpei"); //持久订阅需要设置这个。 31 connection.start(); 32 int INDIVIDUAL_ACK_TYPE = 4; 33 // Session: 一个发送或接收消息的线程 34 final Session session = connection.createSession(true, Session.AUTO_ACKNOWLEDGE); 35 // Destination :消息的目的地;消息送谁那获取. 36 Topic topic = session.createTopic("STOCKS.myTopic");// 创建topic 37 38 // 消费者,消息接收者 39 // MessageConsumer consumer1 = session.createConsumer(destination); 普通订阅 40 MessageConsumer consumer1 = session.createDurableSubscriber(topic,"anpei");//持久化订阅 41 42 consumer1.setMessageListener(new MessageListener() { 43 44 @Override 45 public void onMessage(Message msg) { 46 47 try { 48 49 TextMessage message = (TextMessage) msg; 50 System.out.println("AAAAAAAAA收到消息: " + message.getText());54 // JmsUtils.commitIfNecessary(session); 55 session.commit(); 56 57 58 } catch (JMSException e) { 59 e.printStackTrace(); 60 } 61 62 } 63 }); 64 65 /*// 再来一个消费者,消息接收者 66 MessageConsumer consumer2 = session.createConsumer(destination); 67 68 consumer2.setMessageListener(new MessageListener() { 69 @Override 70 public void onMessage(Message msg) { 71 72 try { 73 74 TextMessage message = (TextMessage) msg; 75 System.out.println("BBBBBBBBB收到消息: " + message.getText()); 76 JmsUtils.commitIfNecessary(session); 77 // session.commit(); 78 } catch (JMSException e) { 79 e.printStackTrace(); 80 } 81 82 } 83 });*/ 84 } catch (Exception e) { 85 e.printStackTrace(); 86 } 87 } 88 89 }
上面程序运行后输出以下信息:
AAAAAAAAA收到消息: j0
AAAAAAAAA收到消息: j1
AAAAAAAAA收到消息: j2
Session session = connection.createSession(true, Session.AUTO_ACKNOWLEDGE);
// Session: 一个发送或接收消息的线程
一、事务
这一句的 true 代表是否使用事务,true:使用 false:不使用。
使用事务和不使用事务的区别:↓
如果使用事务,下面一定要session.commit();提交。 如果不使用事务,则需要把这句话删掉,因为没有事务可以提交,会报错。
如果使用事务,一切都要按照事务的规则来。如果为false,则需要使用ACK机制进行确认接收。如果不确认接收,将一直收到消息通知。
二、ACK机制
Session.AUTO_ACKNOWLEDGE ACK机制,对接收的消息进行处理
- AUTO_ACKNOWLEDGE = 1 自动确认
- CLIENT_ACKNOWLEDGE = 2 客户端手动确认
- DUPS_OK_ACKNOWLEDGE = 3 自动批量确认
- SESSION_TRANSACTED = 0 事务提交并确认
此外AcitveMQ补充了一个自定义的ACK_MODE:
- INDIVIDUAL_ACKNOWLEDGE = 4 单条消息确认
- 具体请参考 http://blog.csdn.net/lulongzhou_llz/article/details/42270113
三、持久化消息
定义:消息持久性对于可靠消息传递来说应该是一种比较好的方法,有了消息持久化,即使发送者和接受者不是同时在线(服务同时启动)或者消息中心在发送者发送消息后宕机了,在消息中心重新启动后仍然可以将消息发送出去。(意思就是说,即使消费者处于离线状态,在重新登陆后,依然可以收到消息) - 上面一对多订阅的代码,是我持久化过后的代码,通过:
connection.setClientID("zhangsan"); //持久订阅需要设置这个。
MessageConsumer consumer1 = session.createDurableSubscriber(topic,"zhangsan");//持久化订阅
如:我是张三,我是张三,请给我馒头。我是王七,我是王七,请给我馒头。对比一对一消息推送,很容易就看懂了。
上面程序接收的消息,接收一次,就不能接收了,因为 - AUTO_ACKNOWLEDGE = 1 自动确认
程序在第一次运行,就已经自动确认已经接收了消息,ActiveMQ将自动删除已经确认的消息。
如果哪个地方有问题,欢迎留言,谢谢。