假设有如下问题:

  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的更多相关文章

  1. 手把手教你用redis实现一个简单的mq消息队列(java)

    众所周知,消息队列是应用系统中重要的组件,主要解决应用解耦,异步消息,流量削锋等问题,实现高性能,高可用,可伸缩和最终一致性架构.目前使用较多的消息队列有 ActiveMQ,RabbitMQ,Zero ...

  2. RabbitMQ消息队列(一): 简单队列

    1. 示例选用python的pika模块进行测试,需要预先安装pika模块: https://pypi.python.org/pypi/pika/0.10.0#downloads 上述地址下载源码,加 ...

  3. .net微软消息队列(msmq)简单案例

    1.首先我们需要安装消息队列服务,它是独立的消息记录的服务,并保存在硬盘文件中. 我们添加名为:DMImgUpload的私有消息队列. 2.定义消息队列的连接字符串建议采用IP: (1)FormatN ...

  4. python 实现多个线程间消息队列传递,一个简单的列子

    #-*-coding:utf8-*-"""Producer and consumer models: 1. There are many producers and co ...

  5. redis消息队列简单应用

    消息队列出现的原因 随着互联网的高速发展,门户网站.视频直播.电商领域等web应用中,高并发.大数据已经成为基本的标识.淘宝双11.京东618.各种抢购.秒杀活动.以及12306的春运抢票等,他们这些 ...

  6. 消息队列_MSMQ(1)简单了解

    MSMQ (微软消息队列)   MSMQ 百度百科 MicroSoft Message Queuing(微软消息队列)是在多个不同的应用之间实现相互通信的一种异步传输模式,相互通信的应用可以分布于同一 ...

  7. redis实现消息队列-java代码实现

    转:https://blog.csdn.net/qq_42175986/article/details/88576849 pom.xml <!-- redis依赖 --> <depe ...

  8. redis(五)---- 简单消息队列

    消息队列一个消息的链表,是一个异步处理的数据处理引擎.不仅能够提高系统的负荷,还能够改善因网络阻塞导致的数据缺失.一般用于邮件发送.手机短信发送,数据表单提交.图片生成.视频转换.日志储存等. red ...

  9. C# 消息队列

    阅读目录 1. 消息队列是什么? 2. 常见的消息队列框架有哪些? 3. MSMQ介绍 4. RabbitMQ介绍 消息队列是什么 简单的理解就是将消息添加一个队列中,使用时在从这个队列中取出来.那么 ...

随机推荐

  1. Spring整合Junit框架

    一.开发环境 eclipse版本:4.6.1 maven版本:3.3.3 junit版本:4.12 spring版本:4.1.5.RELEASE JDK版本:1.8.0_111 二.项目结构 图 三. ...

  2. JavaScript及Java对JSON的相关处理

    JavaScript中JSON字符串与JSON对象的互转及JSON对象的取值: var jsonString = '{"key1":"value1"," ...

  3. java方法的虚分派和方法表

    java:方法的虚分派(virtual dispatch)和方法表(method table) Java方法调用的虚分派 虚分配(Virtual Dispatch) 首先从字节码中对方法的调用说起.J ...

  4. [poj3537]Crosses and Crosses_博弈论

    Crosses and Crosses poj-3537 题目大意:给定一个1*n的网格,每次往格子内填一个$\times$,连续的三个即可获胜. 注释:$1\le n\le 2000$. 想法:我们 ...

  5. P3372 【模板】线段树 1 洛谷

    https://www.luogu.org/problem/show?pid=3372 题目描述 如题,已知一个数列,你需要进行下面两种操作: 1.将某区间每一个数加上x 2.求出某区间每一个数的和 ...

  6. CentOS设置程序开机启动程序/服务的方法(转)

    注意:CentOS 6下基本没什么问题,CentOS 7估计不一定能行. 在CentOS系统下,主要有两种方法设置自己安装的程序开机启动. 1.把启动程序的命令添加到/etc/rc.d/rc.loca ...

  7. ssh连接断开后 shell进程退出

    问题描述:当SSH远程连接到服务器上,然后运行一个服务 ./catalina.sh start,然后把终端开闭(切断SSH连接)之后,发现该服务中断,导致网页无法访问.   解决方法:使用nohup命 ...

  8. [Vue @Component] Place Content in Components with Vue Slots

    Vue's slots enable you to define where content of a component should land when you define the conten ...

  9. Java Map 怎样实现Key 的唯一性?

    大家都知道.在Map和Set不可存在反复元素? 可是对于内部的细节我们并不了解.今天我们就一块来 探讨一下! 1 对于 HashMap  HashSet 他们的底层数据结构的实现是:维护了一张  Ha ...

  10. C++简单版BitSet求解大量数据是否存在莫个数

    #include <iostream> using namespace std; template<int N> class BitSet { public: BitSet() ...