RabbitMq详细入门学习介绍一

版权声明:学海无涯..活到老,学到老,遇一知心人终老... https://blog.csdn.net/qq_30764991/article/details/80571806

RabbitMQ是一个开源的,实现AMQP协议的,可复用企业消息队列系统。

类似的系统还有ActiveMQ(实现JMS)和Kafka(分布式)。RabbitMQ支持主流的操作系统,支持多种开发语言,能降低系统间访问的耦合度,便于数据同步。

RabbitMQ提供如下5种队列模型(远程调用不是消息队列)。

1.Simple

2.Work. 工作模式,一个消息只能被一个消费者获取。

          

3.Publish/Subscribe. 订阅模式,消息被路由投递给多个队列,一个消息被多个消费者获取。ExchangeType为fanout。

4.Routing. 路由模式,一个消息被多个消费者获取。并且消息的目的queue可被生产者指定。ExchangeType为direct。

5.Topic. 通配符模式,一个消息被多个消费者获取。消息的目的queue可用BindingKey以通配符(#:一个或多个词,*:一个词)的方式指定。ExchangeType为topic。

  

6.PRC. 远程调用

 

 

相关名词:
1. Server:RabbitMQ服务器,
2. VirtualHost:权限控制的基本单位,一个VirtualHost里面有若干Exchange和MessageQueue,以及指定被哪些user使用。
3. Connection:生产者/消费者和RabbitMQ服务器的TCP连接。
4. Channel:创建完Connection后,需创建信道才能执行AMQP命令。一个Connection可以创建多个Channel。
5. Exchange:路由。接受生产者发送的消息,并根据Binding规则将消息路由给服务器中的队列。ExchangeType有fanout、direct和topic三种,对应路由使用上述3/4/5号模型。
6. (Message)Queue:消息队列,用于存储还未被消费者消费的消息。
7. Message:由Header和Body组成。Header是生产者添加的相关属性:是否持久化、被哪个MessageQueue接收、优先级等。而Body是传输的数据。
8. Binding:消息被复制传递时,一个消费者对应一个消息队列,消费者绑定MessageQueue到Exchange,可指定多个Bindingkey。生产者在发送Message时,可以在header指定RoutingKey,Exchange匹配RoutingKey和Bindingkey将Message路由到相应的Queue。

9. Command:AMQP命令,生产者/消费者通过Command完成与RabbitMQ服务器交互。Publish:发送消息,txSelect:开启事务,txCommit:提交事务。

以下是具体的实例介绍,如果对你有帮助,请记得赞赏:一分也是爱!哈哈

我这里是基于maven与spring对rabbitmq的整合学习,所以前提需要你有这个相关的基础才能看得懂。

那么首先这里创建一个maven项目。

一,天才第一步,导入依赖库,以下是pom中的依赖。

<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.learn.rabbitmq</groupId>
<artifactId>spring-rabbitmq</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<description>这是一个spring与rabbitmq的整合学习案例!</description>
<!-- rabbitmq客户端 -->
<dependencies>
<dependency>
<groupId>com.rabbitmq</groupId>
<artifactId>amqp-client</artifactId>
<version>3.4.1</version>
</dependency>
<!--sl4j日志依赖 -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.7</version>
</dependency>
<!-- commons工具依赖 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.3.2</version>
</dependency>
<!--spring与rabbitmq整合依赖 -->
<dependency>
<groupId>org.springframework.amqp</groupId>
<artifactId>spring-rabbit</artifactId>
<version>1.4.0.RELEASE</version>
</dependency>


</dependencies>

</project>

二,建立一个log4j.propertie日志具体如下:

log4j.rootLogger=DEBUG,A1
log4j.logger.com.taotao = DEBUG
log4j.logger.org.mybatis = DEBUG


log4j.appender.A1=org.apache.log4j.ConsoleAppender
log4j.appender.A1.layout=org.apache.log4j.PatternLayout

log4j.appender.A1.layout.ConversionPattern=%-d{yyyy-MM-dd HH:mm:ss,SSS} [%t] [%c]-[%p] %m%n

三:那么以上准备工作做好,就开始代码的编写:

首先创建工厂类,获取Connection

public class ConnectionUtil {
public static Connection getConnection() throws Exception {
// 定义连接工厂
ConnectionFactory factory = new ConnectionFactory();
// 设置服务地址
factory.setHost("localhost");
// 端口号
factory.setPort(5672);
// 设置账号信息,用户名、密码、vhost
factory.setVirtualHost("/mystore");//请注意,这个是在http://127.0.0.1:15672/#/users/learn中设置的vhost,类似一个仓库
factory.setUsername("learn");
factory.setPassword("learn");
// 通过工程获取连接
Connection connection = factory.newConnection();
return connection;
}

}

队列模式一:简单模式

生产者:

public class Send {

private final static String QUEUE_NAME = "test_queue";

public static void main(String[] argv) throws Exception {
// 获取到连接以及mq通道
Connection connection = ConnectionUtil.getConnection();
// 从连接中创建通道
Channel channel = connection.createChannel();
// 声明(创建)队列
channel.queueDeclare(QUEUE_NAME, false, false, false, null);
// 消息内容
String message = "Hello World!";
channel.basicPublish("", QUEUE_NAME, null, message.getBytes());
System.out.println(" [x] Sent '" + message + "'");


// 关闭通道和连接
channel.close();
connection.close();
}
}

消费者:

public class Recv {
    private final static String QUEUE_NAME = "test_queue";
    public static void main(String[] argv) throws Exception {
        // 获取到连接以及mq通道
        Connection connection = ConnectionUtil.getConnection();
        Channel channel = connection.createChannel();
        // 声明队列
        channel.queueDeclare(QUEUE_NAME, false, false, false, null);
        // 定义队列的消费者
        QueueingConsumer consumer = new QueueingConsumer(channel);
        // 监听队列
        channel.basicConsume(QUEUE_NAME, true, consumer);
        // 获取消息
        while (true) {
            QueueingConsumer.Delivery delivery = consumer.nextDelivery();
            String message = new String(delivery.getBody());
            System.out.println(" [x] Received '" + message + "'");
        }
    }

}

2.Work

生产者

复制代码
public class Send {

    private final static String QUEUE_NAME = "queue_work";

    public static void main(String[] argv) throws Exception {
        Connection connection = ConnectionUtil.getConnection();
        Channel channel = connection.createChannel();

        // 声明队列
        channel.queueDeclare(QUEUE_NAME, false, false, false, null);

        for (int i = 0; i < 50; i++) {
            String message = "" + i;
            channel.basicPublish("", QUEUE_NAME, null, message.getBytes());

            Thread.sleep(i * 10);
        }

        channel.close();
        connection.close();
    }
}
复制代码

 

消费者1

复制代码
public class Recv1 {

    private final static String QUEUE_NAME = "queue_work";

    public static void main(String[] argv) throws Exception {

        Connection connection = ConnectionUtil.getConnection();
        Channel channel = connection.createChannel();
        channel.queueDeclare(QUEUE_NAME, false, false, false, null);

        // 开启Qos, 同一时刻服务器只发送一条消息. 可以尝试注释该行, 会发现消息会被平均分配给两个消费者
        channel.basicQos(1);

        QueueingConsumer consumer = new QueueingConsumer(channel);
        channel.basicConsume(QUEUE_NAME, false, consumer);
        while (true) {
            QueueingConsumer.Delivery delivery = consumer.nextDelivery();
            String message = new String(delivery.getBody());
            System.out.println("获取:" + message);
            // 模拟handling
            Thread.sleep(100);
            // 手动确认消息接收. 在basicConsume方法中, true为自动, false为手动
            /* 消息确认方式: 
             * 1. 自动确认. 只要消息从队列中移除, 服务端认为消息被成功消费
             * 2. 手动确认. 消费者获取消息后, 服务器将该消息标记为不可用, 并等待反馈. 如果消费者一直不反馈, 则该消息将一直处于不可用状态
             */
            channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false);
        }
    }
}
复制代码

