1.1 MQ(Apache ActiveMQ)消息队列

1.1.1JMS(Java Message Service)



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


(MOM和MQ类似,实现同种功能)。




1.1.2MQ(ActiveMQ)概述



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


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


3、MQ是JMS技术规范的具体实现




1.1.2.1      MQ(ActiveMQ)作用



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




1.1.2.2      MQ(ActiveMQ)工作原理



mq java工具类_spring


1、 解决服务之间耦合


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




1.1.2.3      MQ(ActiveMQ)应用场景



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


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


2、 搜索平台、缓存平台


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


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




1.1.3MQ(Active MQ)的下载与安装

1.1.3.1      下载

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



mq java工具类_mq java工具类_02




 



mq java工具类_java_03




1.1.3.2      安装

解压即安装

1.1.3.3      使用

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



mq java工具类_mq java工具类_04




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



mq java工具类_xml_05




使用admin/admin登录ActiveMQ



mq java工具类_mq java工具类_06




登录之后



mq java工具类_xml_07




 

1.1.3.4      Queue&Topic

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

Queue、Topic

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;


 
publicclass ActiveMQProducer {

    @Test

    publicvoid 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));

       }

       // 8、Session提交

       session.commit();

    }

}



1.1.4.3      打开activemq.bat



mq java工具类_mq java工具类_08




运行测试方法



mq java工具类_spring_09




1.1.4.4访问http://localhost:8161;

并用admin/admin登录



mq java工具类_xml_10




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;



 

publicclass ActiveMQConsumer {



 

    @Test


    // 直接消费


    publicvoid 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创建消息对象(Queue、Topic)


       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;


importjavax.jms.Queue;


import javax.jms.Session;


import javax.jms.TextMessage;



 

import org.apache.activemq.ActiveMQConnectionFactory;


import org.junit.Test;



 

publicclass ActiveMQConsumer {



 

    @Test


    // 直接消费


    publicvoid 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创建消息对象(Queue、Topic)


Queuequeue = session.createQueue("HelloWorld");


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


       MessageConsumer messageConsumer = session.createConsumer(queue);


       // 7、消费消息


       messageConsumer.setMessageListener(new MessageListener() {


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


           publicvoid 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



mq java工具类_java_11




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      生产者配置文件



<?xmlversion="1.0" encoding="UTF-8"?>

<beansxmlns="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-scanbase-package="cn.activemq" />

    

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

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

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

    <amq:connectionFactoryid="amqConnectionFactory"

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


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

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

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

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

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

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

<!-- <constructor-argref="amqConnectionFactory" /> -->

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

<propertyname="sessionCacheSize" value="100" />

    </bean>

    

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


 
    <!-- 定义JmsTemplate的Queue类型 -->

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

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

<constructor-argref="connectionFactory" />

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

<propertyname="pubSubDomain" value="false"/>

    </bean>


 
    <!-- 定义JmsTemplate的Topic类型 -->

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

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

<constructor-argref="connectionFactory" />

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

<propertyname="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;

importorg.springframework.stereotype.Service;


 
@Service

publicclass QueueSender {

    // 注入jmsTemplate

    @Autowired

    @Qualifier("jmsQueueTemplate")

    private JmsTemplate jmsTemplate;


 
    publicvoid 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

publicclass TopicSender {

    // 注入jmsTemplate

    @Autowired

    @Qualifier("jmsTopicTemplate")

    private JmsTemplate jmsTemplate;


 
    publicvoid 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")

publicclass ProducerTest {

    @Autowired

    private QueueSender queueSender;


 
    @Autowired

    private TopicSender topicSender;


 
    @Test

    publicvoid testSendMessage() {

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

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

    }

}



1.1.5.5      消费者配置文件



<?xmlversion="1.0" encoding="UTF-8"?>

<beansxmlns="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-scanbase-package="cn.activemq.consumer" />

    

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

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

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

    <amq:connectionFactoryid="amqConnectionFactory"

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


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

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

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

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

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

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

<!-- <constructor-argref="amqConnectionFactory" /> -->

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

<propertyname="sessionCacheSize" value="100" />

    </bean>

    

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


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

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

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

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

<jms:listenerdestination="spring_queue" ref="queueConsumer1"/>

        <jms:listenerdestination="spring_queue" ref="queueConsumer2"/>

    </jms:listener-container>

    

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

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

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

<jms:listenerdestination="spring_topic" ref="topicConsumer1"/>

<jms:listenerdestination="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

publicclass QueueConsumer1 implements MessageListener {

    publicvoid 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

publicclass QueueConsumer2 implements MessageListener {

    publicvoid 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

publicclass TopicConsumer1 implements MessageListener {


 
    publicvoid 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

publicclass TopicConsumer2 implements MessageListener {


 
    publicvoid 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")

publicclass ConsumerTest {


 
    @Test

    publicvoid testConsumerMessage() {

       while (true) {

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

       }

    }

}



1.1.5.8      测试结果

1、运行消费者测试类

2、运行生产者测试类

3、运行结果



mq java工具类_xml_12