消息队列

来源:互联网 发布:深入分析linux内核源码 编辑:程序博客网 时间:2024/06/14 13:40

消息队列的作用是什么?

关于消息队列的使用
这篇文章讲得好好高深,看它就没错了。

搭建ActiveMQ

在没有接触消息队列之前我们一直熟悉请求/响应的模式,但是这种模式一直有很多问题产生,特别是在实际的生产环境中,于是便引入了消息队列这种模式,把所有待执行指令存入消息队列等待程序调用,这种方法的好处在上面那位大牛的文章中也写得十分清楚了。

ActiveMQ是一种消息队列,它是对JMS(Java Message Service)的一种实现,现在常用的消息队列基本就是ActiveMQ和KAFKA了吧。

下载地址:ActiveMQ

进入ActiveMQ官网下载最新版,解压后,进入/bin文件夹有一个64位,一个32位,文件夹里面的activemq.bat双击运行,一般双击开启服务,服务默认被挂在本地61616端口上,如果开启不了很有可能该端口被占用,关于这个问题百度上很多解答,不赘述。

开启成功后,进入消息队列的管理平台,默认密码账号都是admin,进入后点击queue按钮能看到如下界面。

这里可以看到你的ActiveMQ中存在哪些消息队列,有哪些消费者在消费这些队列。点击Browse能看到具体的消息来自哪台主机哪个端口。

好像不用码代码就有了我们的消息队列了,毕竟是别人实现好的。我们要做的是在我们对应的模块上写对应的方法或者接口,它们或负责发送消息到我们的消息队列,或监听消息队列中中是否有待处理的消息。

消息队列的响应模式

叫这个名儿不知对不对,不对别打我。
消息队列有两种响应方式,p2p和发布/订阅。p2p是点对点,即一个生产者对应一个消费者,在队列中的消息一旦被消费就不在存在队列中。发布/订阅是一对多的消费方式,生产者发布的消息被多个模块消费,每个模块获得该消息的一份拷贝,具体在上面大牛文章概念已十分清晰,我就是卖个萌。

消息队列的一个小Demo

JMSProducer代码如下:

