消息队列知识点整理(ActiveMQ)

《原文链接:https://blog.csdn.net/hjl021/article/details/79245701》

一.背景介绍

1.1 java消息服务:

 不同系统之间的信息交换,是我们开发中比较常见的场景,比如系统A要把数据发送给系统B,这个问题我们应该如何去处理? 1999年,原来的SUN公司领衔提出了一种面向消息的中间件服务--JMS规范(标准);常用的几种信息交互技术(httpClient、hessian、dubbo、jms、webservice 五种).

1.2JMS概述:

 JMS即Java消息服务(Java Message Service的简称),是Java EE 的标准/规范之一。这种规范(标准)指出:消息的发送应该是异步的、非阻塞的。也就是说消息的发送者发送完消息后就直接返回了,不需要等待接收者返回后才能返回,发送者和接收者可以说是互不影响。所以这种规范(标准)能够减轻或消除系统瓶颈,实现系统之间去除耦合,提高系统的整体可伸缩性和灵活性。JMS只是Java EE中定义的一组标准API,它自身并不是一个消息服务系统,它是消息传送服务的一个抽象,也就是说它定义了消息传送的接口而并没有具体实现。

1.3ActiveMQ概述:

 我们知道JMS只是消息服务的一组规范和接口,并没有具体的实现,而ActiveMQ就是JMS规范的具体实现;它是Apache下的一个项目,采用Java语言开发;是一款非常流行的开源消息服务器.

1.4 ActiveMQ与JMS关系:

 我们知道,JMS只是定义了一组有关消息传送的规范和标准,并没有真正实现,也就说JMS只是定义了一组接口而已;就像JDBC抽象了关系数据库访问、JPA抽象了对象与关系数据库映射、JNDI抽象了命名目录服务访问一样,JMS具体的实现由不同的消息中间件厂商提供,比如Apache ActiveMQ就是JMS规范的具体实现,Apache ActiveMQ才是一个消息服务系统,而JMS不是。

                       

二.ActiveMQ的使用

2.1 ActiveMQ环境搭建:

  •  ActiveMQ运行需要Java的支持,首先需要配置Java环境变量;
  • 切换到解压后的activemq的bin目录下 cd /usr/local/apache-activemq-5.15.2 去启动
  • 切换到bin目录下,启动:./activemq start ;关闭:./activemq stop
  • 启动后有两个端口号,一个是web控制台:8161,一个是消息服务broker连接端口:61616
  • web管理控制台admin URL地址:http://localhost:8161  默认登录账号 admin  密码 admin,注意:Linux防火前要关闭 ;通过这个地址可以即时访问交互信息.如下图:

  • 消息服务broker URL地址 : tcp://localhost:61616
2.2 Java消息队列JMS整体设计结构

2.2.1 基本要素:1、生产者producer ; 2、消费者consumer ; 3、消息服务broker

2.2.1 交互模型:

2.2.3 JMS两种消息传送模式

  • 点对点( Point-to-Point):专门用于使用队列Queue传送消息;基于队列Queue的点对点消息只能被一个消费者消费,如多个消费者都注册到同一个消息队列上,当生产者发送一条消息后,而只有其中一个消费者会接收到该消息,而不是所有消费者都能接收到该消息。
  •  发布/订阅(Publish/Subscribe):专门用于使用主题Topic传送消息。基于主题的发布与订阅消息能被多个消费者消费,生产者发送的消息,所有订阅了该topic的消费者都能接收到。

2.3 Java消息队列JMS API总体概览:

 2.3.1JMS API 概览

  •  JMS API可以分为3个主要部分:
    1、公共API:可用于向一个队列或主题发送消息或从其中接收消息;
    2、点对点API:专门用于使用队列Queue传送消息;
    3、发布/订阅API:专门用于使用主题Topic传送消息。
  •  JMS公共API:
   在JMS公共API内部,和发送与接收消息有关的JMS API接口主要是:ConnectionFactory/Connection/Session/Message/Destination/MessageProducer/MessageConsumer . 它们的关系是:一旦有了ConnectionFactory,就可以创建Connection,一旦有了Connection,就可以创建Session,而一旦有了Session,就可以创建Message、MessageProducer和MessageConsumer。

  • JMS点对点API:

点对点(p2p)消息传送模型API是指JMS API之内基于队列(Queue)的接口:QueueConnectionFactory/QueueConnection/QueueSession/Message/Queue/QueueSender/QueueReceiver. 从接口的命名可以看出,大多数接口名称仅仅是在公共API接口

