• 二、activemq 之hello world


    一、概述:

    1.什么是activemq

    MQ全称为Message Queue, 消息队列(MQ)是一种应用程序对应用程序的通信方法。两个系统或两个客户端之间进行消息传送,利用高效可靠的消息传递机制进行平台无关的数据交流,并基于数据通信来进行分布式系统的集成。通过提供消息传递和消息排队模型,它可以在分布式环境下扩展进程间的通信。说人话就是 处理详细的一个服务,当我们的后台服务需要发消息的时候,会把消息发送到MQ服务器,当后台服务需要取数据的时候,就MQ中取数据;作用就是异步化提升性能、降低耦合度、流量削峰。

    举个例子 学生找老师回答问题的场景,如果有有100个学生同时找一个老师回答问题,那么老师只能一个一个的解答学生的问题。没有轮到的学生只能等着。而采用的mq的方式呢,就是 学生按照老师的要求(JMS)写好提问的内容,并把它交给班长,由班长交给老师。只要交了问题的学生就可以该干嘛就干嘛了,不用排队等着;老师拿到谁的提问,就处理谁的提问。

      

    2.应用场景举例

    1)异步通信

    ​ 注册时的短信、邮件通知,减少响应时间;

    2)应用解耦

    ​ 信息发送者和消息接受者无需耦合,比如调用第三方;

    3)流量削峰

    ​ 例如秒杀系统;

    3.消息模型:

    • 队列:Point-to-Point(P2P) --- 点对点(生产者发送一条消息到queue,只有一个消费者能收到)
    • 主题:Publish/Subscribe(Pub/Sub)---  发布订阅(发布者发送到topic的消息,只有订阅了topic的订阅者才会收到消息)

    4.安装:

    https://www.cnblogs.com/lixiuming521125/p/16499787.html

    二、JMS:

    java 实现MQ的规范:

    JMS开发步骤;

    1.创建一个JMS connectionfactory
    2.通过connection factory来创建JMS connection
    3.启动JMS connection
    4.通过connection创建JMS session
    5.创建JMS destination
    6.创建JMS producer,或者创建JMS message,并设置destination
    7.创建JMS consumer,或者是注册一个JMS message listener
    8.发送或者接受JMS message(s)
    9.关闭所有的JMS资源(connection, session, producer, consumer等) 。

    三、队列Queue

    特点:

    • 每个消息只能有一个消费者。
    • 消息的生产者和消费者之间没有时间上的相关性。无论消费者在生产者发送消息的时候是否处于运行状态,它都可以提取消息。

    队列的实现方式如图:

    消息生产者代码实现:

     1 package org.muses.ssm.utils;
     2 
     3 import javax.jms.Connection;
     4 import javax.jms.JMSException;
     5 import javax.jms.MessageProducer;
     6 import javax.jms.Queue;
     7 import javax.jms.Session;
     8 import javax.jms.TextMessage;
     9 
    10 import org.apache.activemq.ActiveMQConnectionFactory;
    11 
    12 public class TestActiveMqProducer {
    13     private static final String ACTIVEMQ_URL = "tcp://192.168.65.116:61616";
    14     private static final String QUEUE_NAME = "queue_01";
    15  
    16     public static void main(String[] args) throws JMSException {
    17         // 创建连接工厂,按照给定的URL,采用默认用户名密码
    18         ActiveMQConnectionFactory activeMQConnectionFactory = new ActiveMQConnectionFactory(ACTIVEMQ_URL);
    19         // 通过连接工厂 获取connection 并启动访问
    20         Connection conn = activeMQConnectionFactory.createConnection();
    21         conn.start();
    22         // 创建session会话
    23         Session session = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
    24         // 创建目的地 (具体是队列还是主题topic)
    25         Queue queue = session.createQueue(QUEUE_NAME);
    26 
    27         // 创建消息的生产者
    28         MessageProducer messageProducer = session.createProducer(queue);
    29 
    30         for (int i = 0; i < 3; i++) {
    31             // 创建消息;可以理解为学生按照要求写好问题
    32             TextMessage textMessage = session.createTextMessage("mession-------" + i);
    33             // 通过messageProducer 发送给mq
    34             messageProducer.send(textMessage);
    35         }
    36         messageProducer.close();
    37         session.close();
    38         conn.close();
    39         System.out.println("发送消息成功");
    40     }
    41 
    42 }
    View Code

    当发送者发送代码后,mq队列列表显示3条待处理的消息

    消费者代码实现方法一:同步阻塞方式(receive())

    订阅者或者接受者调用MessageConsumer的receive()方法来接受消息,receive方法在能够接收到消息之前(或超时之前)将一直阻塞;receive()可设置超时时间;

     1 package org.muses.ssm.utils;
     2 
     3 import java.io.IOException;
     4 
     5 import javax.jms.Connection;
     6 import javax.jms.JMSException;
     7 import javax.jms.MessageConsumer;
     8 import javax.jms.Queue;
     9 import javax.jms.Session;
    10 import javax.jms.TextMessage;
    11 
    12 import org.apache.activemq.ActiveMQConnectionFactory;
    13 
    14 public class TestActiveMqConsumer {
    15     private static final String ACTIVEMQ_URL = "tcp://192.168.65.116:61616";
    16     private static final String QUEUE_NAME = "queue_01";
    17 
    18     public static void main(String[] args) throws JMSException, IOException {
    19         // 创建连接工厂,按照给定的URL,采用默认用户名密码
    20         ActiveMQConnectionFactory activeMQConnectionFactory = new ActiveMQConnectionFactory(ACTIVEMQ_URL);
    21         // 通过连接工厂 获取connection 并启动访问
    22         Connection conn = activeMQConnectionFactory.createConnection();
    23         conn.start();
    24         // 创建session会话
    25         Session session = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
    26         // 创建目的地 (具体是队列还是主题topic)
    27         Queue queue = session.createQueue(QUEUE_NAME);
    28 
    29         // 创建消息的生产者
    30         MessageConsumer messageConsumer = session.createConsumer(queue);
    31         /**
    32          * 同步阻塞方式(receive()) 订阅者或者接受者调用MessageConsumer的receive()方法来接受消息,receive方法在能够接收到消息之前(或超时之前)将一直阻塞;
    33          */
    34         while (true) {
    35             TextMessage textMessage = (TextMessage) messageConsumer.receive();
    36             if (textMessage != null) {
    37                 System.out.println("收到消息:" + textMessage.getText());
    38             } else {
    39                 break;
    40             }
    41         }
    42 
    43         messageConsumer.close();
    44         session.close();
    45         conn.close();
    46 
    47     }
    48 
    49 }
    View Code

    当发布者发布了消息,然后启动消费者代码,则MQ管理后台显示:此时,观察控制台,发现消费者程序一直处于运行状态。原因是recevice()没有设置超时时间,所以消费者会一直开着。如果receive()方法设置了超时时间,则 消费者程序会在等待超时时间后,关闭消费者程序;

    消费者和生产者的队列名称一定要一致

    控制台打印:

    收到消息:mession-------0
    收到消息:mession-------1
    收到消息:mession-------2

    消费者代码实现方法二:消费者监听模式(异步非阻塞方式(监听器onMessage))

    订阅或者接收者通过MessageConsumer的setMessageListener(MessageListener messageListener),注册一个消息监听器, 当消息到达以后,系统自动调用监听器的MessageListener的 onMessage(Message message)方法;程序运行完成后,观察控制台发现,消费者程也是一直没有关闭,一直在监听;

    消费者和生产者的队列名称一定要一致

     1 package org.muses.ssm.utils;
     2 
     3 import java.io.IOException;
     4 
     5 import javax.jms.Connection;
     6 import javax.jms.JMSException;
     7 import javax.jms.Message;
     8 import javax.jms.MessageConsumer;
     9 import javax.jms.MessageListener;
    10 import javax.jms.Queue;
    11 import javax.jms.Session;
    12 import javax.jms.TextMessage;
    13 
    14 import org.apache.activemq.ActiveMQConnectionFactory;
    15 
    16 public class TestActiveMqConsumer {
    17     private static final String ACTIVEMQ_URL = "tcp://192.168.65.116:61616";
    18     private static final String QUEUE_NAME = "queue_01";
    19 
    20     public static void main(String[] args) throws JMSException, IOException {
    21         // 创建连接工厂,按照给定的URL,采用默认用户名密码
    22         ActiveMQConnectionFactory activeMQConnectionFactory = new ActiveMQConnectionFactory(ACTIVEMQ_URL);
    23         // 通过连接工厂 获取connection 并启动访问
    24         Connection conn = activeMQConnectionFactory.createConnection();
    25         conn.start();
    26         // 创建session会话
    27         Session session = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
    28         // 创建目的地 (具体是队列还是主题topic)
    29         Queue queue = session.createQueue(QUEUE_NAME);
    30 
    31         // 创建消息的生产者
    32         MessageConsumer messageConsumer = session.createConsumer(queue);
    33         /**
    34          * 消费者监听模式; 异步非阻塞方式(监听器onMessage) 订阅或者接收者通过MessageConsumer的setMessageListener(MessageListener messageListener)
    35          * 注册一个消息监听器, 当消息到达以后,系统自动调用监听器的MessageListener的 onMessage(Message message)方法
    36          */
    37         messageConsumer.setMessageListener(new MessageListener() {
    38 
    39             @Override
    40             public void onMessage(Message message) {
    41                 if (message != null && message instanceof TextMessage) {
    42                     TextMessage textMessage = (TextMessage) message;
    43                     try {
    44                         System.out.println("收到消息:" + textMessage.getText());
    45                     } catch (JMSException e) {
    46                         // TODO Auto-generated catch block
    47                         e.printStackTrace();
    48                     }
    49                 }
    50             }
    51 
    52         });
    53         // 消费者监听模式 必须要有 System.in.read() ;否则无法消费
    54         System.in.read();
    55 
    56         messageConsumer.close();
    57         session.close();
    58         conn.close();
    59 
    60     }
    61 
    62 }
    View Code

    控制台打印:

    收到消息:mession-------0
    收到消息:mession-------1
    收到消息:mession-------2

    关于有多个消费者的情况说明(本例为两个)

    情况一:先生产3条消息 ,先启动消费者1 再启动消费者2号: 2号没有消费到一条消息,1号消费者消费所有消息 

    实现方式:

      生产3条消息,利用消息生产者代码即可实现;

      启动消费者1号:消费者代码实现方式二 启动 即可实现1号消费者,可以用 System.out.println("****我是1号消费者******")来表示;

      启动消费者2号:再次费者代码实现方式二 启动 即可实现2号消费者,可以用 System.out.println("****我是2号消费者******")来表示;

     

    情况二:先启动2个消费者,再生产消息;那么就会出现 1号消费者和2号消费者平分消息的情况,例如 1号消费者先启动,2号消费者后启动,再生产3条消息:那么就是 1号消费者消费了2条消息,2号消费者消费了1条消息;如果生产了4条消息,那么1号和2号消费者各消费了2条消息;

      实现方式:

      启动消费者1号:消费者代码实现方式二 启动 即可实现1号消费者,可以用 System.out.println("****我是1号消费者******")来表示;

      启动消费者2号:再次费者代码实现方式二 启动 即可实现2号消费者,可以用 System.out.println("****我是2号消费者******")来表示;

      生产3条消息,利用消息生产者代码即可实现;

    队列表头说明:

    1.   Name:消息队列的名称。
    2.   Number Of Pending Messages:未被消费的消息数目。
    3.   Number Of Consumers:消费者的数量。
    4.   Messages Enqueued:进入队列的消息 ;进入队列的总消息数目,包括已经被消费的和未被消费的。 这个数量只增不减。
    5.   Messages Dequeued:出了队列的消息,可以理解为是被消费掉的消息数量。在Queues里它和进入队列的总数量相等(因为一个消息只会被成功消费一次),如果暂时不等是因为消费者还没来得及消费。

    四、订阅Topic

    特点:

    • 每个消息可以有多个消费者。
    • 生产者和消费者之间有时间上的相关性
    • 订阅一个主题的消费者只能消费自它订阅之后发布的消息。JMS规范允许客户创建持久订阅,这在一定程度上放松了时间上的相关性要求 。持久订阅允许消费者消费它在未处于激活状态时发送的消息。
    • 在点对点消息传递域中,目的地被成为队列(queue);在发布/订阅消息传递域中,目的地被成为主题(topic)。

    需要先有消费者,再有消息生产者。

    运行流程:

     消费者代码实现:

     1 package org.muses.ssm.utils;
     2 
     3 import java.io.IOException;
     4 
     5 import javax.jms.Connection;
     6 import javax.jms.JMSException;
     7 import javax.jms.Message;
     8 import javax.jms.MessageConsumer;
     9 import javax.jms.MessageListener;
    10 import javax.jms.Session;
    11 import javax.jms.TextMessage;
    12 import javax.jms.Topic;
    13 
    14 import org.apache.activemq.ActiveMQConnectionFactory;
    15 
    16 public class TestActiveMqConsumer {
    17     private static final String ACTIVEMQ_URL = "tcp://192.168.65.116:61616";
    18     private static final String TOPIC_NAME = "TOPIC_NAME_1";
    19 
    20     public static void main(String[] args) throws JMSException, IOException {
    21         // 创建连接工厂,按照给定的URL,采用默认用户名密码
    22         ActiveMQConnectionFactory activeMQConnectionFactory = new ActiveMQConnectionFactory(ACTIVEMQ_URL);
    23         // 通过连接工厂 获取connection 并启动访问
    24         Connection conn = activeMQConnectionFactory.createConnection();
    25         conn.start();
    26         // 创建session会话
    27         Session session = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
    28         // 创建目的地 (具体是队列还是主题topic)
    29         Topic topic = session.createTopic(TOPIC_NAME);
    30 
    31         // 创建消息的生产者
    32         MessageConsumer messageConsumer = session.createConsumer(topic);
    33 
    34         System.out.println("****我是1号消费者******");
    35         messageConsumer.setMessageListener(new MessageListener() {
    36 
    37             @Override
    38             public void onMessage(Message message) {
    39                 if (message != null && message instanceof TextMessage) {
    40                     TextMessage textMessage = (TextMessage) message;
    41                     try {
    42                         System.out.println("收到消息:" + textMessage.getText());
    43                     } catch (JMSException e) {
    44                         // TODO Auto-generated catch block
    45                         e.printStackTrace();
    46                     }
    47                 }
    48             }
    49 
    50         });
    51         System.in.read();
    52 
    53         messageConsumer.close();
    54         session.close();
    55         conn.close();
    56 
    57     }
    58 
    59 }
    View Code

    启动3个消费者:(分别启动3此消费者代码 System.out.println("****我是1/2/3号消费者******")来表示),MQ后台显示如下:

    生产者代码实现:

     1 package org.muses.ssm.utils;
     2 
     3 import javax.jms.Connection;
     4 import javax.jms.JMSException;
     5 import javax.jms.MessageProducer;
     6 import javax.jms.Session;
     7 import javax.jms.TextMessage;
     8 import javax.jms.Topic;
     9 
    10 import org.apache.activemq.ActiveMQConnectionFactory;
    11 
    12 public class TestActiveMqTopicProducer {
    13     private static final String ACTIVEMQ_URL = "tcp://192.168.65.116:61616";
    14     private static final String TOPIC_NAME = "TOPIC_NAME_1";
    15 
    16     public static void main(String[] args) throws JMSException {
    17         // 创建连接工厂,按照给定的URL,采用默认用户名密码
    18         ActiveMQConnectionFactory activeMQConnectionFactory = new ActiveMQConnectionFactory(ACTIVEMQ_URL);
    19         // 通过连接工厂 获取connection 并启动访问
    20         Connection conn = activeMQConnectionFactory.createConnection();
    21         conn.start();
    22         // 创建session会话
    23         Session session = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
    24         // 创建目的地 (具体是队列还是主题topic)
    25         Topic topic = session.createTopic(TOPIC_NAME);
    26 
    27         // 创建消息的生产者
    28         MessageProducer messageProducer = session.createProducer(topic);
    29 
    30         for (int i = 0; i < 3; i++) {
    31             // 创建消息;可以理解为学生按照要求写好问题
    32             TextMessage textMessage = session.createTextMessage("mession-------" + i);
    33             // 通过messageProducer 发送给mq
    34             messageProducer.send(textMessage);
    35         }
    36         messageProducer.close();
    37         session.close();
    38         conn.close();
    39         System.out.println("发送消息成功");
    40     }
    41 
    42 }
    View Code

    启动消息生产者代码:此时,1号消费者接受到3条消息;2号消费者也接收到3条消息,3号消费者也接收到3条消息;

    控制台显示

    ****我是1号消费者******      ****我是2号消费者******      ****我是3号消费者******      
    收到消息:mession-------0    收到消息:mession-------0      收到消息:mession-------0
    收到消息:mession-------1    收到消息:mession-------1      收到消息:mession-------1
    收到消息:mession-------2    收到消息:mession-------2      收到消息:mession-------2

    MQ管理后台显示:

    Topic &Queue对比

      Topic queue
    概要 Publish  Subscribe messaging 发布订阅消息 Point-to-Point  点对点
    有无状态 topic数据默认不落地,是无状态的。

    Queue数据默认会在mq服务器上以文件形式保存,比如Active MQ一般保存在$AMQ_HOME\data\kr-store\data下面。也可以配置成DB存储。

    完整性保障 并不保证publisher发布的每条数据,Subscriber都能接受到。 Queue保证每条数据都能被receiver接收。
    消息是否会丢失 一般来说publisher发布消息到某一个topic时,只有正在监听该topic地址的sub能够接收到消息;如果没有sub在监听,该topic就丢失了。 Sender发送消息到目标Queue,receiver可以异步接收这个Queue上的消息。Queue上的消息如果暂时没有receiver来取,也不会丢失。
    消息发布接收策略 一对多的消息发布接收策略,监听同一个topic地址的多个sub都能收到publisher发送的消息。Sub接收完通知mq服务器 一对一的消息发布接收策略,一个sender发送的消息,只能有一个receiver接收。receiver接收完后,通知mq服务器已接收,mq服务器对queue里的消息采取删除或其他操作。

    需要的jar包:

    版本需要和 activemq 服务的版本对应,例如,服务端装了5.16.5,那么Java程序端需要用5.16.5的jar包

     1        <!-- activemq 需要的依赖 -->
     2         <dependency>
     3             <groupId>org.apache.activemq</groupId>
     4             <artifactId>activemq-all</artifactId>
     5             <version>5.16.5</version>
     6         </dependency>
     7         <dependency>
     8             <groupId>org.apache.xbean</groupId>
     9             <artifactId>xbean-spring</artifactId>
    10             <version>4.21</version>
    11         </dependency>                

    官方文档地址:

    https://activemq.apache.org/features 

  • 相关阅读:
    OpenVAS安装过程
    网络攻防环境搭建
    kali linux 安装过程
    20159217《网络攻防实践》第三周学习总结
    网络攻防实践第二周学习总结
    移动平台课程总结
    Android实践项目汇报
    性能测试四十六:Linux 从网卡模拟延时和丢包的实现
    性能测试四十五:性能测试策略
    性能测试四十四:性能优化思路
  • 原文地址:https://www.cnblogs.com/lixiuming521125/p/16538452.html
Copyright © 2020-2023  润新知