官网
环境准备
- RabbitMQ 3.8.17
- Erlang 23.3
什么是RabbitMQ
- 一款基于AMQP(Advanced Message Queuing Protocol)用于软件之间通信的中间件,实现了服务之间的高度解耦
- 多用在分布式系统中储存转发的消息,在易用性,拓展性,高可用性等方面表现很好
为什么要使用RabbitMQ
待补充
RabbitMQ的使用场景
待补充
RabbitMQ主要由什么组成?
- 生产者
- 交换机
- 消息队列
- 消费者
图示:
RabbitMQ JAVA客户端连接并使用
工程结构
导入依赖
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.12</version>
</parent>
<dependencies>
<dependency>
<groupId>com.rabbitmq</groupId>
<artifactId>amqp-client</artifactId>
<version>4.0.3</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-api -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</dependency>
</dependencies>
由于amqp-client 内部依赖日志文件, 所以导入了日志的依赖包
HELLOWORLD
图示模型
生产者将消息发送到消息队列中, 消费者直接从消息队列取出
生产者代码
public class Producer_helloworld {
private static final String QUEUE_NAME="hello";
public static void main(String[] args) throws IOException, TimeoutException {
ConnectionFactory connectionFactory = new ConnectionFactory();
Connection connection = connectionFactory.newConnection();
Channel channel = connection.createChannel();
String message="放下过往,他只会遮蔽未来";
channel.basicPublish("",QUEUE_NAME,null,message.getBytes());
channel.close();
connection.close();
}
}
> 变量解析
> ConnectionFactory connectionFactory = new ConnectionFactory(); 创建连接工厂
> Connection connection = connectionFactory.newConnection(); 通过工厂创建连接对象
> Channel channel = connection.createChannel(); 创建通道这个通道指的是整体,可以理解为通道将生产者,消息队列,消费者给连起来, 通道里面包含所有的内容
>
> String message="放下过往,他只会遮蔽未来"; 定义要发送的信息
> channel.basicPublish("",QUEUE\_NAME,null,message.getBytes()); 将消息发送出去
> 参数分析,第一个参数为”“ 代表交换机,我们这里是P发送给队列,C从队列中拿 所以不需要交换机 这里填空值
>第二个参数为QUEUE_NAME,这里代表要将这个消息发送到哪个消息队列里面
> 第三个参数为null, 这里代表发送消息的属性
> 第四个参数代表要发送的内容
关闭通道,关闭连接
被红圈圈起来的这个整体代表chanel
消费者代码
public class Cousumer_helloworld {
private final static String QUEUE_NAME="hello";
public static void main(String[] args) throws IOException, TimeoutException {
ConnectionFactory connectionFactory = new ConnectionFactory(); //创建连接
connectionFactory.setHost("127.0.0.1"); //我们要接受哪个主机发送的消息?
Connection connection = connectionFactory.newConnection(); //建立连接
Channel channel = connection.createChannel(); //创建通道,要注意通道包含P 消息队列 C
channel.queueDeclare(QUEUE_NAME,false,false,false,null); //声明队列
DefaultConsumer defaultConsumer=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);
}
};
channel.basicConsume(QUEUE_NAME,true,defaultConsumer);
}
}
代码解析
channel.queueDeclare(QUEUE_NAME,false,false,false,null);
这句是为了 声明一个队列,也可以理解为创建一个队列, 这个队列名字叫做QUEUE_NAME="HELLO", 我们连接的主机是127.0.0.1 上面主机发送出来了一条消息,发送给了 名字叫hello 的队列, 我们这里声明了一个hello 的队列, 这样就可以收到主机发送出来的消息了,后面的三个false分别代表,队列是否持久化,队列是否独占,队列不使用的时候是否要自动删除,最后一个null代表 队列参数为空
Work Queues
原理图示
生产者代码
public class Producer_work_queues {
private final static String QUEUE_WORKQUEUES_NAME="workqueues"; //定义队列名,为发送消息做准备
public static void main(String[] args) throws IOException, TimeoutException {
ConnectionFactory connectionFactory = new ConnectionFactory(); //创建连接工厂
Connection connection = connectionFactory.newConnection(); //创建工厂
Channel channel = connection.createChannel(); //创建通道
String message="HELLO WORKQUEUES"; //定义消息
channel.basicPublish("",QUEUE_WORKQUEUES_NAME,null,message.getBytes()); //将消息发送到空交换机,上面准备好的队列名的哪个队列, 数据参数为空, 数据信息
channel.close();
connection.close();
}
}
1号消费者代码
public class Cosumer_work_queue_01 {
private final static String QUEUE_WORKQUEUES_NAME="workqueues";
public static void main(String[] args) throws IOException, TimeoutException {
ConnectionFactory connectionFactory = new ConnectionFactory(); //创建连接工厂
connectionFactory.setHost("127.0.0.1"); //连接到哪个主机?
Connection connection = connectionFactory.newConnection(); //建立连接
Channel channel = connection.createChannel(); //创建通道
channel.queueDeclare(QUEUE_WORKQUEUES_NAME,false,false,false,null); //声明一个队列,
channel.basicQos(1); //我是第一个拿的
DefaultConsumer defaultConsumer=new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println(new String(body,"UTF-8"));
}
};
channel.basicConsume(QUEUE_WORKQUEUES_NAME,true,defaultConsumer); //监听这个队列,有新消息接收的时候调用defaultconsumer中的方法 打印输出
}
}
2号消费者代码
public class Cosumer_work_queue_02 {
private final static String QUEUE_WORKQUEUES_NAME="workqueues";
public static void main(String[] args) throws IOException, TimeoutException {
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost("127.0.0.1");
Connection connection = connectionFactory.newConnection();
Channel channel = connection.createChannel();
channel.queueDeclare(QUEUE_WORKQUEUES_NAME,false,false,false,null);
channel.basicQos(2); //注意这里
DefaultConsumer defaultConsumer=new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println(new String(body,"UTF-8"));
}
};
channel.basicConsume(QUEUE_WORKQUEUES_NAME,true,defaultConsumer);
}
}
总结 我们会发现 1号消费者和2号消费者代码几乎一摸一样, 只是中间由两条 不一样 , channel.basicQos(1); channel.basicQos(2); 现在是两个消费者都接受一条队列的消息, 当生产者发送消息的时候, 第一次会被一号消费者先接收到,二号消费者接收不到, 当生产者再次发送消息的时候, 一号消费者接收不到,二号消费者可以接收到, 就是两个消费者轮流接受生产者发送的信息,此时的chanel 代表什么呢?
chanel 代表这个整体!
Publish
生产者
public class Producer_publish {
private final static String EXCHANGE_NAME="exchange";
public static void main(String[] args) throws IOException, TimeoutException {
ConnectionFactory connectionFactory = new ConnectionFactory();
Connection connection = connectionFactory.newConnection();
Channel channel = connection.createChannel();
channel.exchangeDeclare(EXCHANGE_NAME,"fanout");
String message="hello exchange";
channel.basicPublish(EXCHANGE_NAME,"",null,message.getBytes());
channel.close();
connection.close();
}
}
消费者01
public class Consumer_subscribe_01 {
private final static String EXCHANGE_NAME="exchange";
private final static String QUEUE_NAME_01="exchange_queue_01";
public static void main(String[] args) throws IOException, TimeoutException {
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost("127.0.0.1");
Connection connection = connectionFactory.newConnection();
Channel channel = connection.createChannel();
channel.exchangeDeclare(EXCHANGE_NAME,"fanout");
channel.queueDeclare(QUEUE_NAME_01,false,false,false,null);
channel.queueBind(QUEUE_NAME_01,EXCHANGE_NAME,"");
DefaultConsumer defaultConsumer=new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println(new String(body,"UTF-8"));
}
};
channel.basicConsume(QUEUE_NAME_01,true,defaultConsumer);
}
}
消费者02
public class Consumer_subscribe_02 {
private final static String EXCHANGE_NAME="exchange";
private final static String QUEUE_NAME_02="exchange_queue_02";
public static void main(String[] args) throws IOException, TimeoutException {
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost("127.0.0.1");
Connection connection = connectionFactory.newConnection();
Channel channel = connection.createChannel();
channel.exchangeDeclare(EXCHANGE_NAME,"fanout");
channel.queueDeclare(QUEUE_NAME_02,false,false,false,null);
channel.queueBind(QUEUE_NAME_02,EXCHANGE_NAME,"");
DefaultConsumer defaultConsumer=new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println(new String(body,"UTF-8"));
}
};
channel.basicConsume(QUEUE_NAME_02,true,defaultConsumer);
}
}
路由模式
生产者
public class Producer_routing {
private final static String EXCHANGE_NAME="routing_exchange";
private final static String QUEUE_NAME_01="routing_queue_01";
private final static String QUEUE_NAME_02="routing_queue_02";
private final static String ROUTING_KEY_NAME_01="red";
private final static String ROUTING_KEY_NAME_02="blue";
public static void main(String[] args) throws IOException, TimeoutException {
ConnectionFactory connectionFactory = new ConnectionFactory();
Connection connection = connectionFactory.newConnection();
Channel channel = connection.createChannel();
channel.exchangeDeclare(EXCHANGE_NAME, BuiltinExchangeType.DIRECT); //声明交换机
/* channel.queueDeclare(QUEUE_NAME_01,false,false,false,null); //声明消息队列
channel.queueDeclare(QUEUE_NAME_02,false,false,false,null); //声明消息队列
channel.queueBind(QUEUE_NAME_02,EXCHANGE_NAME,ROUTING_KEY_NAME_02); //绑定消息队列,
channel.queueBind(QUEUE_NAME_01,EXCHANGE_NAME,ROUTING_KEY_NAME_01); //绑定消息队列*/
String message="hello routing";
// 推送消息, 交换机名称 路由key 名称 消息属性 , 消息内容
channel.basicPublish(EXCHANGE_NAME,ROUTING_KEY_NAME_01,null,message.getBytes());
channel.basicPublish(EXCHANGE_NAME,ROUTING_KEY_NAME_02,null,message.getBytes());
channel.close();
connection.close();
}
}
消费者01
public class Consumer_routing_01 {
private final static String EXCHANGE_NAME="routing_exchange";
private final static String ROUTING_KEY_NAME_01="red"; //路由键名 red
private final static String QUEUE_NAME_01="routing_queue_01"; //队列名 01
public static void main(String[] args) throws IOException, TimeoutException {
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost("127.0.0.1");
Connection connection = connectionFactory.newConnection();
Channel channel = connection.createChannel(); //创建通道
channel.queueDeclare(QUEUE_NAME_01,false,false,false,null); //声明队列
channel.exchangeDeclare(EXCHANGE_NAME, BuiltinExchangeType.DIRECT); //声明交换机
channel.queueBind(QUEUE_NAME_01,EXCHANGE_NAME,ROUTING_KEY_NAME_01); //队列和交换机 绑定 队列名, 交换机名, 路由名
DefaultConsumer defaultConsumer=new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println(new String(body,"UTF-8"));
}
};
channel.basicConsume(QUEUE_NAME_01,true,defaultConsumer); //监听队列 01 的信息
}
}
消费者02
public class Consumer_routing_02 {
private final static String EXCHANGE_NAME="routing_exchange";
private final static String ROUTING_KEY_NAME_02="blue";
private final static String QUEUE_NAME_02="routing_queue_01";
public static void main(String[] args) throws IOException, TimeoutException {
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost("127.0.0.1");
Connection connection = connectionFactory.newConnection();
Channel channel = connection.createChannel();
channel.queueDeclare(QUEUE_NAME_02,false,false,false,null);
channel.exchangeDeclare(EXCHANGE_NAME, BuiltinExchangeType.DIRECT);
channel.queueBind(QUEUE_NAME_02,EXCHANGE_NAME,ROUTING_KEY_NAME_02);
DefaultConsumer defaultConsumer=new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println(new String(body,"UTF-8"));
}
};
channel.basicConsume(QUEUE_NAME_02,true,defaultConsumer);
}
}
Topic模式
生产者
public class Producer_topics {
private final static String EXCHANGE_NAME="topic_exchange";
private final static String ROUNTING_KEY_01="J.kkk";
private final static String ROUNTING_KEY_02="G.";
public static void main(String[] args) throws IOException, TimeoutException {
ConnectionFactory connectionFactory = new ConnectionFactory();
Connection connection = connectionFactory.newConnection();
Channel channel = connection.createChannel();
channel.exchangeDeclare(EXCHANGE_NAME, BuiltinExchangeType.TOPIC);
String message1="怒火焚身!";
String message2="混元寒冰,朔风凛冽";
channel.basicPublish(EXCHANGE_NAME,ROUNTING_KEY_01,null,message1.getBytes());
channel.basicPublish(EXCHANGE_NAME,ROUNTING_KEY_02,null,message2.getBytes());
channel.close();
connection.close();
}
}
消费者
public class Consumer_topics_01 {
private final static String EXCHANGE_NAME="topic_exchange"; //交换机名字
private final static String QUEUE_NAME="jicanghai"; // 队列名字
private final static String ROUTING_KEY="J.#"; // 路由KEy
public static void main(String[] args) throws IOException, TimeoutException {
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost("127.0.0.1");
Connection connection = connectionFactory.newConnection();
Channel channel = connection.createChannel();
channel.exchangeDeclare(EXCHANGE_NAME, BuiltinExchangeType.TOPIC);
channel.queueDeclare(QUEUE_NAME,false,false,false,null);
channel.queueBind(QUEUE_NAME,EXCHANGE_NAME,ROUTING_KEY); //队列和交换机 通过路由key 绑定
DefaultConsumer defaultConsumer=new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println(new String(body,"UTF-8"));
}
};
channel.basicConsume(QUEUE_NAME,true,defaultConsumer); //监听队列 01 的信息
}
}
SpringBoot 整合RabbitMQ
导入依赖
<dependencies>
<dependency>
<groupId>com.rabbitmq</groupId>
<artifactId>amqp-client</artifactId>
<version>4.0.3</version><!--此版本与spring boot 1.5.9版本匹配-->
</dependency>
<!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-api -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</dependency>
</dependencies>
路由模式测试
编写生产者配置类
@Configuration
public class RabbitMQConfiguration {
public final static String EXCHANGE_NAME_Routing="exchange_routing";
@Bean
public Exchange getExchange(){
return ExchangeBuilder.topicExchange(EXCHANGE_NAME_Routing).build();
}
}
生产者测试类
@SpringBootTest
@RunWith(SpringRunner.class)
public class ProducerTest {
@Autowired
private AmqpTemplate amqpTemplate;
@Value("${mq.message.routing_key}")
private String ROUTING_KEY;
@Test
public void testSending(){
amqpTemplate.convertAndSend(RabbitMQConfiguration.EXCHANGE_NAME_Routing,ROUTING_KEY,"怒火焚身!");
}
}
消费者配置类
@Configuration
public class RabbitMQConfiguration {
public final static String EXCHANGE_NAME_Routing="exchange_routing";
@Value("${mq.consumer.queue.name}")
private String queueName;
@Value("${mq.message.routing_key}")
private String routing_key;
@Bean
public Exchange getExchange(){
return ExchangeBuilder.topicExchange(EXCHANGE_NAME_Routing).build();
}
@Bean
public Queue getQueue(){
return new Queue(queueName,false,false,false);
}
@Bean
public Binding bindingQueueExchange(Queue queue,Exchange exchange){
return BindingBuilder.bind(queue).to(exchange).with(routing_key).noargs();
}
}
消费者处理接受内容类
@Component
public class ReceiveMsg {
@RabbitListener(queues = "routing_queue")
public void doneMsg(String msg){
System.out.println(msg);
}
}