MQ(Apache ActiveMQ)消息队列

1.1 MQApache ActiveMQ)消息队列

1.1.1JMSJava Message Service

JMSJava消息服务(Java Message Service)应用程序接口是一个Java平台中关于面向消息中间件(MOM)的API(面向接口),用于在两个应用程序之间,或分布式系统中发送消息,进行异步通信。Java消息服务是一个与具体平台无关的API,绝大多数MOM提供商都对JMS提供支持。

(MOMMQ类似,实现同种功能)。

1.1.2MQActiveMQ)概述

1、“消息队列”是在消息的传输过程中保存消息的容器。

2MQActiveMQ Apache出品,最流行的,能力强劲的开源消息总线。ActiveMQ 是一个完全支持JMS1.1J2EE 1.4规范的 JMS Provider实现。

3MQJMS技术规范的具体实现

1.1.2.1      MQActiveMQ)作用

消息队列在大型电子商务类网站,如京东、淘宝、去哪儿等网站有这深入的应用,队列的主要作用是消除高并发访问高峰,加快网站的响应速度。在不使用消息队列的情况下,用户的请求数据直接写入数据库,在高并发的情况下,会对数据库造成巨大的压力,同时也使得系统响应延迟加剧。在使用队列后,用户的请求发给队列后立即返回(当然不能直接给用户提示订单提交成功,京东上提示:您“您提交了订单,请等待系统确认”),再由消息队列的消费者进程从消息队列中获取数据,异步写入数据库。由于消息队列的服务处理速度远快于数据库,因此用户的响应延迟可得到有效改善。

1.1.2.2      MQActiveMQ)工作原理

1、 解决服务之间耦合

2、 使用消息队列,增加系统并发处理量

1.1.2.3      MQActiveMQ)应用场景

1、 用户注册,重点用户信息数据库保存,发短信、发邮件,增加业务处理复杂度,这

时候使用 MQ, 将发短信、发邮箱,通知 MQ,由另外服务平台完成

2、 搜索平台、缓存平台

查询数据,建立缓存、索引 ,不从数据库查询,从缓存或者索引库查询

当增加、修改、删除数据时,发送消息给 MQ, 缓存平台、索引平台 从 MQ 获取到这个信息,更新缓存或者索引

1.1.3MQActive MQ)的下载与安装

1.1.3.1      下载

下载地址: http://activemq.apache.org/

 

1.1.3.2      安装

解压即安装

1.1.3.3      使用

进入bin目录下对应平台,执行activemq.bat,将该目录配置成环境变量

通过浏览器访问http://localhost:8161

使用admin/admin登录ActiveMQ

登录之后

 

1.1.3.4      Queue&Topic

ActiveMQ使用的是标准生产者和消费者模型

       有两种数据结构:QueueTopic

1、 Queue队列,生产者生产了一个消息,只能由一个消费者进行消费;

2、 Topic话题,生产者生产了一个消息,可以由多个消费者进行消费。

1.1.4使用java程序操作ActiveMQ

1.1.4.1      maven坐标导入(jar包导入)

    <dependency>

       <groupId>org.apache.activemq</groupId>

       <artifactId>activemq-all</artifactId>

       <version>5.14.0</version>

    </dependency>

<!-- 用于测试 -->

    <dependency>

       <groupId>junit</groupId>

       <artifactId>junit</artifactId>

       <version>4.12</version>

    </dependency>

1.1.4.2      编写MQ消息生产者

import javax.jms.Connection;

import javax.jms.ConnectionFactory;

import javax.jms.MessageProducer;

import javax.jms.Queue;

import javax.jms.Session;

 

import org.apache.activemq.ActiveMQConnectionFactory;

import org.junit.Test;

 

public class ActiveMQProducer {

    @Test