消费者2

复制代码
public class Recv2 {

    private final static String QUEUE_NAME = "queue_work";

    public static void main(String[] argv) throws Exception {

        Connection connection = ConnectionUtil.getConnection();
        Channel channel = connection.createChannel();

        channel.queueDeclare(QUEUE_NAME, false, false, false, null);

        channel.basicQos(1);

        QueueingConsumer consumer = new QueueingConsumer(channel);
        channel.basicConsume(QUEUE_NAME, false, consumer);
        while (true) {
            QueueingConsumer.Delivery delivery = consumer.nextDelivery();
            String message = new String(delivery.getBody());
            System.out.println(" [x] Received '" + message + "'");
            // 模拟handling
            Thread.sleep(200);
            // ACK
            channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false);
        }
    }
}
复制代码

 

3.Publish/Subscribe

生产者

复制代码
public class Send {

    private final static String EXCHANGE_NAME = "exchange_fanout";

    public static void main(String[] argv) throws Exception {
        Connection connection = ConnectionUtil.getConnection();
        Channel channel = connection.createChannel();

        // 声明exchange
        channel.exchangeDeclare(EXCHANGE_NAME, "fanout");

        // 消息内容
        String message = "Hello world";
        // 与前面不同, 生产者将消息发送给exchange, 而非队列. 若发消息时还没消费者绑定queue与该exchange, 消息将丢失
        channel.basicPublish(EXCHANGE_NAME, "", null, message.getBytes());
        channel.close();
        connection.close();
    }
}
复制代码