名称之前添加Queue一词。一般来说,使用点对点消息传送模型的应用程序将使用基于队列的API,而不使用公共API 。

  •  JMS发布/订阅API:

  发布/订阅消息传送模型API是指JMS API之内基于主题(Topic)的接口:TopicConnectionFactory/TopicConnection/

TopicSession/Message/Topic/TopicPublisher/TopicSubscriber. 由于基于主题(Topic)的JMS API类似于基于队列(Queue)

的API,因此在大多数情况下,Queue这个词会由Topic取代。


2.4 ActiveMQ点对点发送与接收消息示例


 2.4.1 简单示例:

 写一个采用Queue队列方式点对点发送接收文本信息的Demo,先写发送者,如下:


  
  
  1. package com.kinglong.activemq.queue;
  2. import org.apache.activemq.ActiveMQConnectionFactory;
  3. import javax.jms.*;
  4. /**
  5. * 消息发送者
  6. *
  7. */
  8. public class Sender {
  9. /**消息服务器的连接地址**/
  10. public static final String BROKER_URL = "tcp://192.168.174.129:61616";
  11. public static void main(String[] args) {
  12. Sender sender = new Sender();
  13. sender.sendMessage( "Hello ActiveMQ.");
  14. }
  15. /**
  16. * 发送消息
  17. *
  18. * @param msg
  19. */
  20. public void sendMessage (String msg) {
  21. Connection connection = null;
  22. Session session = null;
  23. MessageProducer messageProducer = null;
  24. try {
  25. //1.创建一个连接工厂
  26. ConnectionFactory connectionFactory = new ActiveMQConnectionFactory(BROKER_URL);
  27. //2.创建一个连接
  28. connection = connectionFactory.createConnection();
  29. //3.创建一个Session
  30. session = connection.createSession(Boolean.FALSE, Session.AUTO_ACKNOWLEDGE);
  31. //4.创建消息,此处创建了一个文本消息
  32. Message message = session.createTextMessage(msg);
  33. //5.创建一个目的地
  34. Destination destination = session.createQueue( "myQueue");
  35. //6.创建一个消息的生产者(发送者)
  36. messageProducer = session.createProducer(destination);
  37. //7.发送消息
  38. messageProducer.send(message);
  39. } catch (JMSException e) {
  40. e.printStackTrace();
  41. } finally {
  42. try {
  43. //关闭连接释放资源
  44. if ( null != messageProducer) {
  45. messageProducer.close();
  46. }
  47. if ( null != session) {
  48. session.close();
  49. }
  50. if ( null != connection) {
  51. connection.close();
  52. }
  53. } catch (JMSException e) {
  54. e.printStackTrace();
  55. }
  56. }
  57. }
  58. }
 再写接收者:


  
  
  1. package com.kinglong.activemq.queue;
  2. import org.apache.activemq.ActiveMQConnectionFactory;
  3. import javax.jms.*;
  4. public class Receiver {
  5. /**消息服务器的连接地址**/
  6. public static final String BROKER_URL = "tcp://192.168.174.129:61616";
  7. public static void main(String[] args) {
  8. Receiver receiver = new Receiver();
  9. receiver.receiveMessage();
  10. }
  11. /**
  12. * 接收消息
  13. *
  14. */
  15. public void receiveMessage () {
  16. Connection connection = null;
  17. Session session = null;
  18. MessageConsumer messageConsumer = null;
  19. try {
  20. //1.创建一个连接工厂
  21. ConnectionFactory connectionFactory = new ActiveMQConnectionFactory(BROKER_URL);
  22. //2.创建一个连接
  23. connection = connectionFactory.createConnection();
  24. //3.创建一个Session
  25. session = connection.createSession(Boolean.FALSE, Session.AUTO_ACKNOWLEDGE);
  26. //4.创建一个目的地
  27. Destination destination = session.createQueue( "myQueue");
  28. //5.创建一个消息的消费者(接收者)
  29. messageConsumer = session.createConsumer(destination);
  30. //接收消息之前,需要把连接启动一下
  31. connection.start();
  32. //6.接收消息
  33. Message message = messageConsumer.receive();
  34. //判断消息的类型
  35. if (message instanceof TextMessage) { //判断是否是文本消息
  36. String text = ((TextMessage) message).getText();
  37. System.out.println( "接收到的消息内容是:" + text);
  38. }
  39. } catch (JMSException e) {
  40. e.printStackTrace();
  41. } finally {
  42. try {
  43. //关闭连接释放资源
  44. if ( null != messageConsumer) {
  45. messageConsumer.close();
  46. }
  47. if ( null != session) {
  48. session.close();
  49. }
  50. if ( null != connection) {
  51. connection.close();
  52. }
  53. } catch (JMSException e) {
  54. e.printStackTrace();
  55. }
  56. }
  57. }
  58. }
总结:

 创建过程中有几个重要的注意点,说明一下:


  
  
  1. 1. session = connection.createSession(Boolean.FALSE, Session.AUTO_ACKNOWLEDGE);
  2. // 其中:Boolean.FALSE表示本次会话不开启事务管理,假如需要开启事务管理,将其改为Boolean.TRUE即可
  3. //同时需要在发送消息后添加session.commit(),否则,消息是不会被提交的.
  4. //Session.AUTO_ACKNOWLEDGE表示消息确认机制
  5. AUTO_ACKNOWLEDGE:自动确认
  6. CLIENT_ACKNOWLEDGE:客户端确认
  7. SESSION_TRANSACTED:事务确认,如果使用事务推荐使用该确认机制
  8. AUTO_ACKNOWLEDGE:懒散式确认,消息偶尔不会被确认,也就是消息可能会被重复发送.但发生的概率很小
  9. 2. connection.start();
  10. //在消息接收端,接受消息前需要加入这段代码,开启连接,否则一样无法获取消息.
  11. 3. Destination destination = session.createQueue( "myQueue");
  12. //创建目的地时,如果做测试收不到信息,可以将目的地名称修改一下,我用的是IDEA,不清楚为何,
  13. //有时候收不到信息,修改一下就好了,猜测可能是缓存的原因吧

发布与订阅的topic方式实际与点对点的queue方式,代码通用很多,只是在创建目的地Destination时候创建为

Destination destination = session.createTopic("myTopic");
  
  
2.4.2Queue与Topic比较

2.4.3拉模式与推模式

  a. 点对点消息,如果没有消费者在监听队列,消息将保留在队列中,直至消息消费者连接到队列为止。 这种消息传递模型是
传统 意义上的懒模型或轮询模型。在此模型中,消息不是自动推动给消息消费 者的,而是要由消息消费者从队列中请求获得(拉模式)。 
 b.pub/sub消息传递模型基本上是一个推模型。在该模型中,消息会自动广播,消息消费者无须通过主 动请求或轮询主题的方 法来获得新的消息。

2.5 ActiveMQ消息类型
  • 1、TextMessage 文本消息:携带一个java.lang.String作为有效数据(负载)的消息,可用于字符串类型的信息交换;
  • 2、ObjectMessage 对象消息:携带一个可以序列化的Java对象作为有效负载的消息,可用于Java对象类型的信息交换;
  • 3、MapMessage 映射消息:携带一组键值对的数据作为有效负载的消息,有效数据值必须是Java原始数据类型(或者它们的包装类)及String。即:byte, short, int, long, float, double, char, boolean, String
  • 4、BytesMessage 字节消息 :携带一组原始数据类型的字节流作为有效负载的消息;
  • 5、StreamMessage 流消息:携带一个原始数据类型流作为有效负载的消息,它保持了写入流时的数据类型,写入什么类型,
  • 则读取也需要是相同的类型;

需要注意的是:如果使用对象消息做Demo时,如果使用之前的连接创建方式可能会无法接收到消息,因为安全问题.所以,如果想要使用Demo测试对象消息,创建连接时建议改为这样(官网推荐的连接方式):


  
  
  1. //创建对象消息连接工厂
  2. ActiveMQConnectionFactory activeMQConnectionFactory = new ActiveMQConnectionFactory(BROKER_URL);
  3. List<String > list = new ArrayList<String>();
  4. list.add( "com.kinglong.activemq.receiver");
  5. list.add( "com.kinglong.activemq.model");
  6. activeMQConnectionFactory.setTrustedPackages(list);
2.6 ActiveMQ事务消息和非事务消息

 消息分为事务消息和非事务消息

1、事务消息:创建会话Session使用transacted=true
connection.createSession(Boolean.TRUE, Session.AUTO_ACKNOWLEDGE);
2、非事务消息:创建会话Session使用transacted=false
 connection.createSession(Boolean.FALSE, Session.AUTO_ACKNOWLEDGE);

        事务消息必须在发送和接收完消息后显式地调用session.commit();

 事务性消息,不管设置何种消息确认模式,都会自动被确认;与设置的确认机制无关,但官方推荐事务性消息使用事务确认机制.

2.7 ActiveMQ消息确认机制

 消息只有在被确认之后,才认为已经被成功消费,然后消息才会从队列或主题中删除。消息的成功消费通常包含三个阶段:

                           

  (1)、客户接收消息;(2)、客户处理消息;(3)、消息被确认;

确认机制前面提过一下,共有四种:

  • (1)、Session.AUTO_ACKNOWLEDGE;客户(消费者)成功从receive方法返回时,或者从MessageListener.onMessage方法成功返回时,会话自动确认消息,然后自动删除消息.
  • (2)、Session.CLIENT_ACKNOWLEDGE;客户通过显式调用消息的acknowledge方法确认消息,。 即在接收端调用message.acknowledge();方法,否则,消息是不会被删除的.
  • (3)、Session. DUPS_OK_ACKNOWLEDGE ;不是必须确认,是一种“懒散的”消息确认,消息可能会重复发送,在第二次重新传送消息时,消息头的JMSRedelivered会被置为true标识当前消息已经传送过一次,客户端需要进行消息的重复处理控制。
  • (4)、 Session.SESSION_TRANSACTED;事务提交并确认。
2.8 ActiveMQ持久化消息与非持久化消息

 messageProducer.setDeliveryMode(DeliveryMode.NON_PERSISTENT);//不持久化

 messageProducer.setDeliveryMode(DeliveryMode.PERSISTENT);//持久化的,当然activemq发送消息默认都是持久化的

说明:

设置完后,如果为持久化,那么消息在没有被消费前都会被写入本地磁盘kahadb文件中保存起来,即使服务器宕机,也不会影响

消息.如果是非持久化的,那么,服务一旦宕机之类的情况发生,消息即会被删除.

ActiveMQ默认是持久化的.

2.9 ActiveMQ消息过滤

ActiveMQ提供了一种机制,可根据消息选择器中的标准来执行消息过滤,只接收符合过滤标准的消息;

生产者可在消息中放入特有的标志,而消费者使用基于这些特定的标志来接收消息;

1、发送消息放入特殊标志:message.setStringProperty(name, value);

2、接收消息使用基于特殊标志的消息选择器:

MessageConsumer createConsumer(Destination destination, String messageSelector);

注:消息选择器是一个字符串,语法与数据库的SQL相似,相当于SQL语句where条件后面的内容;

具体代码如下:

发送端代码:


  
  
  1. package com.bjpowernode.activemq.selector;
  2. import org.apache.activemq.ActiveMQConnectionFactory;
  3. import javax.jms.*;
  4. /**
  5. * 消息发送者
  6. *
  7. */
  8. public class Sender {
  9. /**消息服务器的连接地址**/
  10. public static final String BROKER_URL = "tcp://192.168.174.129:61616";
  11. public static void main(String[] args) {
  12. Sender sender = new Sender();
  13. sender.sendMessage( "Hello ActiveMQ.");
  14. }
  15. /**
  16. * 发送消息
  17. *
  18. * @param msg
  19. */
  20. public void sendMessage (String msg) {
  21. Connection connection = null;
  22. Session session = null;
  23. MessageProducer messageProducer = null;
  24. try {
  25. //1.创建一个连接工厂
  26. ConnectionFactory connectionFactory = new ActiveMQConnectionFactory(BROKER_URL);
  27. //2.创建一个连接
  28. connection = connectionFactory.createConnection();
  29. //3.创建一个Session
  30. session = connection.createSession(Boolean.FALSE, Session.AUTO_ACKNOWLEDGE);
  31. //5.创建一个目的地
  32. Destination destination = session.createQueue( "myQueue");
  33. //6.创建一个消息的生产者(发送者)
  34. messageProducer = session.createProducer(destination);
  35. //设置发送的消息是否需要持久化
  36. messageProducer.setDeliveryMode(DeliveryMode.NON_PERSISTENT); //这里使用不持久化
  37. //创建一个循环,测试消息标识的使用
  38. for ( int i= 0; i< 20; i++) {
  39. //4.创建消息,此处创建了一个文本消息
  40. Message message = session.createTextMessage(msg+i);
  41. //将消息设置一个特有的标识
  42. message.setIntProperty( "id", i);
  43. //7.发送消息
  44. messageProducer.send(message);
  45. }
  46. } catch (JMSException e) {
  47. e.printStackTrace();
  48. } finally {
  49. try {
  50. //关闭连接释放资源
  51. if ( null != messageProducer) {
  52. messageProducer.close();
  53. }
  54. if ( null != session) {
  55. session.close();
  56. }
  57. if ( null != connection) {
  58. connection.close();
  59. }
  60. } catch (JMSException e) {
  61. e.printStackTrace();
  62. }
  63. }
  64. }
  65. }
接收端代码:


  
  
  1. package com.kinglong.activemq.selector;
  2. import org.apache.activemq.ActiveMQConnectionFactory;
  3. import javax.jms.*;
  4. public class Receiver {
  5. /**消息服务器的连接地址**/
  6. public static final String BROKER_URL = "tcp://192.168.174.129:61616";
  7. public static void main(String[] args) {
  8. Receiver receiver = new Receiver();
  9. receiver.receiveMessage();
  10. }
  11. /**
  12. * 接收消息
  13. *
  14. */
  15. public void receiveMessage () {
  16. Connection connection = null;
  17. Session session = null;
  18. MessageConsumer messageConsumer = null;
  19. try {
  20. //1.创建一个连接工厂
  21. ConnectionFactory connectionFactory = new ActiveMQConnectionFactory(BROKER_URL);
  22. //2.创建一个连接
  23. connection = connectionFactory.createConnection();
  24. //3.创建一个Session
  25. session = connection.createSession(Boolean.FALSE, Session.AUTO_ACKNOWLEDGE);
  26. //4.创建一个目的地
  27. Destination destination = session.createQueue( "myQueue");
  28. //5.创建一个消息的消费者(接收者),selector即为消息选择器,通过选择需要的标识,过滤消息接受id为10-15之 //间的消息
  29. String selector = "id >=10 and id<=15";
  30. messageConsumer = session.createConsumer(destination, selector);
  31. //接收消息之前,需要把连接启动一下
  32. connection.start();
  33. while ( true) {
  34. //6.接收消息 同步接收
  35. Message message = messageConsumer.receive();
  36. //判断消息的类型
  37. if (message instanceof TextMessage) { //判断是否是文本消息
  38. String text = ((TextMessage) message).getText();
  39. System.out.println( "接收到的消息内容是:" + text);
  40. }
  41. }
  42. } catch (JMSException e) {
  43. e.printStackTrace();
  44. } finally {
  45. try {
  46. //关闭连接释放资源
  47. if ( null != messageConsumer) {
  48. messageConsumer.close();
  49. }
  50. if ( null != session) {
  51. session.close();
  52. }
  53. if ( null != connection) {
  54. connection.close();
  55. }
  56. } catch (JMSException e) {
  57. e.printStackTrace();
  58. }
  59. }
  60. }
  61. }
2.10 ActiveMQ消息接收方式

  同步接收:receive()方法接收消息叫同步接收,就是之前的Demo代码使用的接收方式.在不使用循环方法时接收端代码执行

一次即结束.

 异步接收:使用监听器接收消息,这种接收方式叫异步接收,接收端会一直处于监听状态,只要有消息产生,即会接收消息.

下面是异步接收代码:


  
  
  1. package com.kinglong.activemq.listener;
  2. import org.apache.activemq.ActiveMQConnectionFactory;
  3. import javax.jms.*;
  4. public class Receiver {
  5. /**消息服务器的连接地址**/
  6. public static final String BROKER_URL = "tcp://192.168.174.129:61616";
  7. public static void main(String[] args) {
  8. Receiver receiver = new Receiver();
  9. receiver.receiveMessage();
  10. }
  11. /**
  12. * 接收消息
  13. *
  14. */
  15. public void receiveMessage () {
  16. Connection connection = null;
  17. Session session = null;
  18. MessageConsumer messageConsumer = null;
  19. try {
  20. //1.创建一个连接工厂
  21. ConnectionFactory connectionFactory = new ActiveMQConnectionFactory(BROKER_URL);
  22. //2.创建一个连接
  23. connection = connectionFactory.createConnection();
  24. //3.创建一个Session
  25. session = connection.createSession(Boolean.FALSE, Session.AUTO_ACKNOWLEDGE);
  26. //4.创建一个目的地
  27. Destination destination = session.createQueue( "myQueue");
  28. //5.创建一个消息的消费者(接收者)
  29. messageConsumer = session.createConsumer(destination);
  30. //接收消息之前,需要把连接启动一下
  31. connection.start();
  32. //6.接收消息 同步接收
  33. //Message message = messageConsumer.receive();
  34. //异步接收,使用监听器接收消息
  35. messageConsumer.setMessageListener( new MessageListener(){
  36. public void onMessage(Message message) {
  37. //判断消息的类型
  38. if (message instanceof TextMessage) { //判断是否是文本消息
  39. String text = null;
  40. try {
  41. text = ((TextMessage) message).getText();
  42. } catch (JMSException e) {
  43. e.printStackTrace();
  44. }
  45. System.out.println( "接收到的消息内容是:" + text);
  46. }
  47. }
  48. });
  49. } catch (JMSException e) {
  50. e.printStackTrace();
  51. } finally {
  52. /*try {
  53. //关闭连接释放资源
  54. if (null != messageConsumer) {
  55. messageConsumer.close();
  56. }
  57. if (null != session) {
  58. session.close();
  59. }
  60. if (null != connection) {
  61. connection.close();
  62. }
  63. } catch (JMSException e) {
  64. e.printStackTrace();
  65. }*/
  66. }
  67. }
  68. }
三.ActiveMQ的集成使用:

3.1ActiveMQ与Spring集成(以下是一个简单的上手Demo):

鉴于发送端与接收端pom文件依赖相同,所以只写一份,依赖如下:


  
  
  1. <!--spring-jms依赖-->
  2. <dependency>
  3. <groupId>org.springframework </groupId>
  4. <artifactId>spring-jms </artifactId>
  5. <version>4.3.13.RELEASE </version>
  6. </dependency>
  7. <!--activemq的jar依赖-->
  8. <dependency>
  9. <groupId>org.apache.activemq </groupId>
  10. <artifactId>activemq-client </artifactId>
  11. <version>5.15.2 </version>
  12. </dependency>
  13. <!-- JMS规范的jar依赖 -->
  14. <dependency>
  15. <groupId>javax.jms </groupId>
  16. <artifactId>javax.jms-api </artifactId>
  17. <version>2.0.1 </version>
  18. </dependency>


发送端:(需要两个配置文件)

1. applicationContext.xml


  
  
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi= "http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation= "http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
  5. <import resource="applicationContext-jms.xml"/>
  6. </beans>
2. applicationContext-jms.xml


  
  
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi= "http://www.w3.org/2001/XMLSchema-instance"
  4. xmlns:context= "http://www.springframework.org/schema/context"
  5. xsi:schemaLocation= "http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
  6. <context:component-scan base-package="com.kinglong.activemq.sender"/>
  7. <!-- 配置一个连接工厂 -->
  8. <bean id="connectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">
  9. <property name="brokerURL" value="tcp://192.168.174.129:61616"/>
  10. </bean>
  11. <!-- 配置JmsTemplate -->
  12. <bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
  13. <property name="connectionFactory" ref="connectionFactory" />
  14. <property name="defaultDestinationName" value="springTopic" />
  15. <!--指定消息传送模式,true表示发布订阅、false表示点对点-->
  16. <property name="pubSubDomain" value="true"/>
  17. </bean>
  18. </beans>
发送类:


  
  
  1. package com.kinglong.activemq.sender;
  2. import org.springframework.beans.factory.annotation.Autowired;
  3. import org.springframework.jms.core.JmsTemplate;
  4. import org.springframework.jms.core.MessageCreator;
  5. import org.springframework.stereotype.Component;
  6. import javax.jms.JMSException;
  7. import javax.jms.Message;
  8. import javax.jms.Session;
  9. @Component
  10. public class Sender {
  11. @Autowired
  12. private JmsTemplate jmsTemplate;
  13. public void sendMessage (final String msg) {
  14. //发送消息
  15. jmsTemplate.send( new MessageCreator() {
  16. public Message createMessage(Session session) throws JMSException {
  17. return session.createTextMessage(msg);
  18. }
  19. });
  20. }
  21. }
下面是测试类:


  
  
  1. package com.kinglong.activemq.sender;
  2. import org.springframework.context.support.ClassPathXmlApplicationContext;
  3. public class Test {
  4. public static void main(String[] args) {
  5. ClassPathXmlApplicationContext context =
  6. new ClassPathXmlApplicationContext( "classpath:applicationContext.xml");
  7. Sender springSender = (Sender)context.getBean( "sender");
  8. springSender.sendMessage( "Spring jms ActiveMQ.");
  9. }
  10. }

接收端(也同样需要两个配置文件,这里使用异步接收,所以需要配置一个监听器):

1. applicationContext.xml


  
  
  1. <?xml version= "1.0" encoding= "UTF-8"?>
  2. <beans xmlns= "http://www.springframework.org/schema/beans"
  3. xmlns:xsi= "http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation= "http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
  5. < import resource= "applicationContext-jms.xml"/>
  6. </beans>
2. applicationContext-jms.xml

 
 

  
  
  1. <?xml version= "1.0" encoding= "UTF-8"?>
  2. <beans xmlns= "http://www.springframework.org/schema/beans"
  3. xmlns:xsi= "http://www.w3.org/2001/XMLSchema-instance"
  4. xmlns:context= "http://www.springframework.org/schema/context"
  5. xsi:schemaLocation= "http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
  6. <context:component-scan base- package= "com.kinglong.activemq.receiver"/>
  7. <!-- 配置一个连接工厂 -->
  8. <bean id= "connectionFactory" class= "org.apache.activemq.ActiveMQConnectionFactory">
  9. <property name= "brokerURL" value= "tcp://192.168.174.129:61616"/>
  10. </bean>
  11. <!-- 配置JmsTemplate -->
  12. <bean id= "jmsTemplate" class= "org.springframework.jms.core.JmsTemplate">
  13. <property name= "connectionFactory" ref= "connectionFactory" />
  14. <property name= "defaultDestinationName" value= "springTopic" />
  15. <!--指定消息传送模式, true表示发布订阅、 false表示点对点-->
  16. <property name= "pubSubDomain" value= "true"/>
  17. </bean>
  18. <!-- 我们自定义的一个消息监听器 -->
  19. <bean id= "receiverListener" class= "com.kinglong.activemq.receiver.MyMessageListener" />
  20. <!-- 配置一个sping监听器的容器 -->
  21. <bean class= "org.springframework.jms.listener.DefaultMessageListenerContainer">
  22. <property name= "connectionFactory" ref= "connectionFactory"/>
  23. <property name= "destinationName" value= "springTopic"/>
  24. <property name= "messageListener" ref= "receiverListener" />
  25. <!--指定消息传送模式, true表示发布订阅、 false表示点对点-->
  26. <property name= "pubSubDomain" value= "true"/>
  27. </bean>
  28. </beans>
监听器:( MyMessageListener)

  
  
  1. package com.kinglong.activemq.receiver;
  2. import javax.jms.JMSException;
  3. import javax.jms.Message;
  4. import javax.jms.MessageListener;
  5. import javax.jms.TextMessage;
  6. public class MyMessageListener implements MessageListener {
  7. public void onMessage(Message message) {
  8. if (message instanceof TextMessage) {
  9. String text = null;
  10. try {
  11. text = ((TextMessage) message).getText();
  12. } catch (JMSException e) {
  13. e.printStackTrace();
  14. }
  15. System.out.println(text);
  16. }
  17. }
  18. }
下面是测试类:


  
  
  1. package com.kinglong.activemq.receiver;
  2. import org.springframework.context.support.ClassPathXmlApplicationContext;
  3. public class Test {
  4. public static void main(String[] args) {
  5. ClassPathXmlApplicationContext context =
  6. new ClassPathXmlApplicationContext( "classpath:applicationContext.xml");
  7. }
  8. }
说明:由于使用的是Topic发布订阅模式,所以测试时一定先开启接收端服务,再开启发送端发送消息,否则接不到消息.

相比较之下,spring集成的activemq使用已经相当简化,与原始版相比,整个链接对象的创建全部交给spring完成了,所以效率上更高了.

其次,各属性配置也都从代码中剥离归整在配置文件里,使得修改配置也变得更为容易,但是,个人觉得还是有必要学习学习原始版本,

可以更好地理解其创建过程,加深理解.


3.2ActiveMQ与Springboot集成(以下是一个简单的上手Demo):