    public void testProduceMQ() throws Exception {

       // 1、创建连接工厂(使用默认用户名、密码、路径:tcp://host:61616

       ConnectionFactory connectionFactory = new ActiveMQConnectionFactory();

       // 2、获得连接

       Connection connection = connectionFactory.createConnection();

       // 3、打开连接

       connection.start();

       // 4、创建Session对象

       Session session = connection.createSession(true,

              Session.AUTO_ACKNOWLEDGE);

       // 5、通过Session创建消息对象(Topic/Queue

// Topic topic = session.createTopic("helloworld");

       Queue queue = session.createQueue("HelloWorld");

       // 6、通过Session创建生产者对象

       MessageProducer producer = session.createProducer(queue);

 

       // 7、通过消息的生产者给ActiveMQ发送消息

       for (int i = 0; i < 10; i++) {

           producer.send(session.createTextMessage("你好,activeMQ:" + i));

       }

       // 8Session提交

       session.commit();

    }

}

1.1.4.3      打开activemq.bat

运行测试方法

1.1.4.4访问http://localhost:8161

并用admin/admin登录

1.1.4.5      编写MQ消费者代码

A)使用MessageConsumer完成消费(不建议使用)

package activeMQ_helloworld;

 

import javax.jms.Connection;

import javax.jms.ConnectionFactory;

import javax.jms.MessageConsumer;

import javax.jms.Queue;

import javax.jms.Session;

import javax.jms.TextMessage;

 

import org.apache.activemq.ActiveMQConnectionFactory;

import org.junit.Test;

 

public class ActiveMQConsumer {

 

    @Test

    // 直接消费

    public void testCosumeMQ() throws Exception {

       // 1、创建连接工厂

       ConnectionFactory connectionFactory = new ActiveMQConnectionFactory();

       // 2、获取连接

       Connection connection = connectionFactory.createConnection();

       // 3、开启连接(必须开启)

       connection.start();

        // 4、创建Session对象

       //第一个参数,是否使用事物,如果设为true,操作队列后,必须使用session.commit();

       Session session = connection.createSession(false,

              Session.AUTO_ACKNOWLEDGE);

       // 5、通过Session创建消息对象(QueueTopic

       Queue queue = session.createQueue("HelloWorld");

       // 6、通过Session创建消费者

       MessageConsumer messageConsumer = session.createConsumer(queue);

       // 7、消费消息

       while (true) {

           TextMessage message = (TextMessage) messageConsumer.receive(10000);

           if (message != null) {

              System.out.println(message.getText());

           } else {

              break;

           }

       }

    }

}

B) 使用监听器,监听消息的内容,进行消费(建议使用)

package activeMQ_helloworld;

 

import javax.jms.Connection;

import javax.jms.ConnectionFactory;

import javax.jms.JMSException;

import javax.jms.Message;

import javax.jms.MessageConsumer;

import javax.jms.MessageListener;

import javax.jms.Queue;

import javax.jms.Session;

import javax.jms.TextMessage;

 

import org.apache.activemq.ActiveMQConnectionFactory;

import org.junit.Test;

 

public class ActiveMQConsumer {

 

    @Test

    // 直接消费

    public void testCosumeMQ() throws Exception {

       // 1、创建连接工厂

       ConnectionFactory connectionFactory = new ActiveMQConnectionFactory();

       // 2、获取连接

       Connection connection = connectionFactory.createConnection();

       // 3、开启连接(必须开启)

       connection.start();

       // 4、创建Session对象

        //第一个参数,是否使用事物,如果设为true,操作队列后,必须使用session.commit();

       Session session = connection.createSession(false,

              Session.AUTO_ACKNOWLEDGE);

       // 5、通过Session创建消息对象(QueueTopic

       Queue queue = session.createQueue("HelloWorld");

       // 6、通过Session创建消费者

       MessageConsumer messageConsumer = session.createConsumer(queue);

       // 7、消费消息

       messageConsumer.setMessageListener(new MessageListener() {

           // 每次接收消息,自动调用 onMessage

           public void onMessage(Message message) {

              TextMessage textMessage = (TextMessage) message;

              try {

                  System.out.println(textMessage.getText());

              } catch (JMSException e) {

                  e.printStackTrace();

              }

           }

       });

 

       while (true) {

           // 不能让junit线程死掉

       }

    }

}

1.1.4.6      访问http://localhost:8161

1.1.5结合spring完成ActiveMQ编程