消费者1

复制代码
public class Recv1 {

    private final static String QUEUE_NAME = "queue_fanout_1";
    private final static String EXCHANGE_NAME = "exchange_fanout";

    public static void main(String[] argv) throws Exception {

        Connection connection = ConnectionUtil.getConnection();
        Channel channel = connection.createChannel();
        channel.queueDeclare(QUEUE_NAME, false, false, false, null);

        // 绑定队列到交换机. 绑定也可在rabbitMQ的管理界面进行
        channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "");

        channel.basicQos(1);
        QueueingConsumer consumer = new QueueingConsumer(channel);
        channel.basicConsume(QUEUE_NAME, false, consumer);

        while (true) {
            QueueingConsumer.Delivery delivery = consumer.nextDelivery();
            String message = new String(delivery.getBody());
            System.out.println("获取:" + message);
            Thread.sleep(100);
            channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false);
        }
    }
}
复制代码

消费者2

复制代码
public class Recv2 {

    private final static String QUEUE_NAME = "queue_fanout_2";
    private final static String EXCHANGE_NAME = "exchange_fanout";

    public static void main(String[] argv) throws Exception {

        Connection connection = ConnectionUtil.getConnection();
        Channel channel = connection.createChannel();
        channel.queueDeclare(QUEUE_NAME, false, false, false, null);

        // 绑定队列到交换机
        channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "");

        channel.basicQos(1);
        QueueingConsumer consumer = new QueueingConsumer(channel);
        channel.basicConsume(QUEUE_NAME, false, consumer);

        while (true) {
            QueueingConsumer.Delivery delivery = consumer.nextDelivery();
            String message = new String(delivery.getBody());
            System.out.println("获取:" + message);
            Thread.sleep(200);
            channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false);
        }
    }
}
复制代码

 

4.Routing

生产者

复制代码
public class Send {

    private final static String EXCHANGE_NAME = "exchange_direct";

    public static void main(String[] argv) throws Exception {
        Connection connection = ConnectionUtil.getConnection();
        Channel channel = connection.createChannel();

        // 声明exchange
        channel.exchangeDeclare(EXCHANGE_NAME, "direct");

        String message = "Hello world";
        // 发送消息, RoutingKey为 insert
        channel.basicPublish(EXCHANGE_NAME, "insert", null, message.getBytes());

        channel.close();
        connection.close();
    }
}
复制代码

消费者1

复制代码
public class Recv1 {

    private final static String QUEUE_NAME = "queue_direct_1";
    private final static String EXCHANGE_NAME = "exchange_direct";