同样pom依赖,因为依赖相同,所以只写一份,如下:


  
  
  1. <!--配置父级依赖-->
  2. <parent>
  3. <groupId>org.springframework.boot </groupId>
  4. <artifactId>spring-boot-starter-parent </artifactId>
  5. <version>1.5.9.RELEASE </version>
  6. <relativePath/> <!-- lookup parent from repository -->
  7. </parent>
  8. <!--属性配置-->
  9. <properties>
  10. <project.build.sourceEncoding>UTF-8 </project.build.sourceEncoding>
  11. <project.reporting.outputEncoding>UTF-8 </project.reporting.outputEncoding>
  12. <java.version>1.8 </java.version>
  13. </properties>
  14. <dependencies>
  15. <!--开发springboot的Java程序的起步依赖-->
  16. <dependency>
  17. <groupId>org.springframework.boot </groupId>
  18. <artifactId>spring-boot-starter </artifactId>
  19. </dependency>
  20. <dependency>
  21. <groupId>org.springframework.boot </groupId>
  22. <artifactId>spring-boot-starter </artifactId>
  23. </dependency>
  24. <!--springboot集成activemq的起步依赖-->
  25. <dependency>
  26. <groupId>org.springframework.boot </groupId>
  27. <artifactId>spring-boot-starter-activemq </artifactId>
  28. </dependency>
  29. </dependencies>
发送端:

只有一个主配置文件:application.properties


  
  
  1. spring.activemq.broker-url=tcp://192.168.174.129:61616
  2. #发布订阅模式
  3. spring.jms.pub-sub-domain=true
main方法类:


  
  
  1. package com.kinglong.activemq;
  2. import org.springframework.boot.SpringApplication;
  3. import org.springframework.boot.autoconfigure.SpringBootApplication;
  4. import org.springframework.context.ConfigurableApplicationContext;
  5. @SpringBootApplication
  6. public class SenderApplication {
  7. public static void main(String[] args) {
  8. ConfigurableApplicationContext context = SpringApplication.run(SenderApplication.class, args);
  9. SpringBootSender springBootSender = (SpringBootSender)context.getBean( "springBootSender");
  10. springBootSender.sendMessage( "springboot activemq.");
  11. }
  12. }


发送者:SpringBootSender


   
   
  1. package com.kinglong.activemq;
  2. import org.springframework.beans.factory.annotation.Autowired;
  3. import org.springframework.jms.core.JmsTemplate;
  4. import org.springframework.jms.core.MessageCreator;
  5. import org.springframework.stereotype.Component;
  6. import javax.jms.JMSException;
  7. import javax.jms.Message;
  8. import javax.jms.Session;
  9. @Component
  10. public class SpringBootSender {
  11. @Autowired //注入JmsTemplate
  12. private JmsTemplate jmsTemplate;
  13. //发送消息,"myTopic"是发送到的队列destination,message是待发送的消息
  14. public void sendMessage(String message) {
  15. jmsTemplate.send( "myTopic", new MessageCreator() {
  16. @Override
  17. public Message createMessage(Session session) throws JMSException {
  18. return session.createTextMessage(message);
  19. }
  20. });
  21. }
  22. }
接收端:
主配置文件与发送端相同
main方法类: ReceiverApplication

   
   
  1. package com.kinglong.activemq;
  2. import org.springframework.boot.SpringApplication;
  3. import org.springframework.boot.autoconfigure.SpringBootApplication;
  4. import org.springframework.context.ConfigurableApplicationContext;
  5. import javax.jms.JMSException;
  6. @SpringBootApplication
  7. public class ReceiverApplication {
  8. public static void main(String[] args) throws JMSException {
  9. ConfigurableApplicationContext context = SpringApplication.run(ReceiverApplication.class, args);
  10. //这里采用异步接收
  11. }
  12. }

监听器: MessageListenerReceiver

   
   
  1. package com.kinglong.activemq;
  2. import org.springframework.jms.annotation.JmsListener;
  3. import org.springframework.stereotype.Component;
  4. @Component
  5. public class MessageListenerReceiver {
  6. @JmsListener(destination = "myTopic")
  7. public void receiveQueue(String text) {
  8. System.out.println( "Consumer收到的报文为:" + text);
  9. }
  10. }
OVER!  是不是发现springboot集成的ActiveMQ更加精巧了?配置文件都不用写了,springboot全帮我们做完了.不过,还是那句话,建议把原始版本原理,思路 整通了再做spring或是springboot的集成,要不感觉直接理解起来springboot的发送和接收还是比较抽象的.


四.ActiveMQ集群
4.1 何为集群?
集群就是将相同的程序、功能,部署在两台或多台服务器上,这些服务器对外提供的功能是完全一样的。通过不断横向扩展增加服务器的方式,以提高服务的能力。

4.1.1 不集群模式


4.1.2 集群模式

4.2 集群的优势:

 1、集群可以解决单点故障问题;

  2、集群可以提高系统服务能力;









  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值