PTP(点对点的消息模型)
在点对点模型中,相当于两个人打电话,两个人独享一条通信线路。一方发送消息,一方接收消息。
在p2p的模型中,双方通过队列交流,一个队列只有一个生产者和一个消费者。
1、建立项目
建立一个java项目,导入jar包,将apache-activemq-5.11.1-bin.zip解压缩后里面的activemq-all-5.11.1.jar包加入到classpath下面,这个包包含了所有JMS接口API的实现。
点对点的消息模型,只需要一个消息生成者和消息消费者。
- 编写生产者
package com.tgb.activemq; import javax.jms.Connection; import javax.jms.ConnectionFactory; import javax.jms.Destination; import javax.jms.JMSException; import javax.jms.MessageProducer; import javax.jms.Session; import javax.jms.TextMessage; import org.apache.activemq.ActiveMQConnection; import org.apache.activemq.ActiveMQConnectionFactory; /** * 消息的生产者(发送者) * @author liang * */ public class JMSProducer { //默认连接用户名 private static final String USERNAME = ActiveMQConnection.DEFAULT_USER; //默认连接密码 private static final String PASSWORD = ActiveMQConnection.DEFAULT_PASSWORD; //默认连接地址 private static final String BROKEURL = ActiveMQConnection.DEFAULT_BROKER_URL; //发送的消息数量 private static final int SENDNUM = 10; public static void main(String[] args) { //连接工厂 ConnectionFactory connectionFactory; //连接 Connection connection = null; //会话 接受或者发送消息的线程 Session session; //消息的目的地 Destination destination; //消息生产者 MessageProducer messageProducer; //实例化连接工厂 connectionFactory = new ActiveMQConnectionFactory(JMSProducer.USERNAME, JMSProducer.PASSWORD, JMSProducer.BROKEURL); try { //通过连接工厂获取连接 connection = connectionFactory.createConnection(); //启动连接 connection.start(); //创建session session = connection.createSession(true, Session.AUTO_ACKNOWLEDGE); //创建一个名称为HelloWorld的消息队列 destination = session.createQueue("HelloWorld"); //创建消息生产者 messageProducer = session.createProducer(destination); //发送消息 sendMessage(session, messageProducer); session.commit(); } catch (Exception e) { e.printStackTrace(); }finally{ if(connection != null){ try { connection.close(); } catch (JMSException e) { e.printStackTrace(); } } } } /** * 发送消息 * @param session * @param messageProducer 消息生产者 * @throws Exception */ public static void sendMessage(Session session,MessageProducer messageProducer) throws Exception{ for (int i = 0; i < JMSProducer.SENDNUM; i++) { //创建一条文本消息 TextMessage message = session.createTextMessage("ActiveMQ 发送消息" +i); System.out.println("发送消息:Activemq 发送消息" + i); //通过消息生产者发出消息 messageProducer.send(message); } } }
- 编写消费者
package com.tgb.activemq; import javax.jms.Connection; import javax.jms.ConnectionFactory; import javax.jms.Destination; import javax.jms.JMSException; import javax.jms.MessageConsumer; import javax.jms.Session; import javax.jms.TextMessage; import org.apache.activemq.ActiveMQConnection; import org.apache.activemq.ActiveMQConnectionFactory; /** * 消息的消费者(接受者) * @author liang * */ public class JMSConsumer { private static final String USERNAME = ActiveMQConnection.DEFAULT_USER;//默认连接用户名 private static final String PASSWORD = ActiveMQConnection.DEFAULT_PASSWORD;//默认连接密码 private static final String BROKEURL = ActiveMQConnection.DEFAULT_BROKER_URL;//默认连接地址 public static void main(String[] args) { ConnectionFactory connectionFactory;//连接工厂 Connection connection = null;//连接 Session session;//会话 接受或者发送消息的线程 Destination destination;//消息的目的地 MessageConsumer messageConsumer;//消息的消费者 //实例化连接工厂 connectionFactory = new ActiveMQConnectionFactory(JMSConsumer.USERNAME, JMSConsumer.PASSWORD, JMSConsumer.BROKEURL); try { //通过连接工厂获取连接 connection = connectionFactory.createConnection(); //启动连接 connection.start(); //创建session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); //创建一个连接HelloWorld的消息队列 destination = session.createQueue("HelloWorld"); //创建消息消费者 messageConsumer = session.createConsumer(destination); while (true) { TextMessage textMessage = (TextMessage) messageConsumer.receive(100000); if(textMessage != null){ System.out.println("收到的消息:" + textMessage.getText()); }else { break; } } } catch (JMSException e) { e.printStackTrace(); } } }
2、测试
1)首先,启动ActiveMQ,在浏览器中输入:http://localhost:8161/admin/,然后开始执行程序。
2)运行发送者JMSProducer,Eclipse控制台输出,如下图:
生产者生产10条消息。
此时,查看ActiveMQ服务器,Queues内容如下:
可以看到创建了一个名称为HelloWorld的消息队列,队列中有10条消息未被消费,我们也可以通过Browse查看是哪些消息,如下图:
如果这些队列中的消息,被删除,消费者则无法消费。
3)继续运行消费者JMSConsumer,eclipse控制台打印消息,如下:
再查看ActiveMQ服务器,Queues内容如下:
可以看到HelloWorld的消息队列发生变化,多一个消息者,队列中的10条消息被消费了,点击Browse查看,已经为空了。
点击Active Consumers,我们可以看到这个消费者的详细信息:
3、总结
点对点消息的传播,生产者向特定的消息队列传播消息,一个消费者从该队列读取消息。生产者不需要在接收者接收消息时处于运行,消费者也不需要生产者在发送消息时处于运行状态,队列相当于一个中间的仓库,生产者发送消息,立即返回状态发送成功。等消费者上线时 ,才接受消息。
Pub/Sub(发布订阅模型)
就像订阅报纸。我们可以选择一份或者多份报纸,比如:北京日报、人民日报。这些报纸就相当于发布订阅模型中的topic。如果有很多人订阅了相同的报纸,那我们就在同一个topic中注册,对于报纸发行方,它就和所有的订阅者形成了一对多的关系。如下:
1、建立项目
建立一个java项目,导入jar包。
- 编写发布者(这里和点对点的不同就是不再是创建消息队列,而是创建topic。而且也不是消息生产者而是发布者)
package com.tgb.activemqTopic; import java.awt.font.TextMeasurer; import javax.jms.Connection; import javax.jms.ConnectionFactory; import javax.jms.Destination; import javax.jms.JMSException; import javax.jms.MessageProducer; import javax.jms.Session; import javax.jms.TextMessage; import org.apache.activemq.ActiveMQConnection; import org.apache.activemq.ActiveMQConnectionFactory; /** * 消息发布者 * @author xx * */ public class JMSProducer { //默认连接用户名 private static final String USERNAME = ActiveMQConnection.DEFAULT_USER; //默认连接密码 private static final String PASSWORD = ActiveMQConnection.DEFAULT_PASSWORD; //默认的连接地址 private static final String BROKEURL = ActiveMQConnection.DEFAULT_BROKER_URL; //发送的消息数量 private static final int SENNUM = 10; public static void main(String[] args){ ConnectionFactory factory ; //连接工厂 Connection connection = null ; //连接 Session session ; //会话,接收或者发送消息的线程 Destination destination; //消息的目的地 MessageProducer messageProducer; //消息生产者 //实例化连接工厂 factory = new ActiveMQConnectionFactory(JMSProducer.USERNAME, JMSProducer.PASSWORD, JMSProducer.BROKEURL); //通过连接工厂获取connection try { connection = factory.createConnection(); connection.start(); //启动连接 //创建session session = connection.createSession(Boolean.TRUE, Session.AUTO_ACKNOWLEDGE); //创建消息队列 // destination = session.createQueue("FirstQueue"); //创建主题 destination = session.createTopic("topic1"); //创建消息发布者 messageProducer = session.createProducer(destination); //发送消息 sendMessage(session, messageProducer); session.commit(); } catch (JMSException e) { e.printStackTrace(); }finally{ if (connection != null) { try { connection.close(); } catch (JMSException e) { e.printStackTrace(); } } } } /** * 发送消息 * @param session * @param mp * @throws JMSException */ public static void sendMessage(Session session, MessageProducer mp) throws JMSException{ for(int i = 0;i<JMSProducer.SENNUM;i++){ TextMessage message = session.createTextMessage("ActiveMq 发布的消息" + i); System.out.println("发布消息:" + "ActiveMq 发布的消息" + i); mp.send(message); } } }
- 编写订阅者1
package com.tgb.activemqTopic; import javax.jms.Connection; import javax.jms.ConnectionFactory; import javax.jms.Destination; import javax.jms.JMSException; import javax.jms.Message; import javax.jms.MessageConsumer; import javax.jms.MessageListener; import javax.jms.Session; import javax.jms.TextMessage; import org.apache.activemq.ActiveMQConnectionFactory; public class JMSConsumer1 implements MessageListener { public void onMessage(Message message) { if (message instanceof TextMessage) { TextMessage txtMsg = (TextMessage) message; try { System.out.println("订阅者一接收到了消息:" + txtMsg.getText()); } catch (JMSException e) { e.printStackTrace(); } } } public void receive() { // 消费者的主要流程 Connection connection = null; try { // 1.初始化connection工厂 ConnectionFactory connectionFactory = new ActiveMQConnectionFactory(); // 2.创建Connection connection = connectionFactory.createConnection(); // 3.打开连接 connection.start(); // 4.创建session Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); // 5.创建消息目标 Destination destination = session.createTopic("topic1"); // 6.创建消费者 MessageConsumer consumer = session.createConsumer(destination); // 7.配置监听 consumer.setMessageListener(new JMSConsumer1()); } catch (JMSException e) { e.printStackTrace(); } } public static void main(String[] args) { new JMSConsumer1().receive(); } }
- 编写订阅者2
package com.tgb.activemqTopic; import javax.jms.Connection; import javax.jms.ConnectionFactory; import javax.jms.Destination; import javax.jms.JMSException; import javax.jms.Message; import javax.jms.MessageConsumer; import javax.jms.MessageListener; import javax.jms.Session; import javax.jms.TextMessage; import org.apache.activemq.ActiveMQConnectionFactory; public class JMSConsumer2 implements MessageListener { public void onMessage(Message message) { if (message instanceof TextMessage) { TextMessage txtMsg = (TextMessage) message; try { System.out.println("订阅者二接收到了消息:" + txtMsg.getText()); } catch (JMSException e) { e.printStackTrace(); } } } public void receive() { // 消费者的主要流程 Connection connection = null; try { // 1.初始化connection工厂 ConnectionFactory connectionFactory = new ActiveMQConnectionFactory(); // 2.创建Connection connection = connectionFactory.createConnection(); // 3.打开连接 connection.start(); // 4.创建session Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); // 5.创建消息目标 Destination destination = session.createTopic("topic1"); // 6.创建消费者 MessageConsumer consumer = session.createConsumer(destination); // 7.配置监听 consumer.setMessageListener(new JMSConsumer1()); } catch (JMSException e) { e.printStackTrace(); } } public static void main(String[] args) { new JMSConsumer2().receive(); } }
2、测试
1)首先,启动ActiveMQ,在浏览器中输入:http://localhost:8161/admin/,然后开始执行程序。
2)发布订阅模型,要先启动订阅者,订阅者先订阅topic,再发布消息。
启动订阅者,这里我启动两个,可以看到在topic中注册了两个消费者:
3)启动发布者,如下:
发布者发布了10条数据,但是出队的有20条,因为有两个订阅者。
3、总结
发布者向一个特定的消息主题发布消息,0或者多个订阅者可能接收到来自特定消息主题的消息感兴趣。其中发布者和订阅者不知道对方的存在。
配置消息是否持久化
1、建立项目
//配置消息是否持久化,DeliverMode有2种方式
/*
* 1 不持久化:服务器重启之后,消息销毁
* 2 持久化:服务器重启之后,该消息仍存在
*/
messageProducer.setDeliveryMode(2);
- 编写发布者
package com.tgb.activemqTopic; import javax.jms.Connection; import javax.jms.ConnectionFactory; import javax.jms.Destination; import javax.jms.JMSException; import javax.jms.MessageProducer; import javax.jms.Session; import javax.jms.TextMessage; import org.apache.activemq.ActiveMQConnection; import org.apache.activemq.ActiveMQConnectionFactory; /** * 消息发布者 * @author xx * */ public class JMSProducer { //默认连接用户名 private static final String USERNAME = ActiveMQConnection.DEFAULT_USER; //默认连接密码 private static final String PASSWORD = ActiveMQConnection.DEFAULT_PASSWORD; //默认的连接地址 private static final String BROKEURL = ActiveMQConnection.DEFAULT_BROKER_URL; //发送的消息数量 private static final int SENNUM = 10; public static void main(String[] args){ ConnectionFactory factory ; //连接工厂 Connection connection = null ; //连接 Session session ; //会话,接收或者发送消息的线程 Destination destination; //消息的目的地 MessageProducer messageProducer; //消息生产者 //实例化连接工厂 factory = new ActiveMQConnectionFactory(JMSProducer.USERNAME, JMSProducer.PASSWORD, JMSProducer.BROKEURL); //通过连接工厂获取connection try { connection = factory.createConnection(); connection.start(); //启动连接 //创建session session = connection.createSession(true, Session.AUTO_ACKNOWLEDGE); //创建主题 destination = session.createTopic("topic1"); //创建消息发布者 messageProducer = session.createProducer(destination); //配置消息是否持久化,DeliverMode有2种方式 /* * 1 不持久化:服务器重启之后,消息销毁 * 2 持久化:服务器重启之后,该消息仍存在 */ messageProducer.setDeliveryMode(2); //发送消息 sendMessage(session, messageProducer); session.commit(); } catch (JMSException e) { e.printStackTrace(); }finally{ if (connection != null) { try { connection.close(); } catch (JMSException e) { e.printStackTrace(); } } } } /** * 发送消息 * @param session * @param mp * @throws JMSException */ public static void sendMessage(Session session, MessageProducer mp) throws JMSException{ for(int i = 0;i<JMSProducer.SENNUM;i++){ TextMessage message = session.createTextMessage("ActiveMq 发布的消息" + i); System.out.println("发布消息:" + "ActiveMq 发布的消息" + i); mp.send(message); } } }
2、测试
1)首先,启动ActiveMQ,在浏览器中输入:http://localhost:8161/admin/,然后开始执行程序。
2)先2个启动订阅者,再启动发布者,如下: