消息队列 (2) java实现简单的RabbtMQ
假设有如下问题:
1.如果消费者连接中断,这期间我们应该怎么办?
2.如何做到负载均衡?
3.如何有效的将数据发送到相关的接收者?就是怎么样过滤
4.如何保证消费者收到完整正确的数据
5.如何让优先级高的接收者先收到数据
一、"Hello RabbitMQ"
如图:P代表生产者,C代表消费者,红色部分为消息队列
二、项目开始
1.首先创建一个maven项目,然后导入rabbitMQjar包
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion> <groupId>testRabbit</groupId>
<artifactId>test</artifactId>
<version>1.0-SNAPSHOT</version> <dependencies>
<dependency>
<groupId>com.rabbitmq</groupId>
<artifactId>amqp-client</artifactId>
<version>3.6.5</version>
</dependency>
</dependencies>
</project>
2.创建消费者Producer
public class Producer {
public final static String QUEUE_NAME = "rabbitMQ.test"; public static void main(String[] args) throws IOException, TimeoutException { //创建连接工厂
ConnectionFactory factory = new ConnectionFactory(); //设置RabbitMQ相关信息
factory.setHost("localhost"); //创建一个新的连接
Connection connection = factory.newConnection();
//创建一个通道
Channel channel = connection.createChannel();
//声明一个队列
channel.queueDeclare(QUEUE_NAME,false,false,false,null);
//发送消息到队列中
String message = "hello rabbitMQ";
channel.basicPublish("",QUEUE_NAME,null,message.getBytes("UTF-8"));
System.out.println("Producer Send : " + message); //关闭通道和连接
channel.close();
connection.close();
}
}
queueDeclare第一个参数表示队列名称,第二个参数为是否持久化(true表示是,队列将在服务器重启时生存),第三个参数为是否独占队列(创建者可以使用的私有队列,断开后自动删除),第四个参数为当所有消费者客户端连接断开时是否自动删除队列,第五个参数为队列的其他参数。
basicPublish第一个参数为交换机名称,第二个参数为队列映射的路由key,第三个参数为消息的其他属性,第四个参数为发送消息的主体。
3.创建消费者
import com.rabbitmq.client.*; import java.io.IOException;
import java.util.concurrent.TimeoutException; public class Customer {
public final static String QUEUE_NAME = "rabbitMQ.test"; public static void main(String[] args) throws IOException, TimeoutException {
//创建连接工厂
ConnectionFactory factory = new ConnectionFactory();
//设置RabbitMQ地址
factory.setHost("localhost");
//创建一个新的连接
Connection connection = factory.newConnection();
//创建一个通道
Channel channel = connection.createChannel();
//声明要关注的队列
channel.queueDeclare(QUEUE_NAME,false,false,false,null);
System.out.println("客户端等待接受消息"); //DefaultConsumer类实现了Consumer接口,通过传入一个频道,告诉服务器我们需要哪个频道的信息,如果频道中有消息,就会执行回调函数handleDelivery
Consumer comsumer = new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
String message = new String (body,"UTF-8");
System.out.println("客户端接收:"+message);
}
}; //自动回答队列应答 -- RabbitMQ中的消息确认机制
channel.basicConsume(QUEUE_NAME,true,comsumer); }
}
该方法用于获取生产者发送的消息,其中envelope主要存放生产者相关的信息(比如交换机、路由key等)body是消息实体。
运行结果如下:
三、实现任务分发
一个队列的优点就是很容易处理并行化的工作能力,但是如果我们积累了大量的工作,我们就需要更多的工作者来处理,这样就需要采用分布机制了。
新建一个生产者NewTask
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.MessageProperties; import java.io.IOException;
import java.util.concurrent.TimeoutException; public class NewTask {
public final static String TASK_QUEUE_NAME = "task_queue"; public static void main(String [] args) throws IOException, TimeoutException {
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("localhost");
Connection connection = factory.newConnection();
Channel channel = connection.createChannel();
channel.queueDeclare(TASK_QUEUE_NAME,true,false,false,null); //分发消息
for(int i = 0;i<10;i++){
String message = "hello RabbitMQ "+ i;
channel.basicPublish("",TASK_QUEUE_NAME, MessageProperties.PERSISTENT_TEXT_PLAIN,message.getBytes());
System.out.println("NewTask send :" + message);
} channel.close();
connection.close(); }
}
然后创建2个工作者work1和work2代码一样
import com.rabbitmq.client.*; import java.io.IOException;
import java.util.concurrent.TimeoutException; public class Work1 {
private static final String TASK_QUEUE_NAME = "task_queue"; public static void main(String[] args) throws IOException, TimeoutException { final ConnectionFactory factory = new ConnectionFactory();
factory.setHost("localhost");
Connection connection = factory.newConnection();
final Channel channel = connection.createChannel(); channel.queueDeclare(TASK_QUEUE_NAME,true,false,false,null);
System.out.println("Work1 等待接受消息"); //每次从队列获取的数量
channel.basicQos(1); final Consumer consumer = new DefaultConsumer(channel){ public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
String message = new String(body,"UTF-8");
System.out.println("Worker1 接受到消息:"+message);
try{
//throw new Exception();
doWork(message);
}catch (Exception ex){
channel.abort();
}finally {
System.out.println("Work1 完成了");
channel.basicAck(envelope.getDeliveryTag(),false);
}
}
}; boolean autoAck=false;
//消息消费完成确认
channel.basicConsume(TASK_QUEUE_NAME,autoAck,consumer); }
private static void doWork(String task) {
try {
Thread.sleep(1000); // 暂停1秒钟
} catch (InterruptedException _ignored) {
Thread.currentThread().interrupt();
}
}
}
channel.basicQos(1);保证一次只分发一个,autoAck是否自动回复,如果为true的话,每次生产者只要发送信息就会从内存中删除,那么如果消费者程序异常退出,那么就无法获取数据,我们当时不希望出现这样的情况,所以才去手动回复,每当消费者收到并处理信息然后在通知生产者,最后从队列中删除这条信息。如果消费者异常退出,如果还有其他消费者,那么就会把队列中的消息发送给其他消费者,如果没有,等消费者启动时候再次发送。
两个都不抛出异常时:
其中一个设置为异常时,会把消息都发送给另一个正常的。等待异常的程序重启后,才会继续给它发送。
消息队列 (2) java实现简单的RabbtMQ的更多相关文章
- 手把手教你用redis实现一个简单的mq消息队列(java)
众所周知,消息队列是应用系统中重要的组件,主要解决应用解耦,异步消息,流量削锋等问题,实现高性能,高可用,可伸缩和最终一致性架构.目前使用较多的消息队列有 ActiveMQ,RabbitMQ,Zero ...
- RabbitMQ消息队列(一): 简单队列
1. 示例选用python的pika模块进行测试,需要预先安装pika模块: https://pypi.python.org/pypi/pika/0.10.0#downloads 上述地址下载源码,加 ...
- .net微软消息队列(msmq)简单案例
1.首先我们需要安装消息队列服务,它是独立的消息记录的服务,并保存在硬盘文件中. 我们添加名为:DMImgUpload的私有消息队列. 2.定义消息队列的连接字符串建议采用IP: (1)FormatN ...
- python 实现多个线程间消息队列传递,一个简单的列子
#-*-coding:utf8-*-"""Producer and consumer models: 1. There are many producers and co ...
- redis消息队列简单应用
消息队列出现的原因 随着互联网的高速发展,门户网站.视频直播.电商领域等web应用中,高并发.大数据已经成为基本的标识.淘宝双11.京东618.各种抢购.秒杀活动.以及12306的春运抢票等,他们这些 ...
- 消息队列_MSMQ(1)简单了解
MSMQ (微软消息队列) MSMQ 百度百科 MicroSoft Message Queuing(微软消息队列)是在多个不同的应用之间实现相互通信的一种异步传输模式,相互通信的应用可以分布于同一 ...
- redis实现消息队列-java代码实现
转:https://blog.csdn.net/qq_42175986/article/details/88576849 pom.xml <!-- redis依赖 --> <depe ...
- redis(五)---- 简单消息队列
消息队列一个消息的链表,是一个异步处理的数据处理引擎.不仅能够提高系统的负荷,还能够改善因网络阻塞导致的数据缺失.一般用于邮件发送.手机短信发送,数据表单提交.图片生成.视频转换.日志储存等. red ...
- C# 消息队列
阅读目录 1. 消息队列是什么? 2. 常见的消息队列框架有哪些? 3. MSMQ介绍 4. RabbitMQ介绍 消息队列是什么 简单的理解就是将消息添加一个队列中,使用时在从这个队列中取出来.那么 ...
随机推荐
- L2-011. 玩转二叉树(不建树)
L2-011. 玩转二叉树 给定一棵二叉树的中序遍历和前序遍历,请你先将树做个镜面反转,再输出反转后的层序遍历的序列.所谓镜面反转,是指将所有非叶结点的左右孩子对换.这里假设键值都是互不相等的正整 ...
- Spring常用注解总结 hibernate注解
1.@Resource和@Autowired @Resource和@Autowired功能一样在容器查找匹配的Bean @Autowired默认按照byType方式进行bean匹配,@Resource ...
- Leetcode 51.N后问题
N后问题 n 皇后问题研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击. 上图为 8 皇后问题的一种解法. 给定一个整数 n,返回所有不同的 n 皇后问题的解决方案. ...
- noip模拟赛 毁灭
题目描述 YJC决定对入侵C国的W国军队发动毁灭性打击.将C国看成一个平面直角坐标系,W国一共有n^2个人进入了C国境内,在每一个(x,y)(1≤x,y≤n)上都有恰好一个W国人.YJC决定使用m颗核 ...
- alpha版出炉,实现win2008 service的session 0穿透
指定用户名,拿最小session,实现和用户ui交互. 这样,搞windows的自动化部署,就可以向前一大步啦. 比以前用psexec要用户名密码,指定session要先进多啦. 安全保密性也提高了. ...
- Spring Cloud ZooKeeper集成Feign的坑1,错误:Consider defining a bean of type 'org.springframework.web.client.RestTemplate' in your configuration.
错误如下: ERROR 31473 --- [ main] o.s.b.d.LoggingFailureAnalysisReporter : *************************** A ...
- 15、Java并发性和多线程-线程通讯
以下内容转自http://ifeve.com/thread-signaling/: 线程通信的目标是使线程间能够互相发送信号.另一方面,线程通信使线程能够等待其他线程的信号. 例如,线程B可以等待线程 ...
- SVM学习(续)核函数 & 松弛变量和惩罚因子
SVM的文章可以看:http://www.cnblogs.com/charlesblc/p/6193867.html 有写的最好的文章来自:http://www.blogjava.net/zhenan ...
- android混合动画实现
在android开发,我们会常常使用到动画,可是简单的一种动画(如旋转.缩放.渐变.位移等)有时候并不能满足我们项目的要求,这时候就须要运用到混合动画.那么在安卓中是怎样实现一个炫酷的混合动画,以下是 ...
- JavaScript的原生引用类型
引用类型是一种数据结构,用于将数据和功能组织在一起,也常称做类.ECMAScript从技术上说是一门面向对象的语言.但它不具备传统的面向对象语言所支持的类和接口等基本结构. Object类型 大多数引 ...