1.RabbitMQ安装
RabbitMQ官网:https://www.rabbitmq.com
1.rabbitmq对应erlang版本
2.下载rabbitmq和erlang
erlang下载地址:https://www.erlang.org/downloads/22.0
rabbitmq下载地址:https://www.rabbitmq.com/install-windows.html
3.安装erlang
一直点下一步,具体步骤如下
4.安装rabbitmq
一直点下一步
安装完成
在win10中找到
这里会出现启动、停止、重新安装等
5.启动管理工具
安装完之后我们得验证一下安装是否成功,那么接下来如果你能成功启动并且登录,那么恭喜你安装成功,否则你得重新安装。
1.点击
2.输入命令:。
rabbitmq-plugins enable rabbitmq_management
6.打开浏览器控制台
http://localhost:15672/
默认账号guest guest
如果不能访问,
文件夹为隐藏需要再文件夹选项中把隐藏文件夹打开显示。
C:\Users\wangleilAppData\Roaming\RabbitMQ\db里面的数据删除再次安装一下Rabbitmq.exe中
然后执行。
添加用户
- 用户界面
- virtual hosts管理
virtual hosts相当于mysql的db
一般以/开头
我们得对用户进行授权
2.java操作队列
新建项目:myrabbitmq
- pom文件
<?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>com.blj</groupId>
<artifactId>myrabbitmq</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>com.rabbitmq</groupId>
<artifactId>amqp-client</artifactId>
<version>4.0.2</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.10</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.5</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
</dependency>
</dependencies>
</project>
1.简单队列:
P:消息的生产者。
红色的:队列。
C:消费者。
3个对象:生产者 队列 消费者。
1.2.获取MQ连接
package com.blj.rabbitmq.util;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
public class ConnectionUtils {
/**
* 获取MQ链接
*
* @return
*/
public static Connection getConnetion() throws IOException, TimeoutException {
ConnectionFactory factory = new ConnectionFactory();
//设置服务地址
factory.setHost("127.0.0.1");
//设置端口号 AMQP 5672
factory.setPort(5672);
//VirtualHost
factory.setVirtualHost("/test");
//用户名
factory.setUsername("root");
//密码
factory.setPassword("root1234");
return factory.newConnection();
}
}
- 1.3生产者生产消息
package com.blj.rabbitmq.simple;
import com.blj.rabbitmq.util.ConnectionUtils;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
public class Send {
public static final String QUEUE_NAME="test_simple_queue";
public static void main(String[] args) throws IOException, TimeoutException {
//获取一个链接
Connection connetion = ConnectionUtils.getConnetion();
//从链接中获取一个通道
Channel channel = connetion.createChannel();
//创建队列声明
channel.queueDeclare(QUEUE_NAME,false,false,false,null);
String msg="hello simple!";
channel.basicPublish("",QUEUE_NAME,null,msg.getBytes());
System.out.println("-- send msg"+msg);
channel.close();
connetion.close();
}
}
- 1.4消费者接受消息
package com.blj.rabbitmq.simple;
import com.blj.rabbitmq.util.ConnectionUtils;
import com.rabbitmq.client.*;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
/**
* 消费者
*
* @author BaiLiJun on 2019/10/24 0024
*/
public class Recv {
public static final String QUEUE_NAME = "test_simple_queue";
public static void main(String[] args) throws Exception {
//获取链接
Connection connetion = ConnectionUtils.getConnetion();
//创建频道
Channel channel = connetion.createChannel();
//创建队列声明
channel.queueDeclare(QUEUE_NAME, false, false, false, null);
//定义消费者
DefaultConsumer consumer = new DefaultConsumer(channel) {
//获取到达消息
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
String msg = new String(body, "utf-8");
System.out.println("new api recv msg = " + msg);
}
};
//监听队列
channel.basicConsume(QUEUE_NAME, true, consumer);
}
private static void oldApi() throws IOException, TimeoutException, InterruptedException {
//获取链接
Connection connetion = ConnectionUtils.getConnetion();
//创建频道
Channel channel = connetion.createChannel();
//定义队列消费者
QueueingConsumer consumer = new QueueingConsumer(channel);
//监听队列
channel.basicConsume(QUEUE_NAME, true, consumer);
while (true) {
QueueingConsumer.Delivery delivery = consumer.nextDelivery();
String msg = new String(delivery.getBody());
System.out.println("old api Recv msg = " + msg);
}
}
}
- 1.5简单队列的不足
耦合性高,生产者一一对应消费者(如果我想有多个消费者消费队列中消息,这时候就不行了)队列名变更这时候得同时变更
2.work queue 工作队列
为什么会出现工作队列。
Simple队列是一一对应的,而且我们实际开发生产者发送消息是毫不费力的,而消费者一般
是要跟业务相结合的.消费者接收到消息之后就需要处理可能需要花费时间,这时候队列就
会积压了很多消息
- 2.2生产者
package com.blj.rabbitmq.work;
import com.blj.rabbitmq.util.ConnectionUtils;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
/**
* 生产者
*
* @author BaiLiJun on 2019/10/26 0026
*/
public class Send {
public static final String QUEUE_NAME = "test_work_queue";
public static void main(String[] args) throws Exception {
//获取连接
Connection connetion = ConnectionUtils.getConnetion();
//建立通道
Channel channel = connetion.createChannel();
//队列声明
channel.queueDeclare(QUEUE_NAME, false, false, false, null);
for (int i = 0; i < 50; i++) {
String msg = "hello" + i;
System.out.println("Send msg = " + msg);
//发布消息
channel.basicPublish("", QUEUE_NAME, null, msg.getBytes());
Thread.sleep(i*20);
}
channel.close();
connetion.close();
}
}
- 2.3消费者1
package com.blj.rabbitmq.work;
import com.blj.rabbitmq.util.ConnectionUtils;
import com.rabbitmq.client.*;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
/**
* 消费者1
*
* @author BaiLiJun on 2019/10/26 0026
*/
public class Recv1 {
public static final String QUEUE_NAME = "test_work_queue";
public static void main(String[] args) throws Exception {
//获取连接
Connection connetion = ConnectionUtils.getConnetion();
//建立通道
Channel channel = connetion.createChannel();
//队列声明
channel.queueDeclare(QUEUE_NAME, false, false, false, null);
//定义消费者
DefaultConsumer consumer = new DefaultConsumer(channel) {
//消息到达,触发这个方法
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
String msg = new String(body, "utf-8");
System.out.println("[1] Recv msg = " + msg);
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
System.out.println("[1] done");
}
}
};
//监听队列
boolean autoAck=true;
channel.basicConsume(QUEUE_NAME,autoAck,consumer);
}
}
- 2.3消费者2
package com.blj.rabbitmq.work;
import com.blj.rabbitmq.util.ConnectionUtils;
import com.rabbitmq.client.*;
import java.io.IOException;
/**
* 消费者2
*
* @author BaiLiJun on 2019/10/26 0026
*/
public class Recv2 {
public static final String QUEUE_NAME = "test_work_queue";
public static void main(String[] args) throws Exception {
//获取连接
Connection connetion = ConnectionUtils.getConnetion();
//建立通道
Channel channel = connetion.createChannel();
//队列声明
channel.queueDeclare(QUEUE_NAME, false, false, false, null);
//定义消费者
DefaultConsumer consumer = new DefaultConsumer(channel) {
//消息到达,触发这个方法
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
String msg = new String(body, "utf-8");
System.out.println("[2] Recv msg = " + msg);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
System.out.println("[2] done");
}
}
};
//监听队列
boolean autoAck=true;
channel.basicConsume(QUEUE_NAME,autoAck,consumer);
}
}
- 2.4现象
消费者1和消费者2处理的消息是一样的。.
消费者1:偶数。
消费者2:奇数,
这种方式叫做轮询分发(round-robin) 结果就是不管谁忙或者谁清闲都不会多给一个消息
任务消息总是你一个我一个
3.公平分发fair dipatch
- 生产者
package com.blj.rabbitmq.workfair;
import com.blj.rabbitmq.util.ConnectionUtils;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
/**
* 生产者
*
* @author BaiLiJun on 2019/10/26 0026
*/
public class Send {
public static final String QUEUE_NAME = "test_work_queue";
public static void main(String[] args) throws Exception {
//获取连接
Connection connetion = ConnectionUtils.getConnetion();
//建立通道
Channel channel = connetion.createChannel();
//队列声明
channel.queueDeclare(QUEUE_NAME, false, false, false, null);
/**
* 每个消费者发送确认消息之前,消息队列不发送下一条消息到消费者,一次只处理一条数据
*
* 限制发送给同一个消费者不得超过一条消息
*/
int prefetchCount=1;
channel.basicQos(prefetchCount);
for (int i = 0; i < 50; i++) {
String msg = "hello" + i;
System.out.println("Send msg = " + msg);
//发布消息
channel.basicPublish("", QUEUE_NAME, null, msg.getBytes());
Thread.sleep(i*5);
}
channel.close();
connetion.close();
}
}
- 消费者1
package com.blj.rabbitmq.workfair;
import com.blj.rabbitmq.util.ConnectionUtils;
import com.rabbitmq.client.*;
import java.io.IOException;
/**
* 消费者1
*
* @author BaiLiJun on 2019/10/26 0026
*/
public class Recv1 {
public static final String QUEUE_NAME = "test_work_queue";
public static void main(String[] args) throws Exception {
//获取连接
Connection connetion = ConnectionUtils.getConnetion();
//建立通道
final Channel channel = connetion.createChannel();
//队列声明
channel.queueDeclare(QUEUE_NAME, false, false, false, null);
//保证一次只发送一个
channel.basicQos(1);
//定义消费者
DefaultConsumer consumer = new DefaultConsumer(channel) {
//消息到达,触发这个方法
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
String msg = new String(body, "utf-8");
System.out.println("[1] Recv msg = " + msg);
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
System.out.println("[1] done");
//手动回执
channel.basicAck(envelope.getDeliveryTag(), false);
}
}
};
//自动应答改成false
boolean autoAck = false;
//监听队列
channel.basicConsume(QUEUE_NAME, autoAck, consumer);
}
}
- 消费