    public static void main(String[] argv) throws Exception {

        Connection connection = ConnectionUtil.getConnection();
        Channel channel = connection.createChannel();
        channel.queueDeclare(QUEUE_NAME, false, false, false, null);
        // 绑定队列到交换机, BindingKey为 delete update
        channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "update");
        channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "delete");

        channel.basicQos(1);
        QueueingConsumer consumer = new QueueingConsumer(channel);
        channel.basicConsume(QUEUE_NAME, false, consumer);

        while (true) {
            QueueingConsumer.Delivery delivery = consumer.nextDelivery();
            String message = new String(delivery.getBody());
            System.out.println("获取:" + message);
            Thread.sleep(100);
            channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false);
        }
    }
}
复制代码

消费者2

复制代码
public class Recv2 {

    private final static String QUEUE_NAME = "queue_direct_2";
    private final static String EXCHANGE_NAME = "exchange_direct";

    public static void main(String[] argv) throws Exception {

        Connection connection = ConnectionUtil.getConnection();
        Channel channel = connection.createChannel();
        channel.queueDeclare(QUEUE_NAME, false, false, false, null);

        // 绑定队列到交换机, BindingKey为 insert delete update
        channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "insert");
        channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "update");
        channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "delete");

        channel.basicQos(1);
        QueueingConsumer consumer = new QueueingConsumer(channel);
        channel.basicConsume(QUEUE_NAME, false, consumer);

        while (true) {
            QueueingConsumer.Delivery delivery = consumer.nextDelivery();
            String message = new String(delivery.getBody());
            System.out.println("获取:" + message);
            Thread.sleep(200);
            channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false);
        }
    }
}
复制代码

 

5.Topic

生产者

复制代码
public class Send {

    private final static String EXCHANGE_NAME = "exchange_topic";

    public static void main(String[] argv) throws Exception {
        Connection connection = ConnectionUtil.getConnection();
        Channel channel = connection.createChannel();

        // 声明exchange
        channel.exchangeDeclare(EXCHANGE_NAME, "topic");

        String message = "Hello world";
        // 发送消息, 指定RoutingKey
        channel.basicPublish(EXCHANGE_NAME, "item.delete", null, message.getBytes());

        channel.close();
        connection.close();
    }
}
复制代码

消费者1

复制代码
public class Recv1 {

    private final static String QUEUE_NAME = "queue_topic_1";
    private final static String EXCHANGE_NAME = "exchange_topic";

    public static void main(String[] argv) throws Exception {

        Connection connection = ConnectionUtil.getConnection();
        Channel channel = connection.createChannel();
        channel.queueDeclare(QUEUE_NAME, false, false, false, null);

        // 绑定队列到交换机
        channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "item.update");
        channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "item.delete");

        channel.basicQos(1);
        QueueingConsumer consumer = new QueueingConsumer(channel);
        channel.basicConsume(QUEUE_NAME, false, consumer);
        
        while (true) {
            QueueingConsumer.Delivery delivery = consumer.nextDelivery();
            String message = new String(delivery.getBody());
            System.out.println("获取:" + message);
            Thread.sleep(100);
            channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false);
        }
    }
}
复制代码

消费者2

复制代码
public class Recv2 {

    private final static String QUEUE_NAME = "queue_topic_2";

    private final static String EXCHANGE_NAME = "exchange_topic";

    public static void main(String[] argv) throws Exception {

        Connection connection = ConnectionUtil.getConnection();
        Channel channel = connection.createChannel();
        channel.queueDeclare(QUEUE_NAME, false, false, false, null);

        // 绑定队列到交换机. 通配符!
        channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "item.#");

        channel.basicQos(1);
        QueueingConsumer consumer = new QueueingConsumer(channel);
        channel.basicConsume(QUEUE_NAME, false, consumer);

        while (true) {
            QueueingConsumer.Delivery delivery = consumer.nextDelivery();
            String message = new String(delivery.getBody());
            System.out.println("获取:'" + message);
            Thread.sleep(200);
            channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false);
        }
    }
}

源码已经开源:

源码下载地址:https://github.com/oneboat/spring-rabbitmq

阅读更多

没有更多推荐了,返回首页