RabbitMQ(消息中间件)

MQ基本概念

Message Queue(消息队列)。是指在消息的传输过程中保存消息的容器,,多用于分布式系统之间进行通信

分布式系统两种通信方式

远程RPC调用

在这里插入图片描述

引入消息中间件

在这里插入图片描述

小结

  • MQ,消息队列,存储消息的中间件
  • 分布式系统同行两种方式:直接远程调用和借助第三方间接通信
  • 发布方成为生产者,接收方成为消费者。

MQ的优劣

优势

应用解耦:提高系统容错性和可维护性

远程调用带来的下面的耦合
在这里插入图片描述

可以看出这个远程调用带来的问题就是,系统的耦合性高,容错性低。可维护性也低

我们来看看使用中间件的解耦
在这里插入图片描述

使用MQ是的应用间解耦,提升容错性和可维护性

异步提速:提升用户体验与吞吐量

我们来看看这个同步带来的问题
在这里插入图片描述

下单耗时是:20+300+300+300=920ms
用户点击下单按钮以后,需要等待920ms,这样系统的响应时间太长。

我们再来看这个MQ的异步提速
在这里插入图片描述

这里的下单响应时间是:20+5=25ms
不精提高了用户体验和系统的吞吐量

削峰填谷:使用MQ就提高了,系统的稳定性

在这里插入图片描述
在这里插入图片描述

使用了这个MQ之后呢,就限制了消费的速度是1000,这样高峰期产生的数据势必会积压在MQ中,因此削去了高峰,因为消息的积压,为高峰期过后的一段时间内,还是维持在1000,直到消除积压,就叫填谷

劣势

  • 系统可用性降低
    系统引入的外部依赖多系统稳定性就越差,MQ宕机,就会对业务造成影响,因此保证MQ的高可用是问题的关键

  • 系统复杂度提高
    MQ的加入大大提高了系统的复杂度,以前系统间是同步的远程调用,现在是通过MQ进行异步调用,问题的关键就在于:

    • 如何保证消息没有被重复消费?
    • 如何处理消息的丢失情况?
    • 如何保证消息传递的顺序性?
  • 一致性问题
    A处理了业务,通过MQ给BCD业三个系统都发送消息数据,那么如何保证消息数据处理的一致性?

常见MQ

在这里插入图片描述

RabbitMQ的简介与入门

AMQP协议

AMQP:Advanced Message Queuing(高级消息队列协议),是一个网络协议,是应用层协议的一个开放标准,为面向消息的中间件设计。

在这里插入图片描述

JMS

JMS即Java消息服务(JavaMessage Service)应用程序接口,是一个Java平台中关于面向消息中间件(MOM)的API,用于在两个应用程序之间,或分布式系统中发送消息,进行异步通信。

RabbitMQ简介

由ErLang语言开发

基础架构图

在这里插入图片描述

RabbitMQ的入门

安装(这里展示在线安装,屁事少)

# 第一步
rpm --import https://github.com/rabbitmq/signing-keys/releases/download/2.0/rabbitmq-release-signing-key.asc

# 第二步
#=========================================
# centos7 用这个
cat <<EOF > /etc/yum.repos.d/rabbitmq.repo
[bintray-rabbitmq-server]
name=bintray-rabbitmq-rpm
baseurl=https://dl.bintray.com/rabbitmq/rpm/rabbitmq-server/v3.8.x/el/7/
gpgcheck=0
repo_gpgcheck=0
enabled=1
EOF


# centos6 用这个
cat <<EOF > /etc/yum.repos.d/rabbitmq.repo
[bintray-rabbitmq-server]
name=bintray-rabbitmq-rpm
baseurl=https://dl.bintray.com/rabbitmq/rpm/rabbitmq-server/v3.8.x/el/6/
gpgcheck=0
repo_gpgcheck=0
enabled=1
EOF
# ==============================================
# 第三步
yum makecache
# 第四步
yum install socat