1.1.5.1      Maven坐标引入

  <dependencies>

  <!-- Spring -->

    <dependency>

       <groupId>org.springframework</groupId>

       <artifactId>spring-context</artifactId>

       <version>4.1.7.RELEASE</version>

    </dependency>

    <!-- Spring整合Junit -->

    <dependency>

       <groupId>org.springframework</groupId>

       <artifactId>spring-test</artifactId>

       <version>4.1.7.RELEASE</version>

    </dependency>

    <!-- 测试 -->

    <dependency>

       <groupId>junit</groupId>

       <artifactId>junit</artifactId>

       <version>4.12</version>

    </dependency>

    <!-- ActiveMQ -->

    <dependency>

       <groupId>org.apache.activemq</groupId>

       <artifactId>activemq-all</artifactId>

       <version>5.14.0</version>

    </dependency>

    <!-- Spring整合ActiveMQ -->

    <dependency>

       <groupId>org.springframework</groupId>

       <artifactId>spring-jms</artifactId>

       <version>4.1.7.RELEASE</version>

    </dependency>

1.1.5.2      生产者配置文件

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"

    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:aop="http://www.springframework.org/schema/aop"

    xmlns:context="http://www.springframework.org/schema/context"

    xmlns:jdbc="http://www.springframework.org/schema/jdbc"xmlns:tx="http://www.springframework.org/schema/tx"

    xmlns:jpa="http://www.springframework.org/schema/data/jpa"xmlns:task="http://www.springframework.org/schema/task"

    xmlns:amq="http://activemq.apache.org/schema/core"

    xmlns:jms="http://www.springframework.org/schema/jms"

    xsi:schemaLocation="

       http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.1.xsd

       http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.1.xsd

       http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd

       http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-4.1.xsd

       http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.1.xsd

       http://www.springframework.org/schema/data/jpa

       http://www.springframework.org/schema/data/jpa/spring-jpa.xsd

       http://www.springframework.org/schema/jms

http://www.springframework.org/schema/jms/spring-jms.xsd

       http://activemq.apache.org/schema/core

http://activemq.apache.org/schema/core/activemq-core-5.8.0.xsd ">

   

    <!-- 扫描包 -->

    <context:component-scan base-package="cn.activemq" />

   

    <!-- ActiveMQ 连接工厂 -->

    <!-- 真正可以产生ConnectionConnectionFactory,由对应的 JMS服务厂商提供-->

    <!-- 如果连接网络:tcp://ip:61616;未连接网络:tcp://localhost:61616 以及用户名,密码-->

    <amq:connectionFactory id="amqConnectionFactory"

        brokerURL="tcp://localhost:61616" userName="admin" password="admin"  />

 

    <!-- Spring Caching连接工厂 -->

    <!-- Spring用于管理真正的ConnectionFactoryConnectionFactory --> 

    <bean id="connectionFactory" class="org.springframework.jms.connection.CachingConnectionFactory">

<!-- 目标ConnectionFactory对应真实的可以产生JMS ConnectionConnectionFactory --> 

<property name="targetConnectionFactory" ref="amqConnectionFactory"></property>

<!-- 同上,同理 -->

<!-- <constructor-arg ref="amqConnectionFactory" /> -->

<!-- Session缓存数量 -->

<property name="sessionCacheSize" value="100" />

    </bean>

   

     <!-- Spring JmsTemplate 的消息生产者 start-->

 

    <!-- 定义JmsTemplateQueue类型 -->

    <bean id="jmsQueueTemplate" class="org.springframework.jms.core.JmsTemplate">

<!-- 这个connectionFactory对应的是我们定义的Spring提供的那个ConnectionFactory对象 --> 

<constructor-arg ref="connectionFactory" />

<!-- pub/sub模型(发布/订阅),即队列模式 -->

<property name="pubSubDomain" value="false"/>

    </bean>

 

    <!-- 定义JmsTemplateTopic类型 -->

    <bean id="jmsTopicTemplate" class="org.springframework.jms.core.JmsTemplate">

<!-- 这个connectionFactory对应的是我们定义的Spring提供的那个ConnectionFactory对象 --> 

<constructor-arg ref="connectionFactory" />

<!-- pub/sub模型(发布/订阅) -->

<property name="pubSubDomain" value="true"/>

    </bean>

 

    <!--Spring JmsTemplate 的消息生产者 end-->

   

</beans>

1.1.5.3      生产者代码

QueueSender

