RabbitMQ消息中间件

1.队列: 一端存储从另一端获取
2.堆 : 存取都在一端执行
3.rabbitMq使用场景:

  1. 服务解耦:rabbitMQ是一个中间件。用于将消息全部存储在消息中间件中,同时也为程序服务解耦,降低了耦合性。
  2. 流量削峰:当在某一间隔大量的客户进行访问服务器,中间件将会将发送的请求放在队列中慢慢的进行处理,这样把处理时间拉长,以减轻随见压力。
  3. 异步调用:当在高峰期,若在队列执行后返回会比较耗时,则需要引入消息队列,请求数据可以发送到消息队列,调用另一个系统先响应给用户,然后消息队列再慢慢的执行,执行最终结果再次响应给用户(客户端)。

rabbitMQ安装与运行

  1. 搜索官网 下载rabbitMQ:下载rmp文件
  2. 也可以先现在到windows系统中:通过命令brew install rabbitmq安装时下载Rabbitmq-server-generic-unix-3.8.3.tar.xz失败?当前文件可通过添加〜/ Library / Caches / Homebrew / downloads目录下,再次运行命令即可安装成功!
  3. (若不能执行时安装) RabbitMQ依赖于 Erlang 语言库,必须先安装Erlang语言包Erlang-R16B-03.18
  4. 传入到指定目录:进入目录cd rabbitmq-in...
  5. 安装所有的rpm文件: rpm -ivh * .rpm
**启动rabbitmq服务器:**
 1.设置服务,开机自动启动:`systemctl  enable rabbitmq-server  `
 2.启动服务: `systemctl start  rabbitmq-server`
**rabbitmq管理界面**
1.开启管理界面插件: `rabbitmq-plugins enable rabbitmq_management`
2.开启防火墙 打开一个管理端口 
   如: 15672 :为管理端口    5672:通信端口
    1.`firewall-cmd  --zone=public  --add-port=15672/tcp --permanent`
    2.重启`firewall-cmd --reload`
**重启rabbitmq管理界面**
systemctl restart rabbitmq-server
  1. 若进行访问的话,查看linux的ip :ip addr /ipconfig
**访问管理端口**
ip:15762(管理Port)
  1. linux添加超级管理员
1.添加用户 
  rabbitmqctl add_user admin  admin
 2.新用户设置用户超级管理员
  rabbitmqctl set_user_tags admin administrator
  1. 开放客户端连接端口
打开客户端间接端口
1.firewall-cmmd --zone=public --add-port=5672/tcp --permanent
2.firewall-cmd --reload

4369 – erlang发现口
5672 – client端通信口
15672 – 管理界面ui端口
25672 – server间内部通信口

设计模式(发送消息称为生产者 ,接收消息称为消费者)

使用:

  1. 环境:STS/IDEA +maven /springBoot +rabbitmq
    2.使用时需要使用rabbitmq 依赖,及发布依赖 (若使用其他还可以添加 里面加入了日志slf4j 依赖)
<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.tedu</groupId>
	<artifactId>rabbitmq</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<dependencies>
		<dependency>
			<groupId>com.rabbitmq</groupId>
			<artifactId>amqp-client</artifactId>
			<version>5.4.3</version>
		</dependency>
		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>slf4j-api</artifactId>
			<version>1.8.0-alpha2</version>
		</dependency>
		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>slf4j-log4j12</artifactId>
			<version>1.8.0-alpha2</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>
</project>

1. 简单模式
简单理解(一对一): rabbitmq是一个中间件,把他比作一个邮箱:一人传递 一人接收。 简单模式中一人只可以仅有一个接受者(等同于此邮箱是个人专有。)
案例:
发送创建流程: 连接 --建立管道,设置队列----发送
接受创建流程: 连接 --建立管道,设置队列----接受

区别:连接 ,建立管道使用方法一致 :