#第五步
wget https://github.com/rabbitmq/erlang-rpm/releases/download/v21.3.8.12/erlang-21.3.8.12-1.el7.x86_64.rpm
rpm -ivh erlang-21.3.8.12-1.el7.x86_64.rpm --force --nodeps

# 第六部
yum install rabbitmq-server



启动RabbitMQ服务器

#  设置服务自启动
systemctl enable rabbitmq-server
# 启动服务
systemctl start rabbitmq-server

启用图形化管理界面

# 开启管理界面插件
rabbitmq-plugins enable rabbitmq_management

# 防火墙打开 15672 管理端口(这是一个好习惯)
firewall-cmd --zone=public --add-port=15672/tcp --permanent
firewall-cmd --reload
# 打开客户端连接端口
firewall-cmd --zone=public --add-port=5672/tcp --permanent
firewall-cmd --reload
# 或者关掉防火墙
systemctl stop firewalld.service

主要端口介绍

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

添加用户与重启


# 添加用户(用户名是Admin  密码也是Admin)
rabbitmqctl add_user admin admin

# 新用户设置用户为超级管理员
rabbitmqctl set_user_tags admin administrator


# 重启
systemctl restart rabbitmq-server

有如下界面,完事!

在这里插入图片描述
在这里插入图片描述

RabbitMQ的入门案例(使用工作模式中的简单模式)

项目依赖

    <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>

生产者(Producer)

package org.shu;

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

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

/**
 * 这个类是消息中间的一个生产者
 */
public class Producer {
    public static void main(String[] args) throws IOException, TimeoutException {
        // 1.建立连接(连接工厂)
        ConnectionFactory cf = new ConnectionFactory();
        // 2.设置参数 (虚拟机,用户名 密码 端口 ip...)
        cf.setHost("192.168.126.131");//设置主机
        cf.setPort(5672);//默认5672
        cf.setVirtualHost("/shuyoujing");//默认就是/
        cf.setUsername("shu");
        cf.setPassword("shu");


        // 3. 创建连接(Connection)
        Connection connection = cf.newConnection();
        // 4. 创建管道channel
        Channel channel = connection.createChannel();
        // 5. 创建队列(简单模式不需要交换机)
        /**
         * 参数解析
         * String queue       //队列名称
         * boolean durable    //是否持久化
         * boolean exclusive  //是否独占
         * boolean autoDelete //是否自动删除
         * Map<String, Object> arguments //参数
         */
        //如果没有队列就创建队列
        channel.queueDeclare("hello_world",true,false,false,null);

        // 6. 发送消息
        /**
         * 参数信息
         * (String exchange  //交换机
         * String routingKey // 路由名称 (只要跟队列名一样就可以发送消息)
         * BasicProperties props// 配置信息
         * byte[] body  // 发送消息数据
         */
        String body="舒有敬";
        channel.basicPublish("","hello_world",null,body.getBytes());
        // 7.释放资源
        channel.close();
        connection.close();
    }
}

在这里插入图片描述

消费者(Consumer)

package org.shu;

import com.rabbitmq.client.*;

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

public class Consumer {
    public static void main(String[] args) throws IOException, TimeoutException {
        // 1.建立连接(连接工厂)
        ConnectionFactory cf = new ConnectionFactory();
        // 2.设置参数 (虚拟机,用户名 密码 端口 ip...)
        cf.setHost("192.168.126.131");//设置主机
        cf.setPort(5672);//默认5672
        cf.setVirtualHost("/shuyoujing");//默认就是/
        cf.setUsername("shu");
        cf.setPassword("shu");


        // 3. 创建连接(Connection)
        Connection connection = cf.newConnection();
        // 4. 创建管道channel
        Channel channel = connection.createChannel();
        // 5. 创建队列(简单模式不需要交换机)
        /**
         * 参数解析
         * String queue       //队列名称
         * boolean durable    //是否持久化
         * boolean exclusive  //是否独占
         * boolean autoDelete //是否自动删除
         * Map<String, Object> arguments //参数
         */
        //如果没有队列就创建队列
        channel.queueDeclare("hello_world",true,false,false,null);
        // 6 消费数据
        /**
         *String queue 1.队列名称
         * autoAck     2.是否自动确认
         * callback    3. 回调对象
         */
        DefaultConsumer consumer=new DefaultConsumer(channel){
            @Override                       //
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                System.out.println("标识"+consumerTag);
                System.out.println("交换机"+envelope.getExchange());
                System.out.println("properies"+properties);
                System.out.println("收到的消息:"+new String(body));
            }
        };


