目录
基本概念
MQ 的优势
1.应用解耦
2.异步提速
3.削峰填谷
MQ 的劣势
使用mq的条件
常见MQ产品
RabbitMQ简介
RabbitMQ的六种工作模式
JMS
RabbitMQ安装和配置。
RabbitMQ控制台使用。
RabbitMQ快速入门——生产者
需求:
RabbitMQ快速入门——消费者
小结
基本概念
多个系统之间的通信方式有两种,一是直接远程调用,二是通过第三方,mq就是这个第三方
MQ 的优势
1.应用解耦
一个好的系统肯定会要求高内聚低耦合。
像下面这个,订单系统发个订单到库存时,如果库存系统损坏了可能会连带影响订单系统。
有了mq之后,消息存放在mq里面,哪怕库存坏了几分钟,好了之后也可以从mq中接着拿消息出来。
还有一个时,如果要添加一个新的x系统,一般要修改订单系统的代码来兼容。
有了mq之后,订单系统会把所有消息都放到mq里面,新的系统的不管是什么都从mq里面拿东西就好了,就不需要改代码了
2.异步提速
同步下需要走完整个流程才能有反馈,所以很慢。
异步下,即使没有运行完整个流程,也会立刻返回消息,后面的系统会继续从mq中取出消息执行。这种属于是骗人
3.削峰填谷
瞬时请求太多致使服务器宕机了。
mq在这里只是缓存消息和发布消息,不负责业务逻辑处理,因此完全可以承载更多的请求。
如果一层mq解决不了,那就再加一层。
使用mq技术在项目里面之后这些优势可以作为项目亮点写在简历上。
MQ 的劣势
使用mq的条件
常见MQ产品
RabbitMQ简介
RabbitMQ支持AMQP协议,
在AMQP中,交换机分发消息,queue存储消息。分发通过Routes进行 。
RabbitMq里面RabbitMQ Server作为服务端,生产者和消费者都是作为客户端,通过tcp连接和服务端进行通信。如果每一次通信都建立tcp连接资源消耗极大,故这里Connection作为一个连接池,里面有许多管道,通过channel进行通信,这样可以节约资源。
RabbitMq中有很多虚拟机,每个虚拟机里面有很多Exchange和Queue,交换机可以绑定到不同的队列上,Binding就是交换价绑定到队列上的过程。
RabbitMQ的六种工作模式
生产消息和消费消息的工作方式
JMS
类比jdbc是java程序和数据库通信的接口,JMS就是java程序和消息队列通信的接口。
RabbitMQ安装和配置。
在云服务器上直接安装docker版本的就可以了。
Downloading and Installing RabbitMQ — RabbitMQ
docker run -it --rm --name rabbitmq -p 5672:5672 -p 15672:15672 rabbitmq:3.12-management
运行如下所示
安装好后通过IP+端口访问管理界面。
管理界面端口是15672,tcp连接的端口是5672。
账号密码都是guest
RabbitMQ控制台使用。
在控制台可以看见有一个Overview概览,Connection连接,channels通道,Exchanges交换机,Queues,和Admin,Admin中可以管理用户和虚拟机等
这里新建了一个超级用户yhy和一个虚拟机itcast授权给yhy。
有了管理员权限就可以用新用户的账号密码登录了。
RabbitMQ快速入门——生产者
需求:
在idea中创建一个新的空工程,添加两个maven模块。
然后再在两个工程里面分别导入rabbitMQ的依赖和编译的版本插件。
<dependencies><!--rabbitmq的java客户端--><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>
有基本架构图和简单工作模式的图可得以下流程。因为简单模式中没有交换机,所以这里不涉及交换机的创建。
//发送消息
public class producer {public static void main(String[] args) throws IOException, TimeoutException {//1.创建连接工厂ConnectionFactory factory=new ConnectionFactory();//2.设置参数factory.setHost("XXX.XX.XXX.XXX"); //设置ip地址。默认为127.0.0.1factory.setPort(5672); //端口 默认值5672factory.setVirtualHost("/itcast"); //设置虚拟机 默认值/factory.setUsername("yhy"); //用户名,默认值guestfactory.setPassword("XXXXXX"); //密码,默认值guest//3.创建连接ConnectionConnection connection = factory.newConnection();//4.创建ChannelChannel channel = connection.createChannel();//5.创建队列Queue/*queueDeclare(String queue, boolean durable, boolean exclusive, boolean autoDelete, Map<String, Object> arguments)参数:1.queue:队列名称2.durable:是否持久化,当mq重启之后,还在3.exclusive:*是否独占。只能有一个消费者监听这队列*当Connection关闭时,是否删除队列4.autoDelete: 是否自动删除。当没有Consumer时,自动删除掉5.arguments:参数。*///如果没有一个名叫hello_yhy的队列,则会自动创建一个channel.queueDeclare("hello_yhy",true,false,false,null);//6.发送消息/*basicPublish(String exchange, String routingKey, AMQP.BasicProperties props, byte[] body)参数:1.exchange:交换机名称。简单模式下交换机会使用默认的""。2.routerKey:路由名称。3.props:配置信息4.body:发送消息数据*/String body="hello rabbitmq!!!";channel.basicPublish("","hello_yhy",null,body.getBytes());//7.释放资源channel.close();connection.close();}
}
在控制台中可以看见现在没有一个队列。
运行完之后可以看见hello_yhy队列出现了。
但是没有新的Connection和channel出现,因为最后关闭了,如果代码最后不关闭就会出现。
然后程序不同就会显示一直running。
RabbitMQ快速入门——消费者
与生产者非常类似。
但是由上图可知,创建channel的参数虽然一样,但是是不同的channel.
在写生产者时已经有一个队列了,所以再创建一次也没有问题
目前队列中有两条消息。
public class consumer {public static void main(String[] args) throws IOException, TimeoutException {//1.创建连接工厂ConnectionFactory factory=new ConnectionFactory();//2.设置参数factory.setHost("XXX.XX.XXX.XXX"); //设置ip地址。默认为127.0.0.1factory.setPort(5672); //端口 默认值5672factory.setVirtualHost("/itcast"); //设置虚拟机 默认值/factory.setUsername("yhy"); //用户名,默认值guestfactory.setPassword("XXXXXX"); //密码,默认值guest//3.创建连接ConnectionConnection connection = factory.newConnection();//4.创建ChannelChannel channel = connection.createChannel();//5.创建队列Queue/*queueDeclare(String queue, boolean durable, boolean exclusive, boolean autoDelete, Map<String, Object> arguments)参数:1.queue:队列名称2.durable:是否持久化,当mq重启之后,还在3.exclusive:*是否独占。只能有一个消费者监听这队列*当Connection关闭时,是否删除队列4.autoDelete: 是否自动删除。当没有Consumer时,自动删除掉5.arguments:参数。*///如果没有一个名叫hello_yhy的队列,则会自动创建一个channel.queueDeclare("hello_yhy",true,false,false,null);/** basicConsume(String queue, boolean autoAck, Consumer callback)* 参数:* 1.队列名称* 2.autoAck:是否自动确认* 3.callback:回调对象* *///6.接收消息Consumer consumer=new DefaultConsumer(channel){/** 回调方法,当收到消息后,会自动执行该方法* 1.consumerTag:标识* 2.envelope :获取一些信息,交换机,路由key...* 3.properties: 配置信息* 4.body: 数据* */@Overridepublic 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));}};channel.basicConsume("hello_yhy",true,consumer);//不需要关闭资源}
}
运行消费者代码之后
可以看见雀氏取出了两条消息。并且控制台看见已经没有消息了。