打开控制台,选择admin一栏(按照要求填写信息)
为添加的用户,添加新建的Virtual Host权限
p为生产者,生产消息。消息可以为String字符串
红色的为FIFO队列(先进先出)
c为消费者,也就是从队列里面拿取消息
准备依赖
<dependency>
<groupId>com.rabbitmqgroupId>
<artifactId>amqp-clientartifactId>
<version>5.9.0version>
dependency>
编写获取RabbitMQ连接的工具类
public class ConnectUtil {
public static Connection getConnection() throws Exception {
//定义连接工厂
ConnectionFactory factory = new ConnectionFactory();
//设置服务地址
factory.setHost("localhost");
//端口
factory.setPort(5672);
//设置账号信息,用户名、密码、vhost
factory.setVirtualHost("/xiao");
factory.setUsername("xiao");
factory.setPassword("123");
// 通过工程获取连接
Connection connection = factory.newConnection();
return connection;
}
}
编写生产者的代码(生产者的queue_name和消费者的queue_name一致,保证是从一个队列生产或消费消息)
public class Send {
private static final String QUEUE_NAME = "simple_queue";
public static void main(String[] args) throws Exception {
//获得连接
Connection connection = ConnectUtil.getConnection();
//获得管道
Channel channel = connection.createChannel();
//声明队列
channel.queueDeclare(QUEUE_NAME,false,false,false,null);
//设置消息内容
channel.basicPublish("",QUEUE_NAME,null , "hello word!".getBytes());
System.out.println("[send] hello word!");
channel.close();
connection.close();
}
}
编写消费者代码
public class Receive {
private static final String QUEUE_NAME = "simple_queue";
public static void main(String[] args) throws Exception {
//获得连接
Connection connection = ConnectUtil.getConnection();
//获得管道
Channel channel = connection.createChannel();
//声明队列
channel.queueDeclare(QUEUE_NAME,false,false,false,null);
Consumer consumer = new DefaultConsumer(channel) {
@Override
public void handleDelivery(String s, Envelope envelope, AMQP.BasicProperties basicProperties, byte[] bytes) throws IOException {
System.out.println(new String(bytes , "utf-8"));
}
};
// 监听队列,false表示手动返回完成状态,true表示自动
channel.basicConsume(QUEUE_NAME, true, consumer);
}
}
Simple队列是生产者与消费者一对一的关系。在实际开发中,我们经常遇到多个消费者,我们可以想象,生产者发送消息是毫不费力的,然而消费者获取消息通常还需要进行一系列的业务处理,这显然需要一段时间,这时候消息队列可能就会积压很多消息。
所谓轮询分发就是队列会轮流发送消息给消费者。如果现在队列里面有50条消息,那么轮询分发会使两个消费者获得的消息条数一样,每个消费者都可获得25条消息。
生产者代码
public class Send {
private static final String QUEUE_NAME = "work_queue";
public static void main(String[] args) throws Exception {
//获得连接
Connection connection = ConnectUtil.getConnection();
//获得管道
Channel channel = connection.createChannel();
//声明队列
channel.queueDeclare(QUEUE_NAME,false,false,false,null);
for (int i = 0; i < 50; i++) {
String msg = "["+i+"] hello word!";
//设置消息内容
channel.basicPublish("",QUEUE_NAME,null , msg.getBytes());
System.out.println("[send] hello word!");
}
channel.close();
connection.close();
}
}
消费者1号
public class ReceiveOne {
private static final String QUEUE_NAME = "work_queue";
public static void main(String[] args) throws Exception {
//获得连接
Connection connection = ConnectUtil.getConnection();
//获得管道
Channel channel = connection.createChannel();
//声明队列
channel.queueDeclare(QUEUE_NAME,false,false,false,null);
Consumer consumer = new DefaultConsumer(channel) {
@Override
public void handleDelivery(String s, Envelope envelope, AMQP.BasicProperties basicProperties, byte[] bytes) throws IOException {
System.out.println(new String(bytes , "utf-8"));
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
// 监听队列,false表示手动返回完成状态,true表示自动
channel.basicConsume(QUEUE_NAME, true, consumer);
}
}
消费者2号
public class ReceiveTwo {
private static final String QUEUE_NAME = "work_queue";
public static void main(String[] args) throws Exception {
//获得连接
Connection connection = ConnectUtil.getConnection();
//获得管道
Channel channel = connection.createChannel();
//声明队列
channel.queueDeclare(QUEUE_NAME,false,false,false,null);
Consumer consumer = new DefaultConsumer(channel) {
@Override
public void handleDelivery(String s, Envelope envelope, AMQP.BasicProperties basicProperties, byte[] bytes) throws IOException {
System.out.println(new String(bytes , "utf-8"));
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
// 监听队列,false表示手动返回完成状态,true表示自动
channel.basicConsume(QUEUE_NAME, true, consumer);
}
}
先开启两个消费者、在开启生产者
虽然上面的分配法方式也还行,但是有个问题就是:现在的这2个消费者,因为消费能力的不同,所以消费的效率也不同。按照轮询的方式,任务交给了第二个消费者,所以一直在忙个不停。任务交给另一个消费者,则立即完成任务,然后闲得不行。而RabbitMQ则是不了解这些的。这是因为当消息进入队列,RabbitMQ就会分派消息。它不看消费者为应答的数目,只是盲目的将消息发给轮询指定的消费者。
生产者代码
public class Send {
private static final String QUEUE_NAME = "work_queue";
public static void main(String[] args) throws Exception {
//获得连接
Connection connection = ConnectUtil.getConnection();
//获得管道
Channel channel = connection.createChannel();
//声明队列
channel.queueDeclare(QUEUE_NAME,false,false,false,null);
for (int i = 0; i < 50; i++) {
String msg = "["+i+"] hello word!";
//设置消息内容
channel.basicPublish("",QUEUE_NAME,null , msg.getBytes());
System.out.println("[send] hello word!");
}
channel.close();
connection.close();
}
}
消费者1号
public class ReceiveOne {
private static final String QUEUE_NAME = "work_queue";
public static void main(String[] args) throws Exception {
//获得连接
Connection connection = ConnectUtil.getConnection();
//获得管道
final Channel channel = connection.createChannel();
//声明队列
channel.queueDeclare(QUEUE_NAME,false,false,false,null);
//保证一次只接受一个消息,处理完以后在请求下一个
channel.basicQos(1);
Consumer consumer = new DefaultConsumer(channel) {
@Override
public void handleDelivery(String s, Envelope envelope, AMQP.BasicProperties basicProperties, byte[] bytes) throws IOException {
System.out.println(new String(bytes , "utf-8"));
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
channel.basicAck(envelope.getDeliveryTag() , false);
}
}
};
// 监听队列,false表示手动返回完成状态,true表示自动应答 false表示手动应答
channel.basicConsume(QUEUE_NAME, false, consumer);
}
}
消费者2号
public class ReceiveTwo {
private static final String QUEUE_NAME = "work_queue";
public static void main(String[] args) throws Exception {
//获得连接
Connection connection = ConnectUtil.getConnection();
//获得管道
final Channel channel = connection.createChannel();
//声明队列
channel.queueDeclare(QUEUE_NAME,false,false,false,null);
//保证一次只接受一个消息,处理完以后在请求下一个
channel.basicQos(1);
Consumer consumer = new DefaultConsumer(channel) {
@Override
public void handleDelivery(String s, Envelope envelope, AMQP.BasicProperties basicProperties, byte[] bytes) throws IOException {
System.out.println(new String(bytes , "utf-8"));
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
channel.basicAck(envelope.getDeliveryTag() , false);
}
}
};
// 监听队列,false表示手动返回完成状态,true表示自动
channel.basicConsume(QUEUE_NAME, false, consumer);
}
}