        channel.basicConsume("hello_world",true,consumer);
    }

    //不需要释放资源
}

RabbitMQ的工作模式

RabbitMQ 提供了 6 种工作模式

简单模式

上述案例就是

work queues (工作队列)

在这里插入图片描述

  • 多了一个或者多个消费端
  • 多个消费端共同消费一个队列中的小心
  • 对于任务过重的情况使用这个工作地雷可以提高任务处理的速度

Publish/Subscribe (发布与订阅模式)

在这里插入图片描述

交换机(Exchange)

一方面接收生产者发送的消息,另一方面知道如何处理,如何操作取决于交换机的类型:

  • Fanout:广播 将消息给所有绑定到交换机的队列
  • Direct:定向 把消息交给符合指定的Routing key 的队列
  • Topic: 通配符,把消息交给符合Routing pattern

交换机只负责转发消息,不具备消息的存储能力,因此如果没有任何队列与交换机绑定,或者没有符合路由规则的队列,则消息会丢失.

生产者

package org.shu;

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;

/**
 * 这个类是消息中间的一个生产者
 */
public class Producer_PubSub {
    public static void main(String[] args) throws IOException, TimeoutException {
        // 1.建立连接(连接工厂)
        ConnectionFactory cf = new ConnectionFactory();
        // 2.设置参数 (虚拟机,用户名 密码 端口 ip...)
        cf.setHost("192.168.126.131");//设置主机
        cf.setPort(5672);//默认5672
        cf.setVirtualHost("/shuyoujing");//默认就是/
        cf.setUsername("shu");
        cf.setPassword("shu");
        // 3. 创建连接(Connection)
        Connection connection = cf.newConnection();
        // 4. 创建管道channel
        Channel channel = connection.createChannel();
        // 5 创建交换机
        String exchangeName="Test_Fanout";
        channel.exchangeDeclare(exchangeName, BuiltinExchangeType.FANOUT,true,false,false,null);
        // 6创建队列
        String queue1Name="test_fanout_queue1";
        String queue2Name="test_fanout_queue2";
        channel.queueDeclare(queue1Name,true,false,false,null);
        channel.queueDeclare(queue2Name,true,false,false,null);
        //7 绑定队列给交换机
        channel.queueBind(queue1Name,exchangeName,"");
        channel.queueBind(queue2Name,exchangeName,"");
        // 发送消息
        String message="日志信息:---------";
        channel.basicPublish(exchangeName,"",null,message.getBytes());
        // 释放资源
        channel.close();
        connection.close();
    }
}

在这里插入图片描述

消费者


package org.shu;

import com.rabbitmq.client.*;

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

public class Consumer_PubSub1 {
    public static void main(String[] args) throws IOException, TimeoutException {
        // 1.建立连接(连接工厂)
        ConnectionFactory cf = new ConnectionFactory();
        // 2.设置参数 (虚拟机,用户名 密码 端口 ip...)
        cf.setHost("192.168.126.131");//设置主机
        cf.setPort(5672);//默认5672
        cf.setVirtualHost("/shuyoujing");//默认就是/
        cf.setUsername("shu");
        cf.setPassword("shu");


        // 3. 创建连接(Connection)
        Connection connection = cf.newConnection();
        // 4. 创建管道channel
        Channel channel = connection.createChannel();
        // 5. 创建队列(简单模式不需要交换机)
        /**
         * 参数解析
         * String queue       //队列名称
         * boolean durable    //是否持久化
         * boolean exclusive  //是否独占
         * boolean autoDelete //是否自动删除
         * Map<String, Object> arguments //参数
         */
        //如果没有队列就创建队列
        String queue1Name="test_fanout_queue1";
        String queue2Name="test_fanout_queue2";
        channel.queueDeclare(queue1Name,true,false,false,null);
        // 6 消费数据
        /**
         *String queue 1.队列名称
         * autoAck     2.是否自动确认
         * callback    3. 回调对象
         */
        DefaultConsumer consumer=new DefaultConsumer(channel){
            @Override                       //
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                System.out.println("标识"+consumerTag);
                System.out.println("交换机"+envelope.getExchange());
                System.out.println("properies"+properties);
                System.out.println("收到的消息在控制台:"+new String(body));
            }
        };