1.创建连接的工厂: new ConnectionFactory();
2.设置连接的ip,端口,用户名,密码
 setHost(); //ip
 setPort();//端口号
 setUsername();//管理员
 setPassword();//密码
 3.建立管道
 Connection c= 创建连接工厂引用.newConnection().createChannel();
 4.创建队列
 建立管道的引用.queueDeclare("队列名称",(true)(false)持久化,(true)否排他(独占),断开后是(true)(false)删除队列,其他参数若无则填null);
 5.接受和发送的差异主要存在与方法
    发送: 
             建立管道引用.basicPublish("填写交换机 默认写:空字符串" , "队列用户名",其他参数如:头信息  若无则null,消息内容.getBytes());
     接受:(需要创建回调对象)
         1.收到消息后处理消息的回调对象
          	DeliverCallback callback = new DeliverCallback() {
			@Override
			public void handle(String consumerTag, Delivery message) throws IOException {
				String msg = new String(message.getBody(), "UTF-8");
				System.out.println("收到: "+msg);
			}
	     	};
      2.取消消息回调对象
          	CancelCallback cancel = new CancelCallback() {
			@Override
			public void handle(String consumerTag) throws IOException {
			}
		};
       建立管道引用.basicConsume("队列名称",(false)(true)手动ACK消息回执,处理消息对象DeliverCallback ,取消消息回调对象CancelCallback );
  6.关闭通道 
      建立管道引用.close()

发送

package rabbitmq.simple;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;

public class Test1 {
	public static void main(String[] args) throws Exception {

		//创建连接工厂,并设置连接信息
		ConnectionFactory f = new ConnectionFactory();
		f.setHost("192.168.64.140"); //此处是远程调用linux端口
		f.setPort(5672);//可选,5672是默认端口
		f.setUsername("admin"); //用户名
		f.setPassword("admin");

		/*
		 * 与rabbitmq服务器建立连接,
		 * rabbitmq服务器端使用的是nio,会复用tcp连接,
		 * 并开辟多个信道与客户端通信
		 * 以减轻服务器端建立连接的开销
		 */
		 //建立通信管道
		 	Channel c=f.newConnection().createChannel();
		//Connection c = f.newConnection();
		//建立信道
		//Channel ch = c.createChannel();

		/*
		 * 声明队列,会在rabbitmq中创建一个队列
		 * 如果已经创建过该队列,就不能再使用其他参数来创建
		 * 
		 * 参数含义:
		 *   -queue: 队列名称
		 *   -durable: 队列持久化,true表示RabbitMQ重启后队列仍存在
		 *   -exclusive: 排他,true表示限制仅当前连接可用
		 *   -autoDelete: 当最后一个消费者断开后,是否删除队列
		 *   -arguments: 其他参数
		 */
	//	ch.queueDeclare("helloworld", false,false,false,null);
		//若存在直接使用,不存在则会创建
		c.queueDeclare("helloword",//消息队列名称
				false, //是否是持久队列
				false,//是否消费者独占队列 ,false可以共享的队列
				false,//是否自动删除队列(没有消费者自动删除)
				null);//其他参数属性

		/*
		 * 发布消息
		 * 这里把消息向默认交换机发送.
		 * 默认交换机隐含与所有队列绑定,routing key即为队列名称
		 * 
		 * 参数含义:
		 * 	-exchange: 交换机名称,空串表示默认交换机"(AMQP default)",不能用 null 
		 * 	-routingKey: 对于默认交换机,路由键就是目标队列名称
		 * 	-props: 其他参数,例如头信息
		 * 	-body: 消息内容byte[]数组
		 */
		ch.basicPublish("", "helloworld", null, "Hello world!".getBytes());

		System.out.println("消息已发送");
		c.close();  //关闭 
	}
}

接受

package rabbitmq.simple;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
import com.rabbitmq.client.CancelCallback;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.DeliverCallback;
import com.rabbitmq.client.Delivery;

