Rabbitmq的学习分享
文章目录
一、RabbitMq简介
官网对应模式介绍:https://www.rabbitmq.com/getstarted.html
二、Rabbitmq的安装与配置
可以参考这个: https://blog.csdn.net/qq_35332494/article/details/108528524
三、学习工厂模式
1. 简单模式
1.1 步骤分析:
1.2 简单模式分析:
1.3 Java代码进行编写
1.3.1 创建一个Maven工程’
导入ampq的依赖:
<dependencies>
<dependency>
<groupId>com.rabbitmq</groupId>
<artifactId>amqp-client</artifactId>
<version>5.6.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
1.3.2 创建生产者类
Producer_HelloWorld.java
package com.cy.producer;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
/**
* @author cy
* @create 2020-09-10-11:00
* @Description 发送消息
*/
public class Producer_HelloWorld {
public static void main(String[] args) throws Exception{
//1.创建连接工厂
ConnectionFactory factory = new ConnectionFactory();
//2.设置参数
factory.setHost("********");//ip 不设置默认为localhost
factory.setPort(5672); //端口 默认5672
factory.setVirtualHost("**"); //虚拟机 默认是 /
factory.setUsername("***");//用户名 默认guest
factory.setPassword("****"); //密码 默认是 guest
//3.创建连接 Connection
Connection connection = factory.newConnection();
//4.创建Channel
Channel channel = connection.createChannel();
//5.创建队列Queue
/*queueDeclare(String queue, boolean durable, boolean exclusive, boolean autoDelete, Map<String, Object> arguments)
queue: 队列名称
durable: 是否持久化,当mq重启之后还在
exclusive:
*是否独占,只能有一个消费者监听这队列
*当Connection关闭时,是否删除队列
autoDelete:是否自动删除,当没有Consumer时,自动删除掉
arguments:参数
*/
//如果没没有一个叫Hello_World的队列,则会创建
channel.queueDeclare("Hello_Word", true, false, false, null);
//6.发送消息
/*basicPublish(String exchange, String routingKey, BasicProperties props, byte[] body)
exchange: 交换机名称,简单模式下交换机会默认使用的 ""
routingKey: 路由名称
props: 配置信息
body: 发送的消息数据
*/
String body = "Hello rabbitmq~~~";
channel.basicPublish("", "Hello_Word", null, body.getBytes());
//7.释放资源
channel.close();
connection.close();
}
}
运行之后,查看:
没有错误,登录rabbitmq管理界面查看队列:
创建成功,并且Ready列存在一条消息.
1.3.3 创建消费者类
Consumer_HelloWorld.java
package com.cy.consumer;
import com.rabbitmq.client.*;
import java.io.IOException;
/**
* @author cy
* @create 2020-09-10-11:24
* @Description 消费信息
*/
public class Consumer_HelloWord {
public static void main(String[] args) throws Exception{
//1.创建连接工厂
ConnectionFactory factory = new ConnectionFactory();
//2.设置参数
factory.setHost("********");//ip 不设置默认为localhost
factory.setPort(5672); //端口 默认5672
factory.setVirtualHost("**"); //虚拟机 默认是 /
factory.setUsername("***");//用户名 默认guest
factory.setPassword("****"); //密码 默认是 guest
//3.创建连接 Connection
Connection connection = factory.newConnection();
//4.创建Channel
Channel channel = connection.createChannel();
//5.消费信息
/*
* basicConsume(String queue, boolean autoAck, Consumer callback)
* queue: 队列名称
* autoAck: 是否自动确认
* callback: 回调对象
*/
DefaultConsumer consumer = new DefaultConsumer(channel){
/**
* 回调方法,当收到信息后,会自动执行该方法
* @param consumerTag 标识
* @param envelope 获取一些信息,交换机,路由key
* @param properties 配置信息
* @param body 数据
* @throws IOException
*/
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println("consumerTag: "+consumerTag);
System.out.println("Exchange: "+envelope.getExchange());
System.out.println("RoutingKey: "+envelope.getRoutingKey());
System.out.println("properties: "+properties);
System.out.println("body: "+ new String(body));
}
};
/*
* basicConsume(String queue, boolean autoAck, Consumer callback)
* queue: 队列名称
* autoAck: 是否自动确认
* callback: 回调对象
*/
channel.basicConsume("Hello_Word", true, consumer);
}
}
运行之后,进行查看:
消息已经成功打印,查看Rabbitmq管理界面:
消息被消费者消费,成功.
2. 工作队列模式
2.1 模式说明
2.2 代码编写
2.2.1 创建工作队列生产者类
创建Producer_WorkQueue.java
package com.cy.producer;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
/**
* @author cy
* @create 2020-09-10-11:00
* @Description 发送消息
*/
public class Producer_WorkQueue {
public static void main(String[] args) throws Exception{
//1.创建连接工厂
ConnectionFactory factory = new ConnectionFactory();
//2.设置参数
factory.setHost("********");//ip 不设置默认为localhost
factory.setPort(5672); //端口 默认5672
factory.setVirtualHost("**"); //虚拟机 默认是 /
factory.setUsername("***");//用户名 默认guest
factory.setPassword("****"); //密码 默认是 guest
//3.创建连接 Connection
Connection connection = factory.newConnection();
//4.创建Channel
Channel channel = connection.createChannel();
//5.创建队列Queue
/*queueDeclare(String queue, boolean durable, boolean exclusive, boolean autoDelete, Map<String, Object> arguments)
queue: 队列名称
durable: 是否持久化,当mq重启之后还在
exclusive:
*是否独占,只能有一个消费者监听这队列
*当Connection关闭时,是否删除队列
autoDelete:是否自动删除,当没有Consumer时,自动删除掉
arguments:参数
*/
//如果没没有一个叫Hello_World的队列,则会创建
channel.queueDeclare("work_queues", true, false, false, null);
//6.发送消息
/*basicPublish(String exchange, String routingKey, BasicProperties props, byte[] body)
exchange: 交换机名称,简单模式下交换机会默认使用的 ""
routingKey: 路由名称
props: 配置信息
body: 发送的消息数据
*/
for (int i = 0; i <10 ; i++) {
String body = i + "Hello rabbitmq~~~";
channel.basicPublish("", "work_queues", null, body.getBytes());
}
//7.释放资源
channel.close();
connection.close();
}
}
运行之后,查看:
运行成功,来查看rabbitmq后台管理页面:
已经存在队列work_queues,并且有10条消息.
2.2.2 创建工作队列消费者类
由于可以有多个消费者队列,这里创建两个:
Consumer_WorkQueues1.java
package com.cy.consumer;
import com.rabbitmq.client.*;
import java.io.IOException;
/**
* @author cy
* @create 2020-09-10-11:24
* @Description 消费信息
*/
public class Consumer_WorkQueues1 {
public static void main(String[] args) throws Exception{
//1.创建连接工厂
ConnectionFactory factory = new ConnectionFactory();
//2.设置参数
factory.setHost("********");//ip 不设置默认为localhost
factory.setPort(5672); //端口 默认5672
factory.setVirtualHost("**"); //虚拟机 默认是 /
factory.setUsername("***");//用户名 默认guest
factory.setPassword("****"); //密码 默认是 guest
//3.创建连接 Connection
Connection connection = factory.newConnection();
//4.创建Channel
Channel channel = connection.createChannel();
//5.消费信息
/*
* basicConsume(String queue, boolean autoAck, Consumer callback)
* queue: 队列名称
* autoAck: 是否自动确认
* callback: 回调对象
*/
DefaultConsumer consumer = new DefaultConsumer(channel){
/**
* 回调方法,当收到信息后,会自动执行该方法
* @param consumerTag 标识
* @param envelope 获取一些信息,交换机,路由key
* @param properties 配置信息
* @param body 数据
* @throws IOException
*/
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
/* System.out.println("consumerTag"+consumerTag);
System.out.println("Exchange"+envelope.getExchange());
System.out.println("RoutingKey"+envelope.getRoutingKey());
System.out.println("properties"+properties);
System.out.println("body"+ new String(body));*/
System.out.println("body1: "+new String(body));
}
};
/*
* basicConsume(String queue, boolean autoAck, Consumer callback)
* queue: 队列名称
* autoAck: 是否自动确认
* callback: 回调对象
*/
channel.basicConsume("work_queues", true, consumer);
}
}
Consumer_WorkQueues2.java
package com.cy.consumer;
import com.rabbitmq.client.*;
import java.io.IOException;
/**
* @author cy
* @create 2020-09-10-11:24
* @Description 消费信息
*/
public class Consumer_WorkQueues1 {
public static void main(String[] args) throws Exception{
//1.创建连接工厂
ConnectionFactory factory = new ConnectionFactory();
//2.设置参数
factory.setHost("********");//ip 不设置默认为localhost
factory.setPort(5672); //端口 默认5672
factory.setVirtualHost("**"); //虚拟机 默认是 /
factory.setUsername("***");//用户名 默认guest
factory.setPassword("****"); //密码 默认是 guest
//3.创建连接 Connection
Connection connection = factory.newConnection();
//4.创建Channel
Channel channel = connection.createChannel();
//5.消费信息
/*
* basicConsume(String queue, boolean autoAck, Consumer callback)
* queue: 队列名称
* autoAck: 是否自动确认
* callback: 回调对象
*/
DefaultConsumer consumer = new DefaultConsumer(channel){
/**
* 回调方法,当收到信息后,会自动执行该方法
* @param consumerTag 标识
* @param envelope 获取一些信息,交换机,路由key
* @param properties 配置信息
* @param body 数据
* @throws IOException
*/
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
/* System.out.println("consumerTag"+consumerTag);
System.out.println("Exchange"+envelope.getExchange());
System.out.println("RoutingKey"+envelope.getRoutingKey());
System.out.println("properties"+properties);
System.out.println("body"+ new String(body));*/
System.out.println("body1: "+new String(body));
}
};
/*
* basicConsume(String queue, boolean autoAck, Consumer callback)
* queue: 队列名称
* autoAck: 是否自动确认
* callback: 回调对象
*/
channel.basicConsume("work_queues", true, consumer);
}
}
点击运行,查看控制台1和控制台2:
提示:这里需要注意的是,需要先开启两个消费者,在开启生产者,因为开启消费者顺序会存在一前一后.所以我是先开启了两个队列消费者,在开启生产者.
再查看rabbitmq后台管理界面:
成功.
2.3 小小的总结
我们再来看这张图,C1和C2共同消费一个queue中的消息,但是都是轮流的,可以从上述上述控制台1和2看出,轮流消费,你一个我一个那种.属于竞争关系.
3. Pub/Sub 订阅模式
3.1 模式说明
3.2 代码编写
3.2.1 创建Pub/Sub生产者类
Producer_PubSub.java
package com.cy.producer;
import com.rabbitmq.client.*;
import java.io.IOException;
/**
* @author cy
* @create 2020-09-10-11:24
* @Description 生产信息,通过特定模式发送
*/
public class Producer_PubSub {
public static void main(String[] args) throws Exception {
//1.创建连接工厂
ConnectionFactory factory = new ConnectionFactory();
//2.设置参数
factory.setHost("********");//ip 不设置默认为localhost
factory.setPort(5672); //端口 默认5672
factory.setVirtualHost("**"); //虚拟机 默认是 /
factory.setUsername("***");//用户名 默认guest
factory.setPassword("****"); //密码 默认是 guest
//3.创建连接 Connection
Connection connection = factory.newConnection();
//4.创建Channel
Channel channel = connection.createChannel();
//5.创建交换机
/*
exchangeDeclare(String exchange, BuiltinExchangeType type, boolean durable, boolean autoDelete, boolean internal, Map<String, Object> arguments)
exchange: 交换机名称
type: 交换机类型
DIRECT("direct"), :定向
FANOUT("fanout"), :扇形(广播),发送消息到每一个与之绑定的队列
TOPIC("topic"), :通配符的方式
HEADERS("headers");:参数匹配
durable: 是否持久化
autoDelete: 是否自动删除
internal: 内部使用(一般false)
arguments: 参数
*/
String exchangeName = "test_fanout";
channel.exchangeDeclare(exchangeName, BuiltinExchangeType.FANOUT,true,false,false,null);//采用广播类型的交换机
//6.创建队列
String queue1Name = "test_fanout_queue1";
String queue2Name = "test_fanout_queue2";
/*queueDeclare(String queue, boolean durable, boolean exclusive, boolean autoDelete, Map<String, Object> arguments)
queue: 队列名称
durable: 是否持久化,当mq重启之后还在
exclusive:
*是否独占,只能有一个消费者监听这队列
*当Connection关闭时,是否删除队列
autoDelete:是否自动删除,当没有Consumer时,自动删除掉
arguments:参数
*/
channel.queueDeclare(queue1Name, true, false, false, null);
channel.queueDeclare(queue2Name, true, false, false, null);
//7.绑定队列和交换机
/*
queueBind(String queue, String exchange, String routingKey)
queue: 队列名称
exchange: 交换机名称
routingKey: 路由键,绑定规则: 如果交换机规则为fanout,routingKey设置为 ""
*/
channel.queueBind(queue1Name,exchangeName,"");
channel.queueBind(queue2Name,exchangeName,"");
//8.发送消息
String body = "日志信息:张三调用了findAll方法 ..... 日志级别info....";
/*basicPublish(String exchange, String routingKey, BasicProperties props, byte[] body)
exchange: 交换机名称,简单模式下交换机会默认使用的 ""
routingKey: 路由键名称
props: 配置信息
body: 发送的消息数据
*/
channel.basicPublish(exchangeName, "", null, body.getBytes());
//9.释放资源
channel.close();
connection.close();
}
}
运行之后,查看:
没有错误,查看rabbitmq管理后台是否存在队列以及消息:
提示:由于交换机类型为广播类型,又有创建了两个队列和交换机进行绑定,所以,会存在两个队列并都存有一条消息.
3.2.2 创建Pub/Sub消费者类
同样的,创建两个消费者类
Consumer_PubSub1.java
package com.cy.consumer;
import com.rabbitmq.client.*;
import java.io.IOException;
/**
* @author cy
* @create 2020-09-10-11:24
* @Description 消费信息
*/
public class Consumer_PubSub1 {
public static void main(String[] args) throws Exception{
//1.创建连接工厂
ConnectionFactory factory = new ConnectionFactory();
//2.设置参数
factory.setHost("********");//ip 不设置默认为localhost
factory.setPort(5672); //端口 默认5672
factory.setVirtualHost("**"); //虚拟机 默认是 /
factory.setUsername("***");//用户名 默认guest
factory.setPassword("****"); //密码 默认是 guest
//3.创建连接 Connection
Connection connection = factory.newConnection();
//4.创建Channel
Channel channel = connection.createChannel();
//5.消费信息
DefaultConsumer consumer = new DefaultConsumer(channel){
/**
* 回调方法,当收到信息后,会自动执行该方法
* @param consumerTag 标识
* @param envelope 获取一些信息,交换机,路由key
* @param properties 配置信息
* @param body 数据
* @throws IOException
*/
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
/* System.out.println("consumerTag"+consumerTag);
System.out.println("Exchange"+envelope.getExchange());
System.out.println("RoutingKey"+envelope.getRoutingKey());
System.out.println("properties"+properties);
System.out.println("body"+ new String(body));*/
System.out.println("body1: "+new String(body));
System.out.println("将日志打印到控制台......");
}
};
String queue1Name = "test_fanout_queue1";
String queue2Name = "test_fanout_queue2";
/*
* basicConsume(String queue, boolean autoAck, Consumer callback)
* queue: 队列名称
* autoAck: 是否自动确认
* callback: 回调对象
*/
channel.basicConsume(queue1Name, true, consumer);
}
}
Consumer_PubSub1.java
package com.cy.consumer;
import com.rabbitmq.client.*;
import java.io.IOException;
/**
* @author cy
* @create 2020-09-10-11:24
* @Description 消费信息
*/
public class Consumer_PubSub2 {
public static void main(String[] args) throws Exception{
//1.创建连接工厂
ConnectionFactory factory = new ConnectionFactory();
//2.设置参数
factory.setHost("********");//ip 不设置默认为localhost
factory.setPort(5672); //端口 默认5672
factory.setVirtualHost("**"); //虚拟机 默认是 /
factory.setUsername("***");//用户名 默认guest
factory.setPassword("****"); //密码 默认是 guest
//3.创建连接 Connection
Connection connection = factory.newConnection();
//4.创建Channel
Channel channel = connection.createChannel();
//5.消费信息
DefaultConsumer consumer = new DefaultConsumer(channel){
/**
* 回调方法,当收到信息后,会自动执行该方法
* @param consumerTag 标识
* @param envelope 获取一些信息,交换机,路由key
* @param properties 配置信息
* @param body 数据
* @throws IOException
*/
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
/* System.out.println("consumerTag"+consumerTag);
System.out.println("Exchange"+envelope.getExchange());
System.out.println("RoutingKey"+envelope.getRoutingKey());
System.out.println("properties"+properties);
System.out.println("body"+ new String(body));*/
System.out.println("body1: "+new String(body));
System.out.println("将日志保存到数据库......");
}
};
String queue1Name = "test_fanout_queue1";
String queue2Name = "test_fanout_queue2";
/*
* basicConsume(String queue, boolean autoAck, Consumer callback)
* queue: 队列名称
* autoAck: 是否自动确认
* callback: 回调对象
*/
channel.basicConsume(queue2Name, true, consumer);
}
}
开启消费者1和消费者2,查看控制台:
两个消费者都消费了消息
再查看rabbitmq管理后台:
两个队列都无消息.
3.3 小小的总结
4. Routing 路由模式
4.1 模式说明
4.2 代码编写
4.2.1 创建 路由生产者
Producer_Routing.java
package com.cy.producer;
import com.rabbitmq.client.BuiltinExchangeType;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
/**
* @author cy
* @create 2020-09-10-11:24
* @Description 消费信息
*/
public class Producer_Routing {
public static void main(String[] args) throws Exception {
//1.创建连接工厂
ConnectionFactory factory = new ConnectionFactory();
//2.设置参数
factory.setHost("********");//ip 不设置默认为localhost
factory.setPort(5672); //端口 默认5672
factory.setVirtualHost("**"); //虚拟机 默认是 /
factory.setUsername("***");//用户名 默认guest
factory.setPassword("****"); //密码 默认是 guest
//3.创建连接 Connection
Connection connection = factory.newConnection();
//4.创建Channel
Channel channel = connection.createChannel();
//5.创建交换机
/*
exchangeDeclare(String exchange, BuiltinExchangeType type, boolean durable, boolean autoDelete, boolean internal, Map<String, Object> arguments)
exchange: 交换机名称
type: 交换机类型
DIRECT("direct"), :定向
FANOUT("fanout"), :扇形(广播),发送消息到每一个与之绑定的队列
TOPIC("topic"), :通配符的方式
HEADERS("headers");:参数匹配
durable: 是否持久化
autoDelete: 是否自动删除
internal: 内部使用(一般false)
arguments: 参数
*/
String exchangeName = "test_direct";
channel.exchangeDeclare(exchangeName, BuiltinExchangeType.DIRECT,true,false,false,null);
//6.创建队列
String queue1Name = "test_direct_queue1";
String queue2Name = "test_direct_queue2";
channel.queueDeclare(queue1Name, true, false, false, null);
channel.queueDeclare(queue2Name, true, false, false, null);
//7.绑定队列和交换机
/*
queueBind(String queue, String exchange, String routingKey)
queue: 队列名称
exchange: 交换机名称
routingKey: 路由键,绑定规则: 如果交换机规则为fanout,routingKey设置为 ""
*/
//队列一的绑定
channel.queueBind(queue1Name,exchangeName,"error");
//队列二的绑定
channel.queueBind(queue2Name,exchangeName,"info");
channel.queueBind(queue2Name,exchangeName,"error");
channel.queueBind(queue2Name,exchangeName,"warning");
//8.发送消息
String body = "日志信息:张三调用了delete方法 .....出错了.. 日志级别error....";
channel.basicPublish(exchangeName, "warning", null, body.getBytes());
//9.释放资源
channel.close();
connection.close();
}
}
运行之后,查看:
没有错误,再来查看rabbitmq后台:
只有队列二有消息
/*
queueBind(String queue, String exchange, String routingKey)
queue: 队列名称
exchange: 交换机名称
routingKey: 路由键,绑定规则: 如果交换机规则为fanout,routingKey设置为 ""
*/
//队列一的绑定
channel.queueBind(queue1Name,exchangeName,"error");
//队列二的绑定
channel.queueBind(queue2Name,exchangeName,"info");
channel.queueBind(queue2Name,exchangeName,"error");
channel.queueBind(queue2Name,exchangeName,"warning");
查看这部分代码,routingKey中, 队列 1 绑定了 “error” 规则 ,队列 2绑定了 “info”,“error”,“warning” 等路由规则.
//8.发送消息
/*basicPublish(String exchange, String routingKey, BasicProperties props, byte[] body)
exchange: 交换机名称,简单模式下交换机会默认使用的 ""
routingKey: 路由名称
props: 配置信息
body: 发送的消息数据
*/
String body = "日志信息:张三调用了delete方法 .....出错了.. 日志级别error....";
channel.basicPublish(exchangeName, "warning", null, body.getBytes());
由于发送的消息为"warning" 规则 , 所以只有 队列 2 才会收到消息 .
4.2.2 创建路由消费者
Consumer_Routing1.java
package com.cy.consumer;
import com.rabbitmq.client.*;
import java.io.IOException;
/**
* @author cy
* @create 2020-09-10-11:24
* @Description 消费信息
*/
public class Consumer_Routing1 {
public static void main(String[] args) throws Exception{
//1.创建连接工厂
ConnectionFactory factory = new ConnectionFactory();
//2.设置参数
factory.setHost("********");//ip 不设置默认为localhost
factory.setPort(5672); //端口 默认5672
factory.setVirtualHost("**"); //虚拟机 默认是 /
factory.setUsername("***");//用户名 默认guest
factory.setPassword("****"); //密码 默认是 guest
//3.创建连接 Connection
Connection connection = factory.newConnection();
//4.创建Channel
Channel channel = connection.createChannel();
//5.消费信息
/*
* basicConsume(String queue, boolean autoAck, Consumer callback)
* queue: 队列名称
* autoAck: 是否自动确认
* callback: 回调对象
*/
DefaultConsumer consumer = new DefaultConsumer(channel){
/**
* 回调方法,当收到信息后,会自动执行该方法
* @param consumerTag 标识
* @param envelope 获取一些信息,交换机,路由key
* @param properties 配置信息
* @param body 数据
* @throws IOException
*/
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
/* System.out.println("consumerTag"+consumerTag);
System.out.println("Exchange"+envelope.getExchange());
System.out.println("RoutingKey"+envelope.getRoutingKey());
System.out.println("properties"+properties);
System.out.println("body"+ new String(body));*/
System.out.println("body1: "+new String(body));
System.out.println("将日志存储到数据库......");
}
};
String queue1Name = "test_direct_queue1";
String queue2Name = "test_direct_queue2";
channel.basicConsume(queue1Name, true, consumer);
}
}
Consumer_Routing2.java
package com.cy.consumer;
import com.rabbitmq.client.*;
import java.io.IOException;
/**
* @author cy
* @create 2020-09-10-11:24
* @Description 消费信息
*/
public class Consumer_Routing2 {
public static void main(String[] args) throws Exception{
//1.创建连接工厂
ConnectionFactory factory = new ConnectionFactory();
//2.设置参数
factory.setHost("********");//ip 不设置默认为localhost
factory.setPort(5672); //端口 默认5672
factory.setVirtualHost("**"); //虚拟机 默认是 /
factory.setUsername("***");//用户名 默认guest
factory.setPassword("****"); //密码 默认是 guest
//3.创建连接 Connection
Connection connection = factory.newConnection();
//4.创建Channel
Channel channel = connection.createChannel();
//5.消费信息
/*
* basicConsume(String queue, boolean autoAck, Consumer callback)
* queue: 队列名称
* autoAck: 是否自动确认
* callback: 回调对象
*/
DefaultConsumer consumer = new DefaultConsumer(channel){
/**
* 回调方法,当收到信息后,会自动执行该方法
* @param consumerTag 标识
* @param envelope 获取一些信息,交换机,路由key
* @param properties 配置信息
* @param body 数据
* @throws IOException
*/
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
/* System.out.println("consumerTag"+consumerTag);
System.out.println("Exchange"+envelope.getExchange());
System.out.println("RoutingKey"+envelope.getRoutingKey());
System.out.println("properties"+properties);
System.out.println("body"+ new String(body));*/
System.out.println("body1: "+new String(body));
System.out.println("将日志打印到控制台......");
}
};
String queue1Name = "test_direct_queue1";
String queue2Name = "test_direct_queue2";
channel.basicConsume(queue2Name, true, consumer);
}
}
运行消费者,查看控制台:
只有二队列有消息并得到了消费,查看rabbitmq后台查看:
成功.
4.3 小小的总结
5. Topics 通配符模式
5.1 模式说明
- ( # ) :占位符,只零个或多个单位
- ( * ) : 占位符,指单个单位
5.2 代码编写
5.2.1 编写通配生产者类
Producer_Topics.java
package com.cy.producer;
import com.rabbitmq.client.BuiltinExchangeType;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
/**
* @author cy
* @create 2020-09-10-11:24
* @Description
*/
public class Producer_Topics {
public static void main(String[] args) throws Exception {
//1.创建连接工厂
ConnectionFactory factory = new ConnectionFactory();
//2.设置参数
factory.setHost("********");//ip 不设置默认为localhost
factory.setPort(5672); //端口 默认5672
factory.setVirtualHost("**"); //虚拟机 默认是 /
factory.setUsername("***");//用户名 默认guest
factory.setPassword("****"); //密码 默认是 guest
//3.创建连接 Connection
Connection connection = factory.newConnection();
//4.创建Channel
Channel channel = connection.createChannel();
//5.创建交换机
/*
exchangeDeclare(String exchange, BuiltinExchangeType type, boolean durable, boolean autoDelete, boolean internal, Map<String, Object> arguments)
exchange: 交换机名称
type: 交换机类型
DIRECT("direct"), :定向
FANOUT("fanout"), :扇形(广播),发送消息到每一个与之绑定的队列
TOPIC("topic"), :通配符的方式
HEADERS("headers");:参数匹配
durable: 是否持久化
autoDelete: 是否自动删除
internal: 内部使用(一般false)
arguments: 参数
*/
String exchangeName = "test_topic";
channel.exchangeDeclare(exchangeName, BuiltinExchangeType.TOPIC,true,false,false,null);
//6.创建队列
String queue1Name = "test_topic_queue1";
String queue2Name = "test_topic_queue2";
channel.queueDeclare(queue1Name, true, false, false, null);
channel.queueDeclare(queue2Name, true, false, false, null);
//7.绑定队列和交换机
/*
queueBind(String queue, String exchange, String routingKey)
queue: 队列名称
exchange: 交换机名称
routingKey: 路由键,绑定规则: 如果交换机规则为fanout,routingKey设置为 ""
*/
// # 代表零个或者多个 * 代表一个
//routingKey 系统的名称.日志的级别
//===需求: 所有error级别的日志存入数据库 , 所有order 系统的日志存入数据库
//队列1 的绑定
channel.queueBind(queue1Name,exchangeName,"#.error");
channel.queueBind(queue1Name,exchangeName,"order.*");
// 队列2 的绑定
channel.queueBind(queue2Name,exchangeName,"*.*");
//8.发送消息
String body = "日志信息:张三调用了findAll方法 ..... 日志级别info....";
channel.basicPublish(exchangeName, "my.goods.error", null, body.getBytes());
//9.释放资源
channel.close();
connection.close();
}
}
启动生产者,并查看控制台:
查看rabbitmq后台是否有相应队列以及消息:
5.2.2 编写通配消费者类
Consumer_Topic1.java
package com.cy.consumer;
import com.rabbitmq.client.*;
import java.io.IOException;
/**
* @author cy
* @create 2020-09-10-11:24
* @Description 消费信息
*/
public class Consumer_Topic1 {
public static void main(String[] args) throws Exception{
//1.创建连接工厂
ConnectionFactory factory = new ConnectionFactory();
//2.设置参数
factory.setHost("********");//ip 不设置默认为localhost
factory.setPort(5672); //端口 默认5672
factory.setVirtualHost("**"); //虚拟机 默认是 /
factory.setUsername("***");//用户名 默认guest
factory.setPassword("****"); //密码 默认是 guest
//3.创建连接 Connection
Connection connection = factory.newConnection();
//4.创建Channel
Channel channel = connection.createChannel();
//5.消费信息
/*
* basicConsume(String queue, boolean autoAck, Consumer callback)
* queue: 队列名称
* autoAck: 是否自动确认
* callback: 回调对象
*/
DefaultConsumer consumer = new DefaultConsumer(channel){
/**
* 回调方法,当收到信息后,会自动执行该方法
* @param consumerTag 标识
* @param envelope 获取一些信息,交换机,路由key
* @param properties 配置信息
* @param body 数据
* @throws IOException
*/
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
/* System.out.println("consumerTag"+consumerTag);
System.out.println("Exchange"+envelope.getExchange());
System.out.println("RoutingKey"+envelope.getRoutingKey());
System.out.println("properties"+properties);
System.out.println("body"+ new String(body));*/
System.out.println("body1: "+new String(body));
System.out.println("将日志存储到数据库......");
}
};
String queue1Name = "test_topic_queue1";
String queue2Name = "test_topic_queue2";
channel.basicConsume(queue1Name, true, consumer);
}
}
Consumer_Topic2.java
package com.cy.consumer;
import com.rabbitmq.client.*;
import java.io.IOException;
/**
* @author cy
* @create 2020-09-10-11:24
* @Description 消费信息
*/
public class Consumer_Topic2 {
public static void main(String[] args) throws Exception{
//1.创建连接工厂
ConnectionFactory factory = new ConnectionFactory();
//2.设置参数
factory.setHost("********");//ip 不设置默认为localhost
factory.setPort(5672); //端口 默认5672
factory.setVirtualHost("**"); //虚拟机 默认是 /
factory.setUsername("***");//用户名 默认guest
factory.setPassword("****"); //密码 默认是 guest
//3.创建连接 Connection
Connection connection = factory.newConnection();
//4.创建Channel
Channel channel = connection.createChannel();
//5.创建队列Queue
/*queueDeclare(String queue, boolean durable, boolean exclusive, boolean autoDelete, Map<String, Object> arguments)
queue: 队列名称
durable: 是否持久化,当mq重启之后还在
exclusive:
*是否独占,只能有一个消费者监听这队列
*当Connection关闭时,是否删除队列
autoDelete:是否自动删除,当没有Consumer时,自动删除掉
arguments:参数
*/
//如果没没有一个叫Hello_World的队列,则会创建
//6.消费信息
/*
* basicConsume(String queue, boolean autoAck, Consumer callback)
* queue: 队列名称
* autoAck: 是否自动确认
* callback: 回调对象
*/
DefaultConsumer consumer = new DefaultConsumer(channel){
/**
* 回调方法,当收到信息后,会自动执行该方法
* @param consumerTag 标识
* @param envelope 获取一些信息,交换机,路由key
* @param properties 配置信息
* @param body 数据
* @throws IOException
*/
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
/* System.out.println("consumerTag"+consumerTag);
System.out.println("Exchange"+envelope.getExchange());
System.out.println("RoutingKey"+envelope.getRoutingKey());
System.out.println("properties"+properties);
System.out.println("body"+ new String(body));*/
System.out.println("body1: "+new String(body));
System.out.println("将日志打印控制台.....");
}
};
String queue1Name = "test_topic_queue1";
String queue2Name = "test_topic_queue2";
channel.basicConsume(queue2Name, true, consumer);
}
}
运行消费者,并查看控制台打印:
符合,查看后台:
这就是路由通配方式.
5.3 小小的总结
四、工作模式总结
工作队列模式 和简单模式生产区别不大,主要在于消费时,多创建了消费者
发布订阅模式(Pub/Sub) 主要在与生产时,需要创建一个交换机并制动交换机类型为"fanout",也要绑定交换机和队列,发布时,如果交换机规则为fanout,routingKey设置为 " " .
路由模式(Routing) 主要在于生产时,需要创建一个交换机并制动交换机类型为"direct", 交换机和队列绑定时,需要制定特定的routingKey , 例如 “error”,“info”,“warning” 等等. 消费无差.
通配符模式 主要在于生产时,需要创建一个交换机并制动交换机类型为"topic", 交换机和队列绑定时,需要制定特定的routingKey,例如 “#.error” "order." ".*"等等,消费无差.
仅供个人学习参考,只是一枚Java菜鸟,如有问题请指出.谢谢