        channel.basicConsume(queue1Name,true,consumer);
    }

    //不需要释放资源
}

在这里插入图片描述

Routing 路由模式

在这里插入图片描述

  • 队列与交换机的绑定,不能是任意绑定,而是要指定一个RoutingKey(路由Key)
  • 消息的发送方在想Exchange发送消息是,也必然指定消息的RoutingKey
  • Exchange不再把消息交给每一个绑定的队列,而是根据消息的Routing Key进行判断,只有队列的Routing Key与消息的RoutingKey完全一致,才会接受到消息

生产者

package org.shu;

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;

/**
 * 这个类是消息中间的一个生产者
 */
public class Producer_Routing {
    public static void main(String[] args) throws IOException, TimeoutException {
        // 1.建立连接(连接工厂)
        ConnectionFactory cf = new ConnectionFactory();
        // 2.设置参数 (虚拟机,用户名 密码 端口 ip...)
        cf.setHost("192.168.126.131");//设置主机
        cf.setPort(5672);//默认5672
        cf.setVirtualHost("/shuyoujing");//默认就是/
        cf.setUsername("shu");
        cf.setPassword("shu");
        // 3. 创建连接(Connection)
        Connection connection = cf.newConnection();
        // 4. 创建管道channel
        Channel channel = connection.createChannel();
        // 5 创建交换机
        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 绑定队列给交换机
        channel.queueBind(queue1Name,exchangeName,"error");
        channel.queueBind(queue2Name,exchangeName,"info");
        channel.queueBind(queue2Name,exchangeName,"error");
        channel.queueBind(queue2Name,exchangeName,"warning");
        // 发送消息
        String message="日志信息:---------日志级别:error";
        channel.basicPublish(exchangeName,"error",null,message.getBytes());
        // 释放资源
        channel.close();
        connection.close();
    }
}

消费者1(只接受Error路由Key)

package org.shu;

import com.rabbitmq.client.*;

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

public class Consumer_Rounting1 {
    public static void main(String[] args) throws IOException, TimeoutException {
        // 1.建立连接(连接工厂)
        ConnectionFactory cf = new ConnectionFactory();
        // 2.设置参数 (虚拟机,用户名 密码 端口 ip...)
        cf.setHost("192.168.126.131");//设置主机
        cf.setPort(5672);//默认5672
        cf.setVirtualHost("/shuyoujing");//默认就是/
        cf.setUsername("shu");
        cf.setPassword("shu");


        // 3. 创建连接(Connection)
        Connection connection = cf.newConnection();
        // 4. 创建管道channel
        Channel channel = connection.createChannel();
        // 5. 创建队列(简单模式不需要交换机)
        /**
         * 参数解析
         * String queue       //队列名称
         * boolean durable    //是否持久化
         * boolean exclusive  //是否独占
         * boolean autoDelete //是否自动删除
         * Map<String, Object> arguments //参数
         */
        //如果没有队列就创建队列
        String queue1Name="test_direct_queue1";
        String queue2Name="test_direct_queue2";
        channel.queueDeclare(queue1Name,true,false,false,null);
        // 6 消费数据
        /**
         *String queue 1.队列名称
         * autoAck     2.是否自动确认
         * callback    3. 回调对象
         */
        DefaultConsumer consumer=new DefaultConsumer(channel){
            @Override                       //
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                System.out.println("标识"+consumerTag);
                System.out.println("交换机"+envelope.getExchange());
                System.out.println("properies"+properties);
                System.out.println("收到的消息在数据库中:"+new String(body));
            }
        };


        channel.basicConsume(queue1Name,true,consumer);
    }

    //不需要释放资源
}

在这里插入图片描述

消费者2(可以接受3种路由Key)打印在控制台

package org.shu;

import com.rabbitmq.client.*;

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

public class Consumer_Rounting2 {
    public static void main(String[] args) throws IOException, TimeoutException {
        // 1.建立连接(连接工厂)
        ConnectionFactory cf = new ConnectionFactory();
        // 2.设置参数 (虚拟机,用户名 密码 端口 ip...)
        cf.setHost("192.168.126.131");//设置主机
        cf.setPort(5672);//默认5672
        cf.setVirtualHost("/shuyoujing");//默认就是/
        cf.setUsername("shu");
        cf.setPassword("shu");


        // 3. 创建连接(Connection)
        Connection connection = cf.newConnection();
        // 4. 创建管道channel
        Channel channel = connection.createChannel();
        // 5. 创建队列(简单模式不需要交换机)
        /**
         * 参数解析
         * String queue       //队列名称
         * boolean durable    //是否持久化
         * boolean exclusive  //是否独占
         * boolean autoDelete //是否自动删除
         * Map<String, Object> arguments //参数
         */
        //如果没有队列就创建队列
        String queue1Name="test_direct_queue1";
        String queue2Name="test_direct_queue2";
        channel.queueDeclare(queue2Name,true,false,false,null);
        // 6 消费数据
        /**
         *String queue 1.队列名称
         * autoAck     2.是否自动确认
         * callback    3. 回调对象
         */
        DefaultConsumer consumer=new DefaultConsumer(channel){
            @Override                       //
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                System.out.println("标识"+consumerTag);
                System.out.println("交换机"+envelope.getExchange());
                System.out.println("properies"+properties);
                System.out.println("收到的消息在控制台中:"+new String(body));
            }
        };


        channel.basicConsume(queue2Name,true,consumer);
    }

    //不需要释放资源
}

在这里插入图片描述

Topics 主题模式(通配符模式)

在这里插入图片描述

生产者

package org.shu;

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;

/**
 * 这个类是消息中间的一个生产者
 */
public class Producer_Topic {
    public static void main(String[] args) throws IOException, TimeoutException {
        // 1.建立连接(连接工厂)
        ConnectionFactory cf = new ConnectionFactory();
        // 2.设置参数 (虚拟机,用户名 密码 端口 ip...)
        cf.setHost("192.168.126.131");//设置主机
        cf.setPort(5672);//默认5672
        cf.setVirtualHost("/shuyoujing");//默认就是/
        cf.setUsername("shu");
        cf.setPassword("shu");
        // 3. 创建连接(Connection)
        Connection connection = cf.newConnection();
        // 4. 创建管道channel
        Channel channel = connection.createChannel();
        // 5 创建交换机
        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 绑定队列给交换机
        channel.queueBind(queue1Name,exchangeName,"#.error");
        channel.queueBind(queue1Name,exchangeName,"order.*");
        channel.queueBind(queue2Name,exchangeName,"*.*");
        // 发送消息
        String message="日志信息:---------日志级别:NaN";
        channel.basicPublish(exchangeName,"x.x",null,message.getBytes());
        // 释放资源
        channel.close();
        connection.close();
    }
}

消费者1

package org.shu;

import com.rabbitmq.client.*;

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

public class Consumer_Topic1 {
    public static void main(String[] args) throws IOException, TimeoutException {
        // 1.建立连接(连接工厂)
        ConnectionFactory cf = new ConnectionFactory();
        // 2.设置参数 (虚拟机,用户名 密码 端口 ip...)
        cf.setHost("192.168.126.131");//设置主机
        cf.setPort(5672);//默认5672
        cf.setVirtualHost("/shuyoujing");//默认就是/
        cf.setUsername("shu");
        cf.setPassword("shu");


        // 3. 创建连接(Connection)
        Connection connection = cf.newConnection();
        // 4. 创建管道channel
        Channel channel = connection.createChannel();
        // 5. 创建队列(简单模式不需要交换机)
        /**
         * 参数解析
         * String queue       //队列名称
         * boolean durable    //是否持久化
         * boolean exclusive  //是否独占
         * boolean autoDelete //是否自动删除
         * Map<String, Object> arguments //参数
         */
        //如果没有队列就创建队列
        String queue1Name="test_topic_queue1";
        String queue2Name="test_topic_queue2";
        channel.queueDeclare(queue1Name,true,false,false,null);
        // 6 消费数据
        /**
         *String queue 1.队列名称
         * autoAck     2.是否自动确认
         * callback    3. 回调对象
         */
        DefaultConsumer consumer=new DefaultConsumer(channel){
            @Override                       //
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                System.out.println("标识"+consumerTag);
                System.out.println("交换机"+envelope.getExchange());
                System.out.println("properies"+properties);
                System.out.println("收到的消息在数据库中:"+new String(body));
            }
        };


        channel.basicConsume(queue1Name,true,consumer);
    }

    //不需要释放资源
}

消费者2


package org.shu;

import com.rabbitmq.client.*;

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

public class Consumer_Topic2 {
    public static void main(String[] args) throws IOException, TimeoutException {
        // 1.建立连接(连接工厂)
        ConnectionFactory cf = new ConnectionFactory();
        // 2.设置参数 (虚拟机,用户名 密码 端口 ip...)
        cf.setHost("192.168.126.131");//设置主机
        cf.setPort(5672);//默认5672
        cf.setVirtualHost("/shuyoujing");//默认就是/
        cf.setUsername("shu");
        cf.setPassword("shu");


        // 3. 创建连接(Connection)
        Connection connection = cf.newConnection();
        // 4. 创建管道channel
        Channel channel = connection.createChannel();
        // 5. 创建队列(简单模式不需要交换机)
        /**
         * 参数解析
         * String queue       //队列名称
         * boolean durable    //是否持久化
         * boolean exclusive  //是否独占
         * boolean autoDelete //是否自动删除
         * Map<String, Object> arguments //参数
         */
        //如果没有队列就创建队列
        String queue1Name="test_topic_queue1";
        String queue2Name="test_topic_queue2";
        channel.queueDeclare(queue2Name,true,false,false,null);
        // 6 消费数据
        /**
         *String queue 1.队列名称
         * autoAck     2.是否自动确认
         * callback    3. 回调对象
         */
        DefaultConsumer consumer=new DefaultConsumer(channel){
            @Override                       //
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                System.out.println("标识"+consumerTag);
                System.out.println("交换机"+envelope.getExchange());
                System.out.println("properies"+properties);
                System.out.println("收到的消息在控制台中:"+new String(body));
            }
        };


        channel.basicConsume(queue2Name,true,consumer);
    }

    //不需要释放资源
}

RPC 远程调用模式(远程调用)

Spring整合RabbitMQ

创建两个Maven项目

在这里插入图片描述

依赖

<dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.1.7.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.amqp</groupId>
            <artifactId>spring-rabbit</artifactId>
            <version>2.1.8.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>5.1.7.RELEASE</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>

properties文件(与依赖一样,生产者消费者都要有这个)

rabbitmq.host=192.168.126.131
rabbitmq.port=5672
rabbitmq.username=shu
rabbitmq.password=shu
rabbitmq.virtual-host=/shuyoujing

生产者的XML配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:rabbit="http://www.springframework.org/schema/rabbit"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       https://www.springframework.org/schema/context/spring-context.xsd
       http://www.springframework.org/schema/rabbit
       http://www.springframework.org/schema/rabbit/spring-rabbit.xsd