public class Test2 {
	public static void main(String[] args) throws Exception {
		//连接工厂
		ConnectionFactory f = new ConnectionFactory();
		f.setHost("192.168.64.140");
		//此处端口默认 :5672属于默认端口
		f.setUsername("admin");
		f.setPassword("admin");
		//此处可以合并
		//建立连接
		Connection c = f.newConnection();
		//建立信道
		Channel ch = c.createChannel();
		//声明队列,如果该队列已经创建过,则不会重复创建
		ch.queueDeclare("helloworld",false,false,false,null);
		System.out.println("等待接收数据");
		
		//收到消息后用来处理消息的回调对象
		DeliverCallback callback = new DeliverCallback() {
			@Override
			public void handle(String consumerTag, Delivery message) throws IOException {
				String msg = new String(message.getBody(), "UTF-8");
				System.out.println("收到: "+msg);
			}
		};
		
		//消费者取消时的回调对象
		CancelCallback cancel = new CancelCallback() {
			@Override
			public void handle(String consumerTag) throws IOException {
			}
		};
		
		ch.basicConsume("helloworld", true, callback, cancel);
	}
}

2. 工作模式
思想是避免立即执行资源密集型任务
在这里插入图片描述

介绍(一对多):1.多个消费者可以在同一个队列中接受数据。
2. 负载均衡:轮询发送
3. 手动设置ack消息回执,可以知道消费者是空闲还是繁忙
4. 可以设置抓取消息数量 (结合手动Ack使用)
5. 消息的持久化
工作模式
案例

发生的改变:具体的观看简单模式

在简单模式添加的操作: 
1.为了防止消费者挂掉,而导致的数据丢失。 -----手动ACK(系统默认手动ack :false),不通过消费者发送ack给rabbitmq服务器,可以删除此消息。
2.添加消息持久化,队列持久化(在发送的头信息上加入)
3.添加每次抓取信息
修改:

发送:
      1.队列持久化:  
    //第二个参数设置队列持久化
		ch.queueDeclare("task_queue", true,false,false,null);
      2. 消息持久化
	//第三个参数设置消息持久化
			ch.basicPublish("", "task_queue", MessageProperties.PERSISTENT_TEXT_PLAIN, msg.getBytes("UTF-8"));
	
 接受:
 	1.队列持久化:  
 		//第二个参数设置队列持久化
	ch.queueDeclare("task_queue",true,false,false,null);
	2.一次抓取一条信息
	ch.basicQos(1); //一次只接收一条消息
	3.在处理回调函数添加
		//发送回执
		ch.basicAck(message.getEnvelope().getDeliveryTag(), false);
	4.手动ack
			//autoAck设置为false,则需要手动确认发送回执
		ch.basicConsume("task_queue", false, callback, cancel);

发送

package rabbitmq.workqueue;

import java.util.Scanner;

import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.MessageProperties;

public class Test3 {
	public static void main(String[] args) throws Exception {
		ConnectionFactory f = new ConnectionFactory();
		f.setHost("192.168.64.140");
		f.setPort(5672);
		f.setUsername("admin");
		f.setPassword("admin");
		
		Connection c = f.newConnection();
		Channel ch = c.createChannel();
		
		//第二个参数设置队列持久化
		ch.queueDeclare("task_queue", true,false,false,null);

		while (true) {
			System.out.print("输入消息: ");
			String msg = new Scanner(System.in).nextLine();
			if ("exit".equals(msg)) {
				break;
			}
			
			//第三个参数设置消息持久化
			ch.basicPublish("", "task_queue", MessageProperties.PERSISTENT_TEXT_PLAIN, msg.getBytes("UTF-8"));
			System.out.println("消息已发送: "+msg);
		}

		c.close();
	}
}

接受

package rabbitmq.workqueue;

import java.io.IOException;
import java.util.concurrent.TimeoutException;

import com.rabbitmq.client.CancelCallback;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.DeliverCallback;
import com.rabbitmq.client.Delivery;

public class Test4 {
	public static void main(String[] args) throws Exception {
		ConnectionFactory f = new ConnectionFactory();
		f.setHost("192.168.64.140");
		f.setUsername("admin");
		f.setPassword("admin");
		Connection c = f.newConnection();
		Channel ch = c.createChannel();
		
		//第二个参数设置队列持久化
		ch.queueDeclare("task_queue",true,false,false,null);
		
		System.out.println("等待接收数据");
		
		ch.basicQos(1); //一次只接收一条消息
		
		//收到消息后用来处理消息的回调对象
		DeliverCallback callback = new DeliverCallback() {
			@Override
			public void handle(String consumerTag, Delivery message) throws IOException {
				String msg = new String(message.getBody(), "UTF-8");
				System.out.println("收到: "+msg);
				for (int i = 0; i < msg.length(); i++) {
					if (msg.charAt(i)=='.') {
						try {
							Thread.sleep(1000);
						} catch (InterruptedException e) {
						}
					}
				}
				System.out.println("处理结束");
				//发送回执
				ch.basicAck(message.getEnvelope().getDeliveryTag(), false);
			}
		};
		
		//消费者取消时的回调对象
		CancelCallback cancel = new CancelCallback() {
			@Override
			public void handle(String consumerTag) throws IOException {
			}
		};
		
		//autoAck设置为false,则需要手动确认发送回执
		ch.basicConsume("task_queue", false, callback, cancel);
	}
}


