消息队列

消息队列的作用是什么?

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

搭建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;

@Service
public 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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值