http://www.springframework.org/schema/rabbit ">
    <!--加载配置文件-->
    <context:property-placeholder location="classpath:properties/rabbitmq.properties"/>

    <!-- 定义rabbitmq connectionFactory -->
    <rabbit:connection-factory id="connectionFactory" host="${rabbitmq.host}"
                               port="${rabbitmq.port}"
                               username="${rabbitmq.username}"
                               password="${rabbitmq.password}"
                               virtual-host="${rabbitmq.virtual-host}"/>
    <!--定义管理交换机、队列-->
    <rabbit:admin connection-factory="connectionFactory"/>

    <!--定义持久化队列,不存在则自动创建;不绑定到交换机则绑定到默认交换机
    默认交换机类型为direct,名字为:"",路由键为队列的名称
    -->
    <rabbit:queue id="spring_queue" name="spring_queue" auto-declare="true"/>

    <!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~广播;所有队列都能收到消息~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
    <!--定义广播交换机中的持久化队列,不存在则自动创建-->
    <rabbit:queue id="spring_fanout_queue_1" name="spring_fanout_queue_1" auto-declare="true"/>

    <!--定义广播交换机中的持久化队列,不存在则自动创建-->
    <rabbit:queue id="spring_fanout_queue_2" name="spring_fanout_queue_2" auto-declare="true"/>

    <!--定义广播类型交换机;并绑定上述两个队列-->
    <rabbit:fanout-exchange id="spring_fanout_exchange" name="spring_fanout_exchange" auto-declare="true">
        <rabbit:bindings>
            <rabbit:binding queue="spring_fanout_queue_1"/>
            <rabbit:binding queue="spring_fanout_queue_2"/>
        </rabbit:bindings>
    </rabbit:fanout-exchange>

    <!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~通配符;*匹配一个单词,#匹配多个单词 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
    <!--定义广播交换机中的持久化队列,不存在则自动创建-->
    <rabbit:queue id="spring_topic_queue_star" name="spring_topic_queue_star" auto-declare="true"/>
    <!--定义广播交换机中的持久化队列,不存在则自动创建-->
    <rabbit:queue id="spring_topic_queue_well" name="spring_topic_queue_well" auto-declare="true"/>
    <!--定义广播交换机中的持久化队列,不存在则自动创建-->
    <rabbit:queue id="spring_topic_queue_well2" name="spring_topic_queue_well2" auto-declare="true"/>

    <rabbit:topic-exchange id="spring_topic_exchange" name="spring_topic_exchange" auto-declare="true">
        <rabbit:bindings>
            <rabbit:binding pattern="heima.*" queue="spring_topic_queue_star"/>
            <rabbit:binding pattern="heima.#" queue="spring_topic_queue_well"/>
            <rabbit:binding pattern="itcast.#" queue="spring_topic_queue_well2"/>
        </rabbit:bindings>
    </rabbit:topic-exchange>

    <!--定义rabbitTemplate对象操作可以在代码中方便发送消息-->
    <rabbit:template id="rabbitTemplate" connection-factory="connectionFactory"/>
</beans>

消费者的XML文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:rabbit="http://www.springframework.org/schema/rabbit"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       https://www.springframework.org/schema/context/spring-context.xsd
       http://www.springframework.org/schema/rabbit
       http://www.springframework.org/schema/rabbit/spring-rabbit.xsd">
    <!--加载配置文件-->
    <context:property-placeholder location="classpath:properties/rabbitmq.properties"/>

    <!-- 定义rabbitmq connectionFactory -->
    <rabbit:connection-factory id="connectionFactory" host="${rabbitmq.host}"
                               port="${rabbitmq.port}"
                               username="${rabbitmq.username}"
                               password="${rabbitmq.password}"
                               virtual-host="${rabbitmq.virtual-host}"/>

    <bean id="springQueueListener" class="com.itheima.rabbitmq.listener.SpringQueueListener"/>
<!--    <bean id="fanoutListener1" class="com.itheima.rabbitmq.listener.FanoutListener1"/>-->
<!--    <bean id="fanoutListener2" class="com.itheima.rabbitmq.listener.FanoutListener2"/>-->
<!--    <bean id="topicListenerStar" class="com.itheima.rabbitmq.listener.TopicListenerStar"/>-->
<!--    <bean id="topicListenerWell" class="com.itheima.rabbitmq.listener.TopicListenerWell"/>-->
<!--    <bean id="topicListenerWell2" class="com.itheima.rabbitmq.listener.TopicListenerWell2"/>-->

    <rabbit:listener-container connection-factory="connectionFactory" auto-declare="true">
        <rabbit:listener ref="springQueueListener" queue-names="spring_queue"/>