package cn.activemq.producer.queue;

 

import javax.jms.JMSException;

import javax.jms.Message;

import javax.jms.Session;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.beans.factory.annotation.Qualifier;

import org.springframework.jms.core.JmsTemplate;

import org.springframework.jms.core.MessageCreator;

import org.springframework.stereotype.Service;

 

@Service

public class QueueSender {

    // 注入jmsTemplate

    @Autowired

    @Qualifier("jmsQueueTemplate")

    private JmsTemplate jmsTemplate;

 

    public void send(String queueName, final String message) {

       jmsTemplate.send(queueName, new MessageCreator() {

           public Message createMessage(Session session) throws JMSException {

              return session.createTextMessage(message);

           }

       });

    }

}

TopicSender

package cn.activemq.producer.topic;

 

import javax.jms.JMSException;

import javax.jms.Message;

import javax.jms.Session;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.beans.factory.annotation.Qualifier;

import org.springframework.jms.core.JmsTemplate;

import org.springframework.jms.core.MessageCreator;

import org.springframework.stereotype.Service;

 

@Service

public class TopicSender {

    // 注入jmsTemplate

    @Autowired

    @Qualifier("jmsTopicTemplate")

    private JmsTemplate jmsTemplate;

 

    public void send(String topicName, final String message) {

       jmsTemplate.send(topicName, new MessageCreator() {

 

           public Message createMessage(Session session) throws JMSException {

              return session.createTextMessage(message);

           }

       });

    }

}

1.1.5.4      生产者测试代码

package cn.activemq.producer.test;

 

import org.junit.Test;

import org.junit.runner.RunWith;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.test.context.ContextConfiguration;

import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import cn.activemq.producer.queue.QueueSender;

import cn.activemq.producer.topic.TopicSender;

 

@RunWith(SpringJUnit4ClassRunner.class)

@ContextConfiguration(locations = "classpath:applicationContext-mq.xml")

public class ProducerTest {

    @Autowired

    private QueueSender queueSender;

 

    @Autowired

    private TopicSender topicSender;

 

    @Test

    public void testSendMessage() {

       queueSender.send("spring_queue", "你好,Queue");

       topicSender.send("spring_topic", "你好,Topic");

    }

}

1.1.5.5      消费者配置文件

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"

    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:aop="http://www.springframework.org/schema/aop"

    xmlns:context="http://www.springframework.org/schema/context"

    xmlns:jdbc="http://www.springframework.org/schema/jdbc"xmlns:tx="http://www.springframework.org/schema/tx"

    xmlns:jpa="http://www.springframework.org/schema/data/jpa"xmlns:task="http://www.springframework.org/schema/task"

    xmlns:amq="http://activemq.apache.org/schema/core"

    xmlns:jms="http://www.springframework.org/schema/jms"

    xsi:schemaLocation="

       http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.1.xsd

       http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.1.xsd

       http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd

       http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-4.1.xsd

       http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.1.xsd

       http://www.springframework.org/schema/data/jpa

       http://www.springframework.org/schema/data/jpa/spring-jpa.xsd

       http://www.springframework.org/schema/jms

http://www.springframework.org/schema/jms/spring-jms.xsd

       http://activemq.apache.org/schema/core

http://activemq.apache.org/schema/core/activemq-core-5.8.0.xsd ">

   

    <!-- 扫描包 -->

    <context:component-scan base-package="cn.activemq.consumer" />

   

    <!-- ActiveMQ 连接工厂 -->

    <!-- 真正可以产生ConnectionConnectionFactory,由对应的 JMS服务厂商提供-->

    <!-- 如果连接网络:tcp://ip:61616;未连接网络:tcp://localhost:61616 以及用户名,密码-->

    <amq:connectionFactory id="amqConnectionFactory"

        brokerURL="tcp://localhost:61616" userName="admin" password="admin"  />

 

    <!-- Spring Caching连接工厂 -->

    <!-- Spring用于管理真正的ConnectionFactoryConnectionFactory --> 

    <bean id="connectionFactory" class="org.springframework.jms.connection.CachingConnectionFactory">

<!-- 目标ConnectionFactory对应真实的可以产生JMS ConnectionConnectionFactory --> 