package com.icebear.activemq;import javax.jms.Connection;import javax.jms.ConnectionFactory;import javax.jms.Destination;import javax.jms.MessageProducer;import javax.jms.Session;import javax.jms.TextMessage;import org.apache.activemq.ActiveMQConnection;import org.apache.activemq.ActiveMQConnectionFactory;public class JMSProducer {    //默认用户名,admin    private static final String USERNAME = ActiveMQConnection.DEFAULT_USER;    //默认登陆密码,admin    private static final String PASSWORD = ActiveMQConnection.DEFAULT_PASSWORD;    //默认链接,tcp://localhost:61616    private static final String BROKEURL = ActiveMQConnection.DEFAULT_BROKER_URL;    //默认信息条数,1000    private static final int SENDSUM = ActiveMQConnection.DEFAULT_THREAD_POOL_SIZE;    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 = (Connection) connectionFactory.createConnection();            //开始连接            connection.start();            //创建session            session = connection.createSession(true, Session.AUTO_ACKNOWLEDGE);            //目的地,我们的消息具体发送到哪一个消息队列            destination = session.createQueue("queue");            //创建messageProducer,它需要被指明生产信息到哪一个地方            messageProducer = session.createProducer(destination);            //send message            for(int i=0; i<JMSProducer.SENDSUM; i++){                TextMessage message = session.createTextMessage("JMSProducer 发送消息 " + i);                System.out.println("JMSProducer 发送消息 " + i);                //调用messageProducer的send方法发送消息                messageProducer.send(message);            }            //提交,没有提交的信息发送不会发送出去            session.commit();        }catch(Exception e){        }    }}

总结一下上面的代码,无非是创建了五个对象,connectionFactory,connection,session,destination,messageProducer,这几个对象存在关系如下:

connectionFactory 创建了 connection
connection 创建了 session
session 创建了 destination
session 用 destination 创建了 messageProducer
最后 messageProducer 往destination 里面塞message
大概流程就是这样。

现在看看消费者的代码是如何的。

package com.icebear.activemq;import javax.jms.Connection;import javax.jms.ConnectionFactory;import javax.jms.Destination;import javax.jms.MessageConsumer;import javax.jms.Session;import javax.jms.TextMessage;import org.apache.activemq.ActiveMQConnection;import org.apache.activemq.ActiveMQConnectionFactory;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 = (Connection)connectionFactory.createConnection();            //开启连接            connection.start();            //创建session            session = connection.createSession(true, Session.AUTO_ACKNOWLEDGE);            //创建目的地            destination = session.createQueue("queue");            //创建消费者            messageConsumer = session.createConsumer(destination);            while(true){                TextMessage message = (TextMessage)messageConsumer.receive(100000);                if(message != null){                    System.out.println("接收到这样的消息:" + message.getText());                }else{                    break;                }            }        }catch(Exception e){        }    }}

大体的实现代码和生产者是一样的,这里需要提出几点,首先上面只是实现了p2p模式,实现发布/订阅只要把创建的队列改为createTopic,而且上面的消费方式是同步的,意味着在等待消息到来之前,这个程序是干等什么都不干的,要将其实现成异步需要实现一个监听器,这部分我们在下面讲。

SSM整合JMS

ActiveMQ配置文件如下:

<?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:context="http://www.springframework.org/schema/context"    xmlns:jms="http://www.springframework.org/schema/jms"    xsi:schemaLocation="http://www.springframework.org/schema/beans       http://www.springframework.org/schema/beans/spring-beans-3.0.xsd       http://www.springframework.org/schema/context       http://www.springframework.org/schema/context/spring-context-3.0.xsd      http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd      http://www.springframework.org/schema/jms http://www.springframework.org/schema/jms/spring-jms-3.0.xsd">    <context:component-scan base-package="com.icebear" />    <!-- Spring提供的JMS工具类,它可以进行消息发送、接收等 -->    <bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">        <!-- 这个connectionFactory对应的是我们定义的Spring提供的那个ConnectionFactory对象 -->        <property name="connectionFactory" ref="connectionFactory" />    </bean>    <!-- 真正可以产生Connection的ConnectionFactory,由对应的 JMS服务厂商提供 -->    <bean id="targetConnectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">        <property name="brokerURL" value="tcp://localhost:61616" />    </bean>    <!-- Spring用于管理真正的ConnectionFactory的ConnectionFactory -->    <bean id="connectionFactory"        class="org.springframework.jms.connection.SingleConnectionFactory">        <!-- 目标ConnectionFactory对应真实的可以产生JMS Connection的ConnectionFactory -->        <property name="targetConnectionFactory" ref="targetConnectionFactory" />    </bean>    <!--这个是队列目的地 -->    <bean id="queueDestination" class="org.apache.activemq.command.ActiveMQQueue">        <constructor-arg>            <value>queue</value>        </constructor-arg>    </bean>    <!-- 消息监听器 -->    <bean id="consumerMessageListener"        class="com.icebear.springactivemq.service.impl.ConsumerMessageListener" />    <!-- 消息监听容器 -->    <bean id="jmsContainer"        class="org.springframework.jms.listener.DefaultMessageListenerContainer">        <property name="connectionFactory" ref="connectionFactory" />        <property name="destination" ref="queueDestination" />        <property name="messageListener" ref="consumerMessageListener" />    </bean></beans>  

熟悉了上面程序调用JMS接口,那么这里的整合步骤也相当清晰,它也是在实现我们之前实现的步骤,在这里我们可以看到它创建了一个监听器,监听器的实现如下:

package com.icebear.springactivemq.service.impl;import javax.jms.JMSException;import javax.jms.Message;import javax.jms.MessageListener;import javax.jms.TextMessage;public class ConsumerMessageListener implements MessageListener{    @Override    public void onMessage(Message message) {        TextMessage textMessage = (TextMessage)message;        System.out.println("接收一个纯文本信息");        try {            System.out.println("信息内容:" + textMessage.getText());        } catch (JMSException e) {            // TODO Auto-generated catch block            e.printStackTrace();        }    }}

只要实现了MessageListener接口,重写它的onMessage方法就能获得监听器监听到的所有内容,然后在这里对这些数据进行具体的操作。

生产者跟我们普通的面向接口开发的习惯一样,首先设计一个接口:

package com.icebear.springactivemq.service;import javax.jms.Destination;public interface ProductorService {    public void sendMessage(Destination destiantion, final String message);}

它只有一个方法,就是sendMessage

具体实现如下:

package com.icebear.springactivemq.service.impl;import javax.jms.Destination;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.jms.core.JmsTemplate;import org.springframework.stereotype.Service;import com.icebear.springactivemq.service.ProductorService;@Servicepublic class ProductorServiceImpl implements ProductorService{    @Autowired    private JmsTemplate jmsTemplate;    @Override    public void sendMessage(Destination destination, final String message) {        System.out.println("生产者发送了一个消息");        System.out.println("消息内容:" + message);        jmsTemplate.convertAndSend(destination, message);    }}

任何时候需要向队列推入信息就可以调用这个接口,另一个监听同样队列的模块会在监听到消息的时候执行相应的方法,这样就完全把ActiveMQ整合到SSM中啦。

0 0