<!--        <rabbit:listener ref="fanoutListener1" queue-names="spring_fanout_queue_1"/>-->
<!--        <rabbit:listener ref="fanoutListener2" queue-names="spring_fanout_queue_2"/>-->
<!--        <rabbit:listener ref="topicListenerStar" queue-names="spring_topic_queue_star"/>-->
<!--        <rabbit:listener ref="topicListenerWell" queue-names="spring_topic_queue_well"/>-->
<!--        <rabbit:listener ref="topicListenerWell2" queue-names="spring_topic_queue_well2"/>-->
    </rabbit:listener-container>
</beans>

生产者的代码

package org.shu;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import java.nio.channels.Pipe;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:spring-rabbitmq-producer.xml")
public class ProducerTest {
    @Autowired
    private RabbitTemplate template;


    @Test
    public void testHelloWorld(){
        template.convertAndSend("spring_queue","Hello World By Spring ");

    }
    @Test
    public void testFanout(){

        template.convertAndSend("spring_fanout_exchange","","Hello FanOut");
    }
    @Test
    public void testTopic( ){

        template.convertAndSend("spring_topic_exchange","heima.shu.shu","Spring Topci");
    }







}

消费者的代码

提供一个类,实现MessageListener接口
package com.itheima.rabbitmq.listener;

import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageListener;

public class SpringQueueListener implements MessageListener {
    @Override
    public void onMessage(Message message) {
        System.out.println(new String(message.getBody()));
    }
}


测试代码

package org.shu;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:spring-rabbitmq-consumer.xml")
public class ConsumerTest {

    @Test
    public  void test1(){
        boolean flag=true;
        while (true){

        }
    }
}

SpringBoot整合RabbitMQ

创建SpringBoott项目

引入依赖坐标



    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-amqp</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
        </dependency>
    </dependencies>

编写yml文件的配置,基本信息配置

spring:
  rabbitmq:
    host: 192.168.126.131
    port: 5672
    username: admin
    password: admin
    virtual-host: /shushu

生产者:定义交换机,队列以及绑定关机的配置类

package org.shu.config;



import org.springframework.amqp.core.*;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class RabbitConfig {

    public static final String EXCHNAGE_NAME="bootExchange";
    public static final String QUEUE_NAME="bootQueue";
    //1. 定义交换机 Exchange
    @Bean("exchange")
    public Exchange getExchange(){
        return ExchangeBuilder.topicExchange(EXCHNAGE_NAME).durable(true).build();
    }
    //2. 定义队列 Queue
    @Bean("queue")
    public Queue getQueue(){
        return QueueBuilder.durable(QUEUE_NAME).build();
    }
    //3. 绑定交换机 Bingding

    /**
     * 知道队列
     * 知道交换机
     * routingkey
     * @return
     */
    @Bean
    public Binding binding(@Qualifier("queue") Queue queue,@Qualifier("exchange") Exchange exchange){
        return BindingBuilder.bind(queue).to(exchange).with("boot.#").noargs();
    }
}

注入RabbitTemplate调用方法完成消息队列

测试类

package org.shu.test;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.shu.config.RabbitConfig;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

@SpringBootTest
@RunWith(SpringRunner.class)
public class ProducerTest {
    @Autowired
    private RabbitTemplate rabbitTemplate;
    @Test
    public void testSend(){
        rabbitTemplate.convertAndSend(RabbitConfig.EXCHNAGE_NAME,"boot.hh","这是SpringBoot整合给出的消息");
    }
}

消费者获取数据

package org.shu.comsumerspringboot.listener;

import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;

@Component
public class RabbitListeners {
    @RabbitListener(queues = "bootQueue")
    public void GetMessage(Message message){
        System.out.println(new String(message.getBody()));
    }

}

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值