消息队列
来源:互联网 发布:深入分析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中啦。
- 消息队列
- 消息队列
- 消息队列
- 消息队列
- 消息队列
- 消息队列
- 消息队列
- 消息队列
- 消息队列
- 消息队列
- 消息队列
- 消息队列
- 消息队列
- 消息队列
- 消息队列
- 消息队列
- <>消息队列
- 消息队列
- redis面试题总结
- ClassNotFoundException: com.mysql.jdbc.Driver
- freemarker 数字输出中的逗号问题
- ubuntu 同步网络时间
- WCF入门教程(五)配置文件
- 消息队列
- Java8—ConcurrentHashMap分析
- C++ 部分文件不在编辑器中显示
- DDOS攻击最受不了240G高防服务器
- Hello BaiduMap!百度地图Android SDK接入
- 微信小程序调用第三方地图API实现获取输入提示词
- 架构设计八之状态模式
- jDownload.js与.net交互
- Haproxy+Keepalived+MySQL高可用均衡负载部署