1、使用RabbitMQ原生Java客户端进行消息通信
首先比较推荐使用Maven项目来学习,JDK版本在1.8及以上版本。要使用RabbitMQ客户端需要引用amqp-client-5.0.0.jar和slf4j-api-1.6.1.jar两个依赖包
第一步首选添加以下依赖
<dependency>
<groupId>com.rabbitmq</groupId>
<artifactId>amqp-client</artifactId>
<version>5.0.0</version>
</dependency>
2.Direct交换器的基本使用
生产者
生产者主要就是用于消息的生产,并且将消息通过交换器,将消息由路由键和队列的匹配关系发送到指定的队列上的过程。
package com.kevin.task.exchange.direct;
import com.rabbitmq.client.BuiltinExchangeType;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
/**
* 描述:Direct交换器生产者<br/>
* 创建人: Kevin Lea <br/>
* 创建时间: 2019-9-22 14:24<br/>
* 版本:1.0
*/
public class DirectProduct {
public final static String EXCHANGE_NAME = "direct_exchange";
public static void main(String[] args) throws IOException,TimeoutException {
//1.创建连接,连接到RabbitMQ
ConnectionFactory connectionFactory = new ConnectionFactory();
//2.设置连接地址,和端口,默认是5672
connectionFactory.setHost("172.0.0.1");
connectionFactory.setPort(5672);
connectionFactory.setUsername("test");
connectionFactory.setPassword("test");
connectionFactory.setVirtualHost("myhost");
//3.创建连接
Connection connection = connectionFactory.newConnection();
//4.创建信道
Channel channel = connection.createChannel();
//5.在信道中去设置交换器
channel.exchangeDeclare(EXCHANGE_NAME, BuiltinExchangeType.DIRECT);
//6.申明队列,可以在消费者地方申明,也可以在生产者地方申明,这里采用在消费者地方申明
//7.申明路由键
String[] routeKeys = {"apple","huawei","xiaomi"};
for(int i=0;i<routeKeys.length;i++){
String routeKey = routeKeys[i%3];
String msg = "I like " + routeKey + (i+1);
channel.basicPublish(EXCHANGE_NAME,routeKey,null,msg.getBytes());
System.out.println("Send:" + routeKey + ":" + msg);
}
channel.close();
connection.close();
}
}
消费者
Direct交换器有四种使用方法:1.生产者消费者一般用法;2.队列和交换器的多重绑定;3.一个连接多个信道;4.一个队列多个消费者。那下面我们看看这四种消费者是如何实现的。
- 1.生产者消费者一般用法
package com.kevin.task.exchange.direct;
import com.rabbitmq.client.*;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
/**
* 描述:一般使用方法<br/>
* 创建人: Kevin Lea <br/>
* 创建时间: 2019-9-22 14:42<br/>
* 版本:1.0
*/
public class NormalConsumer {
public static void main(String[] args) throws IOException,TimeoutException {
//1.创建连接,连接到RabbitMQ
ConnectionFactory connectionFactory = new ConnectionFactory();
//2.设置连接地址,和端口,默认是5672
connectionFactory.setHost("172.0.0.1");
connectionFactory.setPort(5672);
connectionFactory.setUsername("test");
connectionFactory.setPassword("test");
connectionFactory.setVirtualHost("myhost");
//3.创建连接
Connection connection = connectionFactory.newConnection();
//4.创建信道
Channel channel = connection.createChannel();
//5.在信道中去设置交换器
channel.exchangeDeclare(DirectProduct.EXCHANGE_NAME, BuiltinExchangeType.DIRECT);
//6.申明队列,之前在生产者地方没有创建的队列在这里创建了
String queueName = "queue-apple";
/**
* 第一个参数:队列名称
* 第二个参数:是否是持久队列
* 第三个参数:是否是独占队列
* 第四个参数:是否自动删除队列
* 第五个参数:队列的其他属性是一个hashmap
*/
channel.queueDeclare(queueName,false,false,false,null);
//7.绑定路由键,这里只绑定apple做测试,其他所有的key不接收
String routeKey = "apple";
channel.queueBind(queueName,DirectProduct.EXCHANGE_NAME,routeKey);
System.out.println("waiting for message......");
//8.申明消费者去消费-回调函数
final Consumer consumer = 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("received:["+envelope.getRoutingKey()+"]" + message);
}
};
//9.消费者正式在一个指定的队列上消费
//第一个参数:队列名称
//第二个参数:是否自动确认
//第三个参数:回调函数
channel.basicConsume(queueName,true,consumer);
}
}
- 2.队列和交换器的多重绑定
package com.kevin.task.exchange.direct;
import com.rabbitmq.client.*;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
/**
* 描述:队列和交换器的多重绑定<br/>
* 创建人: Kevin Lea <br/>
* 创建时间: 2019-9-22 14:42<br/>
* 版本:1.0
*/
public class MultiBindConsumer {
public static void main(String[] args) throws IOException,TimeoutException {
//1.创建连接,连接到RabbitMQ
ConnectionFactory connectionFactory = new ConnectionFactory();
//2.设置连接地址,和端口,默认是5672
connectionFactory.setHost("172.0.0.1");
connectionFactory.setPort(5672);
connectionFactory.setUsername("test");
connectionFactory.setPassword("test");
connectionFactory.setVirtualHost("myhost");
//3.创建连接
Connection connection = connectionFactory.newConnection();
//4.创建信道
Channel channel = connection.createChannel();
//5.在信道中去设置交换器
channel.exchangeDeclare(DirectProduct.EXCHANGE_NAME, BuiltinExchangeType.DIRECT);
//6.申明随机队列
String queueName = channel.queueDeclare().getQueue();
//7.绑定路由键
String[] routeKeys = {"apple","huawei","xiaomi"};
for(String routeKey : routeKeys){
channel.queueBind(queueName,DirectProduct.EXCHANGE_NAME,routeKey);
}
System.out.println("waiting for message......");
//8.申明消费者去消费
final Consumer consumer = 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("received:["+envelope.getRoutingKey()+"]" + message);
}
};
//9.消费者正式在一个指定的队列上消费
channel.basicConsume(queueName,true,consumer);
}
}
- 3.一个连接多个信道
package com.kevin.task.exchange.direct;
import com.rabbitmq.client.*;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
/**
* 描述:一个连接多个信道<br/>
* 创建人: Kevin Lea <br/>
* 创建时间: 2019-9-22 14:42<br/>
* 版本:1.0
*/
public class MultiChannerConsumer {
public static void main(String[] args) throws IOException,TimeoutException {
//1.创建连接,连接到RabbitMQ
ConnectionFactory connectionFactory = new ConnectionFactory();
//2.设置连接地址,和端口,默认是5672
connectionFactory.setHost("172.0.0.1");
connectionFactory.setPort(5672);
connectionFactory.setUsername("test");
connectionFactory.setPassword("test");
connectionFactory.setVirtualHost("myhost");
//3.创建连接
Connection connection = connectionFactory.newConnection();
//创建两个子线程去创建信道,这里创建2个信道,都共同用同一个connection
for(int i=0;i<2;i++){
Thread thread = new Thread(new ConsumerWork(connection));
thread.start();
}
}
/**
* 内部静态类
*/
public static class ConsumerWork implements Runnable{
private final Connection connection;
public ConsumerWork(Connection connection) {
this.connection = connection;
}
public void run() {
try {
//4.创建信道
Channel channel = connection.createChannel();
//5.在信道中去设置交换器
channel.exchangeDeclare(DirectProduct.EXCHANGE_NAME, BuiltinExchangeType.DIRECT);
//6.申明随机队列
String queueName = channel.queueDeclare().getQueue();
//7.绑定路由键
String[] routeKeys = {"apple","huawei","xiaomi"};
for(String routeKey : routeKeys){
channel.queueBind(queueName,DirectProduct.EXCHANGE_NAME,routeKey);
}
//消费者名称,这里用线程的名称作为消费者名称
final String consumerName = Thread.currentThread().getName() + "-all";
System.out.println("["+consumerName+"]waiting for message......");
//8.申明消费者去消费
final Consumer consumer = 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("["+consumerName+"]received:["+envelope.getRoutingKey()+"]" + message);
}
};
//9.消费者正式在一个指定的队列上消费
channel.basicConsume(queueName,true,consumer);
}catch (Exception e){
e.printStackTrace();
}
}
}
}
- 4.一个队列多个消费者。那下面我们看看这四种消费者是如何实现的
package com.kevin.task.exchange.direct;
import com.rabbitmq.client.*;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
/**
* 描述:一个队列多个消费者<br/>
* 创建人: Kevin Lea <br/>
* 创建时间: 2019-9-22 14:42<br/>
* 版本:1.0
*/
public class MultiConsumerOneQueue {
public static void main(String[] args) throws IOException,TimeoutException {
//1.创建连接,连接到RabbitMQ
ConnectionFactory connectionFactory = new ConnectionFactory();
//2.设置连接地址,和端口,默认是5672
connectionFactory.setHost("172.0.0.1");
connectionFactory.setPort(5672);
connectionFactory.setUsername("test");
connectionFactory.setPassword("test");
connectionFactory.setVirtualHost("myhost");
//3.创建连接
Connection connection = connectionFactory.newConnection();
//申明一个唯一的队列名称
String queueName = "OnlyQueue";
//创建3个任务
for(int i=0;i<3;i++){
Thread thread = new Thread(new ConsumerWork(connection,queueName));
thread.start();
}
}
/**
* 内部静态类,一个连接,一个队列,多个消费者
*/
public static class ConsumerWork implements Runnable{
private final Connection connection;
private final String queueName;
public ConsumerWork(Connection connection,String queueName) {
this.connection = connection;
this.queueName = queueName;
}
public void run() {
try {
//4.创建信道
Channel channel = connection.createChannel();
//5.在信道中去设置交换器
channel.exchangeDeclare(DirectProduct.EXCHANGE_NAME, BuiltinExchangeType.DIRECT);
/**
* 第一个参数:队列名称
* 第二个参数:是否是持久队列
* 第三个参数:是否是独占队列
* 第四个参数:是否自动删除队列
* 第五个参数:队列的其他属性是一个hashmap
*/
channel.queueDeclare(queueName,false,false,false,null);
//7.绑定路由键
String[] routeKeys = {"apple","huawei","xiaomi"};
for(String routeKey : routeKeys){
channel.queueBind(queueName,DirectProduct.EXCHANGE_NAME,routeKey);
}
final String consumerName = Thread.currentThread().getName() + "-all";
System.out.println("["+consumerName+"]waiting for message......");
//8.申明消费者去消费
final Consumer consumer = 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("["+consumerName+"]received:["+envelope.getRoutingKey()+"]" + message);
}
};
//9.消费者正式在一个指定的队列上消费
channel.basicConsume(queueName,true,consumer);
}catch (Exception e){
e.printStackTrace();
}
}
}
}
3.Fanout交换器的基本使用
Fanout其实就是一个广播模式,在这里消费者其实绑定什么路由键都是无所谓的,生产者生产的消息他们其实都是可以收的到的。
生产者
package com.kevin.task.exchange.fanout;
import com.rabbitmq.client.BuiltinExchangeType;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
/**
* 描述:Fanout生产者,除了交换器类型不一样外,其他基本上是一样的<br/>
* 创建人: Kevin Lea <br/>
* 创建时间: 2019-9-22 14:24<br/>
* 版本:1.0
*/
public class FanoutProduct {
public final static String EXCHANGE_NAME = "fanout_exchange";
public static void main(String[] args) throws IOException,TimeoutException {
//1.创建连接,连接到RabbitMQ
ConnectionFactory connectionFactory = new ConnectionFactory();
//2.设置连接地址,和端口,默认是5672
connectionFactory.setHost("172.0.0.1");
connectionFactory.setPort(5672);
connectionFactory.setUsername("test");
connectionFactory.setPassword("test");
connectionFactory.setVirtualHost("myhost");
//3.创建连接
Connection connection = connectionFactory.newConnection();
//4.创建信道
Channel channel = connection.createChannel();
//5.在信道中去设置交换器,这里指定FANOUT类型
channel.exchangeDeclare(EXCHANGE_NAME, BuiltinExchangeType.FANOUT);
//6.申明队列,可以在消费者地方申明,也可以在生产者地方申明,这里采用在消费者地方申明
//7.申明路由键
String[] routeKeys = {"apple","huawei","xiaomi"};
for(int i=0;i<routeKeys.length;i++){
String routeKey = routeKeys[i%3];
String msg = "I like " + routeKey + (i+1);
channel.basicPublish(EXCHANGE_NAME,routeKey,null,msg.getBytes());
System.out.println("Send:" + routeKey + ":" + msg);
}
channel.close();
connection.close();
}
}
消费者
这里可以启动多个下面的想消费者。用于监听消息广播,可以把每个消费者的绑定的路由键给设置成不同的,或者设置成生产者没有的路由键也可以。主要测试消费者是否能够全部收到消息。
package com.kevin.task.exchange.fanout;
import com.kevin.task.exchange.direct.DirectProduct;
import com.rabbitmq.client.*;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
/**
* 描述:FANOUT方式的消费者<br/>
* 创建人: Kevin Lea <br/>
* 创建时间: 2019-9-22 14:42<br/>
* 版本:1.0
*/
public class Consumer1 {
public static void main(String[] args) throws IOException,TimeoutException {
//1.创建连接,连接到RabbitMQ
ConnectionFactory connectionFactory = new ConnectionFactory();
//2.设置连接地址,和端口,默认是5672
connectionFactory.setHost("172.0.0.1");
connectionFactory.setPort(5672);
connectionFactory.setUsername("test");
connectionFactory.setPassword("test");
connectionFactory.setVirtualHost("myhost");
//3.创建连接
Connection connection = connectionFactory.newConnection();
//4.创建信道
Channel channel = connection.createChannel();
//5.在信道中去设置交换器
channel.exchangeDeclare(FanoutProduct.EXCHANGE_NAME, BuiltinExchangeType.FANOUT);
//6.申明队列
String queueName = channel.queueDeclare().getQueue();
//7.绑定路由键,这里只绑定apple做测试
String routeKey = "all";
channel.queueBind(queueName,FanoutProduct.EXCHANGE_NAME,routeKey);
System.out.println("waiting for message......");
//8.申明消费者去消费
final Consumer consumer = 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("received:["+envelope.getRoutingKey()+"]" + message);
}
};
//9.消费者正式在一个指定的队列上消费
channel.basicConsume(queueName,true,consumer);
}
}
4.Topic交换器的基本使用
Topic交换器主要呢也就是绑定路由键有很多姿势,路由键一般是有几个段组成每个段之间呢用点号分割(例如a.b.c),这里主要有两种方式做路由键匹配一个是#一个是*。
#匹配一个或者多个(例如a.#)
*匹配一个(a.*.c)
生产者
package com.kevin.task.exchange.topic;
import com.rabbitmq.client.BuiltinExchangeType;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
/**
* 描述:Topic交换器的基本使用-生产者<br/>
* 创建人: Kevin Lea <br/>
* 创建时间: 2019-9-22 14:24<br/>
* 版本:1.0
*/
public class TopicProduct {
public final static String EXCHANGE_NAME = "topic_exchange";
public static void main(String[] args) throws IOException,TimeoutException {
//1.创建连接,连接到RabbitMQ
ConnectionFactory connectionFactory = new ConnectionFactory();
//2.设置连接地址,和端口,默认是5672
connectionFactory.setHost("172.0.0.1");
connectionFactory.setPort(5672);
connectionFactory.setUsername("test");
connectionFactory.setPassword("test");
connectionFactory.setVirtualHost("myhost");
//3.创建连接
Connection connection = connectionFactory.newConnection();
//4.创建信道
Channel channel = connection.createChannel();
//5.在信道中去设置交换器
channel.exchangeDeclare(EXCHANGE_NAME, BuiltinExchangeType.TOPIC);
//6.申明队列,可以在消费者地方申明,也可以在生产者地方申明,这里采用在消费者地方申明
//7.申明路由键
String[] phones = {"apple","huawei","xiaomi"};
for(int i=0;i<phones.length;i++){
String[] products = {"iphone","MATE","ReadMi"};
for(int j=0;j<products.length;j++){
String[] versions = {"11","20","9"};
for(int k=0;k<versions.length;k++){
String routeKey = phones[i%3] + "." + products[j%3] + "." + versions[k%3];
String msg = "I like " + routeKey + (i+1);
channel.basicPublish(EXCHANGE_NAME,routeKey,null,msg.getBytes());
System.out.println("Send:" + routeKey + ":" + msg);
}
}
}
channel.close();
connection.close();
}
}
消费者
package com.kevin.task.exchange.topic;
import com.rabbitmq.client.*;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
/**
* 描述:Topic交换器的基本使用-消费者<br/>
* 创建人: Kevin Lea <br/>
* 创建时间: 2019-9-22 14:42<br/>
* 版本:1.0
*/
public class ALL_Consumer {
public static void main(String[] args) throws IOException,TimeoutException {
//1.创建连接,连接到RabbitMQ
ConnectionFactory connectionFactory = new ConnectionFactory();
//2.设置连接地址,和端口,默认是5672
connectionFactory.setHost("172.0.0.1");
connectionFactory.setPort(5672);
connectionFactory.setUsername("test");
connectionFactory.setPassword("test");
connectionFactory.setVirtualHost("myhost");
//3.创建连接
Connection connection = connectionFactory.newConnection();
//4.创建信道
Channel channel = connection.createChannel();
//5.在信道中去设置交换器
channel.exchangeDeclare(TopicProduct.EXCHANGE_NAME, BuiltinExchangeType.TOPIC);
//6.申明队列
String queueName = channel.queueDeclare().getQueue();
//7.绑定路由键,这里只匹配apple开头的消息
String routeKey = "apple.#";
channel.queueBind(queueName,TopicProduct.EXCHANGE_NAME,routeKey);
System.out.println("waiting for message......");
//8.申明消费者去消费
final Consumer consumer = 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("received:["+envelope.getRoutingKey()+"]" + message);
}
};
//9.消费者正式在一个指定的队列上消费
channel.basicConsume(queueName,true,consumer);
}
}