<property name="targetConnectionFactory" ref="amqConnectionFactory"></property>

<!-- 同上,同理 -->

<!-- <constructor-arg ref="amqConnectionFactory" /> -->

<!-- Session缓存数量 -->

<property name="sessionCacheSize" value="100" />

    </bean>

   

     <!-- 消息消费者 start-->

 

    <!-- 定义Queue监听器 -->

    <jms:listener-container destination-type="queue" container-type="default"

        connection-factory="connectionFactory"acknowledge="auto">

<!-- 默认注册bean名称,应该是类名首字母小写-->

<jms:listener destination="spring_queue" ref="queueConsumer1"/>

        <jms:listener destination="spring_queue" ref="queueConsumer2"/>

    </jms:listener-container>

   

    <!-- 定义Topic监听器 -->

    <jms:listener-container destination-type="topic" container-type="default"

        connection-factory="connectionFactory"acknowledge="auto">

<jms:listener destination="spring_topic" ref="topicConsumer1"/>

<jms:listener destination="spring_topic" ref="topicConsumer2"/>

    </jms:listener-container>

 

    <!-- 消息消费者 end -->

   

</beans>

1.1.5.6      消费者代码

QueueConsumer1

package cn.activemq.consumer.queue;

 

import javax.jms.JMSException;

import javax.jms.Message;

import javax.jms.MessageListener;

import javax.jms.TextMessage;

import org.springframework.stereotype.Service;

 

@Service

public class QueueConsumer1 implements MessageListener {

    public void onMessage(Message message) {

       TextMessage textMessage = (TextMessage) message;

       try {

           System.out.println("消费者QueueConsumer1获取消息:" + textMessage.getText());

       } catch (JMSException e) {

           e.printStackTrace();

       }

    }

}

QueueConsumer2

package cn.activemq.consumer.queue;

 

import javax.jms.JMSException;

import javax.jms.Message;

import javax.jms.MessageListener;

import javax.jms.TextMessage;

import org.springframework.stereotype.Service;

 

@Service

public class QueueConsumer2 implements MessageListener {

    public void onMessage(Message message) {

       TextMessage textMessage = (TextMessage) message;

       try {

           System.out

                  .println("消费者QueueConsumer2获取消息:" + textMessage.getText());

       } catch (JMSException e) {

           e.printStackTrace();

       }

    }

}

TopicConsumer1

package cn.activemq.consumer.topic;

 

import javax.jms.JMSException;

import javax.jms.Message;

import javax.jms.MessageListener;

import javax.jms.TextMessage;

import org.springframework.stereotype.Service;

 

@Service

public class TopicConsumer1 implements MessageListener {

 

    public void onMessage(Message message) {

       TextMessage textMessage = (TextMessage) message;

       try {

           System.out

                  .println("消费者TopicConsumer1获取消息:" + textMessage.getText());

       } catch (JMSException e) {

           e.printStackTrace();

       }

    }

}

TopicConsumer2

package cn.activemq.consumer.topic;

 

import javax.jms.JMSException;

import javax.jms.Message;

import javax.jms.MessageListener;

import javax.jms.TextMessage;

import org.springframework.stereotype.Service;

 

@Service

public class TopicConsumer2 implements MessageListener {

 

    public void onMessage(Message message) {

       TextMessage textMessage = (TextMessage) message;

       try {

           System.out

                  .println("消费者TopicConsumer2获取消息:" + textMessage.getText());

       } catch (JMSException e) {

           e.printStackTrace();

       }

    }

}

1.1.5.7      消费者测试代码

package cn.activemq.producer.test;

 

import org.junit.Test;

import org.junit.runner.RunWith;

import org.springframework.test.context.ContextConfiguration;

import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

 

@RunWith(SpringJUnit4ClassRunner.class)

@ContextConfiguration(locations = "classpath:applicationContext-mq-consumer.xml")

public class ConsumerTest {

 

    @Test

    public void testConsumerMessage() {

       while (true) {

           // junit退出,防止进程死掉

       }

    }

}

1.1.5.8      测试结果

1、运行消费者测试类

2、运行生产者测试类

3、运行结果

 

 





posted @ 2018-04-10 10:34  zhaoxuan734  阅读(602)  评论(0编辑  收藏  举报