3. 发布和订阅模式
RabbitMQ消息传递模型的核心思想是,生产者永远不会将任何消息直接发送到队列。实际上,通常生产者甚至不知道消息是否会被传递到任何队列。
在这里插入图片描述

介绍: 1. 等同于群发:一条消息,可以多个消费者收到。
2.fanout类型交换机:将接受到的所有消息广播给它所知道的所有队列 ,作用可以做日志系统。
何为交换机:交换机可以一边接受一边将消息推送到队列(常见交换机:direct,topic,header,fanout)
3. 你要明白这里会需要不同的队列来接收。

发布订阅模式
案例

1.更换交换机,不使用系统默认的,发布订阅使用fandout
2.为了演示 :创建非持久的、独占的、自动删除队列
3.增加了绑定

发送

package rabbitmq.publishsubscribe;

import java.util.Scanner;

import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;

public class Test1 {
	public static void main(String[] args) throws Exception {
		ConnectionFactory f = new ConnectionFactory();
		f.setHost("192.168.64.140");
		f.setPort(5672);
		f.setUsername("admin");
		f.setPassword("admin");
		
		Connection c = f.newConnection();
		Channel ch = c.createChannel();
		
		//定义名字为logs的交换机,交换机类型为fanout
		//这一步是必须的,因为禁止发布到不存在的交换。

		ch.exchangeDeclare("logs", "fanout");   //定义交换机名称
		//或者使用:
		//ch.exchangeDeclare("logs", BuiltinExchangeType.FANOUT); 
		
		while (true) {
			System.out.print("输入消息: ");
			String msg = new Scanner(System.in).nextLine();
			if ("exit".equals(msg)) {
				break;
			}
			
			//第一个参数,向指定的交换机发送消息
			//第二个参数,不指定队列,由消费者向交换机绑定队列
			//如果还没有队列绑定到交换器,消息就会丢失,
			//但这对我们来说没有问题;即使没有消费者接收,我们也可以安全地丢弃这些信息。
			ch.basicPublish("logs", "", null, msg.getBytes("UTF-8"));
			System.out.println("消息已发送: "+msg);
		}
		c.close();
	}
}

接受

package rabbitmq.publishsubscribe;

import java.io.IOException;

import com.rabbitmq.client.CancelCallback;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.DeliverCallback;
import com.rabbitmq.client.Delivery;

public class Test2 {
	public static void main(String[] args) throws Exception {
		ConnectionFactory f = new ConnectionFactory();
		f.setHost("192.168.64.140");
		f.setUsername("admin");
		f.setPassword("admin");
		Connection c = f.newConnection();
		Channel ch = c.createChannel();
		
		//定义名字为 logs 的交换机, 它的类型是 fanout
		ch.exchangeDeclare("logs", "fanout");
		//或者
				//或者使用:
		//ch.exchangeDeclare("logs", BuiltinExchangeType.FANOUT); 
		//自动生成对列名,
		//非持久,独占,自动删除
		String queueName = ch.queueDeclare().getQueue();//服务器随机命名
		//等同于
       //String queue=  UUID.randomUUID().toString(); //调用UUID随机生成
     //  ch.queueDeclare(queue,false,true,true,null);//为了演示设置了,非持久化,独占,自动删除序列

		

		
		//把该队列,绑定到 logs 交换机
		//对于 fanout 类型的交换机, routingKey会被忽略,不允许null值
		ch.queueBind(queueName, "logs", "");
		
		System.out.println("等待接收数据");
		
		//收到消息后用来处理消息的回调对象
		DeliverCallback callback = new DeliverCallback() {
			@Override
			public void handle(String consumerTag, Delivery message) throws IOException {
				String msg = new String(message.getBody(), "UTF-8");
				System.out.println("收到: "+msg);
			}
		};
		
		//消费者取消时的回调对象
		CancelCallback cancel = new CancelCallback() {
			@Override
			public void handle(String consumerTag) throws IOException {
			}
		};
		
		ch.basicConsume(queueName, true, callback, cancel);
	}
}

4. 路由模式
介绍:根据队列的名称,指定发送到队列。
在这里插入图片描述
在这里插入图片描述
案例

1.需要绑定,需要使用routingKey参数,取决于交换机名字
2.使用直连交换机 DIrect 

发送

package rabbitmq.routing;

import java.util.Random;
import java.util.Scanner;

import com.rabbitmq.client.BuiltinExchangeType;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;

public class Test1 {
	public static void main(String[] args) throws Exception {
		String[] a = {"warning", "info", "error"};
		
		ConnectionFactory f = new ConnectionFactory();
		f.setHost("192.168.64.140");
		f.setPort(5672);
		f.setUsername("admin");
		f.setPassword("admin");
		
		Connection c = f.newConnection();
		Channel ch = c.createChannel();
		
		//参数1: 交换机名
		//参数2: 交换机类型
		ch.exchangeDeclare("direct_logs", BuiltinExchangeType.DIRECT);
		
		while (true) {
			System.out.print("输入消息: ");
			String msg = new Scanner(System.in).nextLine();
			if ("exit".equals(msg)) {
				break;
			}
			
			//随机产生日志级别
			String level = a[new Random().nextInt(a.length)];
			
			//参数1: 交换机名
			//参数2: routingKey, 路由键,这里我们用日志级别,如"error","info","warning"
			//参数3: 其他配置属性
			//参数4: 发布的消息数据 
			ch.basicPublish("direct_logs", level, null, msg.getBytes());//名称,路右键,其他配置,发布信息数据
			System.out.println("消息已发送: "+level+" - "+msg);
			
		}

		c.close();
	}
}


接受

package rabbitmq.routing;

import java.io.IOException;
import java.util.Scanner;

import com.rabbitmq.client.BuiltinExchangeType;
import com.rabbitmq.client.CancelCallback;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.DeliverCallback;
import com.rabbitmq.client.Delivery;

public class Test2 {
	public static void main(String[] args) throws Exception {
		ConnectionFactory f = new ConnectionFactory();
		f.setHost("192.168.64.140");
		f.setUsername("admin");
		f.setPassword("admin");
		Connection c = f.newConnection();
		Channel ch = c.createChannel();
		
		//定义名字为 direct_logs 的交换机, 它的类型是 "direct"
		ch.exchangeDeclare("direct_logs", BuiltinExchangeType.DIRECT);
		
		//自动生成对列名,
		//非持久,独占,自动删除
		String queueName = ch.queueDeclare().getQueue();
		
		System.out.println("输入接收的日志级别,用空格隔开:");
		String[] a = new Scanner(System.in).nextLine().split("\\s");//填写所向队列传递,名称
		
		//把该队列,绑定到 direct_logs 交换机
		//允许使用多个 bindingKey
		for (String level : a) {
			ch.queueBind(queueName, "direct_logs", level);
		}
		
		System.out.println("等待接收数据");
		
		//收到消息后用来处理消息的回调对象
		DeliverCallback callback = new DeliverCallback() {
			@Override
			public void handle(String consumerTag, Delivery message) throws IOException {
				String msg = new String(message.getBody(), "UTF-8");
				String routingKey = message.getEnvelope().getRoutingKey();//随机生成名称
				System.out.println("收到: "+routingKey+" - "+msg);
			}
		};
		
		//消费者取消时的回调对象
		CancelCallback cancel = new CancelCallback() {
			@Override
			public void handle(String consumerTag) throws IOException {
			}
		};
		
		ch.basicConsume(queueName, true, callback, cancel);
	}
}

5. 主题模式
6. RPC模式

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

大众筹码

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值