RabbitMQ入门

  • 1 安装和启动
  • 1.1 erlang安装
  • 1.2 RabbitMQ安装及启动
  • 2 Java代码示例
  • 2.1 静态工厂类——获取连接
  • 2.2 RabbitMQ消费者线程类
  • 2.3 RabbitMQ生产者线程类
  • 2.4 测试实例
  • 参考链接


1 安装和启动

1.1 erlang安装

RabbitMQ 是由 Erlang语言编写的,在安装RabbitMQ 之前需要安装 Erlang。Erlang 官网下载:http://www.erlang.org/downloads

windows下安装erlang后,需要配置erlang的环境变量:

ERLANG_HOME:C:\szh\erl
Path:;%ERLANG_HOME%\bin

接着在cmd命令窗口输入"erl",若安装配置erlang成功,会显示erlang的版本信息。

1.2 RabbitMQ安装及启动

RabbitMQ官网下载:https://www.rabbitmq.com/install-rpm.html

windows下安装RabbitMQ后,需要配置环境变量:

RABBITMQ_SERVER:C:\szh\RabbitMQ Server\rabbitmq_server
Path:;%RABBITMQ_SERVER%\sbin

RabbitMQ的相关启动命令如下:

1、以应用方式启动

rabbitmq-server -detached // 后台启动
rabbitmq-server 直接启动,// 如果你关闭窗口或者需要在改窗口使用其他命令时应用就会停止
rabbitmqctl stop // 关闭

2、以服务方式启动(安装完之后在任务管理器中服务一栏能看到RabbtiMq)

rabbitmq-service install // 安装服务
rabbitmq-service start // 开始服务
Rabbitmq-service stop  // 停止服务
Rabbitmq-service enable // 使服务有效
Rabbitmq-service disable // 使服务无效
rabbitmq-service help // 帮助
rabbitmqctl stop // 关闭

当rabbitmq-service install之后默认服务是enable的,如果这时设置服务为disable的话,rabbitmq-service start就会报错。
当rabbitmq-service start正常启动服务之后,使用disable是没有效果的。

3、Rabbitmq 管理插件启动,可视化界面

Rabbitmq 管理插件启动,可视化界面
rabbitmq-plugins enable rabbitmq_management // 启动
rabbitmq-plugins disable rabbitmq_management // 关闭

启动可视化界面后,在浏览器输入"ip地址:15672"可进入可视化界面。

4、Rabbitmq节点管理方式

Rabbitmqctl

2 Java代码示例

RabbitMQ的默认用户名和密码是guest:guest,默认传递消息的端口为5672,下面的代码是直接在本地测试,故访问地址为127.0.0.1
下面通过建立多个线程来模拟消息的生产和消费。

2.1 静态工厂类——获取连接

这里创建了一个静态工厂来获取连接,可以直接调用getConnection方法获取

class RabbitMQFactory{

    // RabbitMQ的IP
    private final static String MQ_HOST = "127.0.0.1";
    // RabbitMQ的端口
    private final static Integer MQ_PORT = 5672;
    // RabbitMQ的用户名
    private final static String USER_NAME = "guest";
    // RabbitMQ的密码
    private final static String PASSWORD = "guest";
    // RabbitMQ工厂类
    private final static ConnectionFactory connectionFactory = new ConnectionFactory();

    static{
        // 设置RabbitMQ连接参数
        connectionFactory.setHost(MQ_HOST);
        connectionFactory.setPort(MQ_PORT);
        connectionFactory.setUsername(USER_NAME);
        connectionFactory.setPassword(PASSWORD);
    }

    // 获取连接
    public static Connection getConnection() throws IOException {
        // 建立连接
        Connection connection = connectionFactory.newConnection();
        return connection;
    }

}

2.2 RabbitMQ消费者线程类

class Consumer implements Runnable{

    // RabbitMQ队列名称
    private String queueName;

    public Consumer(String queueName){
        this.queueName = queueName;
    }

    public void run() {
        Connection connection = null;
        Channel channel = null;
        try {
            // 创建连接
            connection = RabbitMQFactory.getConnection();
            // 创建连接通道
            channel = connection.createChannel();
            /*
             声明要连接的队列
             参数说明:
                1、name: 队列名称
                2、durable: 是否持久化,为 true 则设置队列为持久化。持久化的队列会存盘,在服务器重启的时候可以保证不丢失相关信息。
                3、exclusive: 是否排外的,为 true 则设置队列为排他的。如果一个队列被声明为排 他队列,该队列仅对首次声明它的连接可见,并在连接断开时自动删除。这里需要注意 三点:排他队列是基于连接( Connection) 可见的,同 个连接的不同信道 (Channel) 是可以同时访问同一连接创建的排他队列; "首次"是指如果 个连接己经声明了 排他队列,其他连接是不允许建立同名的排他队列的,这个与普通队列不同:即使该队 列是持久化的,一旦连接关闭或者客户端退出,该排他队列都会被自动删除,这种队列 适用于一个客户端同时发送和读取消息的应用场景。
                4、autoDelete: 是否自动删除队列,为 true 则设置队列为自动删除。自动删除的前提是: 至少有一个消费者连接到这个队列,之后所有与这个队列连接的消费者都断开时,才会 自动删除。不能把这个参数错误地理解为: "当连接到此队列的所有客户端断开时,这 个队列自动删除",因为生产者客户端创建这个队列,或者没有消费者客户端与这个队 列连接时,都不会自动删除这个队列。
                5、args: 相关参数,如 x-rnessage-ttl 、x-expires 、x-rnax-length 、x-rnax-length-bytes、 x-dead-letter-exchange、 x-deadletter-routing-key 、 x-rnax-priority 等。
             */
            channel.queueDeclare(queueName, false, false, false, null);
            // 创建消费者对象,用于读取消息
            QueueingConsumer queueingConsumer = new QueueingConsumer(channel);
            /**
             * 启动一个消费者,并返回服务端生成的消费者标识
             * queue:队列名
             * autoAck:true 接收到传递过来的消息后acknowledged(应答服务器),false 接收到消息后不应答服务器
             * callback: 消费者对象的回调接口
             * @return 服务端生成的消费者标识
             */
            channel.basicConsume(queueName, true, queueingConsumer);
            while (true){
                // 读取队列,在读到消息前再这里阻塞,直到等到消息
                QueueingConsumer.Delivery delivery = queueingConsumer.nextDelivery();
                String message = new String(delivery.getBody());
                System.out.println("消费者" + Thread.currentThread().getName() + "收到消息:" + message);
                // 模拟执行处理消息时间
                Thread.sleep(3000);

                System.out.println("消费者" + Thread.currentThread().getName() + "处理完消息:" + message);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            /* 关闭连接 */
            try {
                channel.close();
                connection.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

}

channel.queueDeclare(name, durable, exclusive, autoDelete, args)方法参数说明:
1、name: 队列名称
2、durable: 是否持久化,为 true 则设置队列为持久化。持久化的队列会存盘,在服务器重启的时候可以保证不丢失相关信息。
3、exclusive: 是否排外的,为 true 则设置队列为排他的。如果一个队列被声明为排 他队列,该队列仅对首次声明它的连接可见,并在连接断开时自动删除。这里需要注意 三点:排他队列是基于连接( Connection) 可见的,同 个连接的不同信道 (Channel) 是可以同时访问同一连接创建的排他队列; "首次"是指如果 个连接己经声明了 排他队列,其他连接是不允许建立同名的排他队列的,这个与普通队列不同:即使该队 列是持久化的,一旦连接关闭或者客户端退出,该排他队列都会被自动删除,这种队列 适用于一个客户端同时发送和读取消息的应用场景。
4、autoDelete: 是否自动删除队列,为 true 则设置队列为自动删除。自动删除的前提是: 至少有一个消费者连接到这个队列,之后所有与这个队列连接的消费者都断开时,才会 自动删除。不能把这个参数错误地理解为: “当连接到此队列的所有客户端断开时,这 个队列自动删除”,因为生产者客户端创建这个队列,或者没有消费者客户端与这个队 列连接时,都不会自动删除这个队列。
5、args: 相关参数,如 x-rnessage-ttl 、x-expires 、x-rnax-length 、x-rnax-length-bytes、 x-dead-letter-exchange、 x-deadletter-routing-key 、 x-rnax-priority 等。

channel.basicConsume(queue, autoAck, callback)方法参数说明:
1、queue:队列名
2、 autoAck:true 接收到传递过来的消息后acknowledged(应答服务器),false 接收到消息后不应答服务器
3、 callback: 消费者对象的回调接口

2.3 RabbitMQ生产者线程类

class Provider implements Runnable{

    // RabbitMQ队列名称
    private String queueName;

    public Provider(String queueName){
        this.queueName = queueName;
    }

    public void run() {
        Connection connection = null;
        Channel channel = null;
        try {
            // 创建连接
            connection = RabbitMQFactory.getConnection();
            // 创建连接通道
            channel = connection.createChannel();
            // 声明要连接的队列
            channel.queueDeclare(queueName, false, false, false, null);
            String message = "message";
            // 每3秒发送一条消息,总共发送10条
            for(int i = 1; i <= 10; i++){
                // 创建消息队列,并且发送消息
                System.out.println("生产者" + Thread.currentThread().getName() + "发布了新消息:" + message + i);
                channel.basicPublish("", queueName, null, (message + i).getBytes());
                Thread.sleep(2000);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            /* 关闭连接 */
            try {
                channel.close();
                connection.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

}

channel.basicPublish(exchange, routingKey, props, body)方法参数说明:
1、exchange: 要将消息发送到的交换器
2、routingKey: 路由KEY
3、props: 消息的其它属性,如:路由头等
4、body: 消息体

2.4 测试实例

建立一个生产者线程和两个消费者线程来实现消息的读取操作

public class RabbitMQDemo {

    public static void main(String[] args) {
        Provider provider = new Provider("queue");
        Consumer consumer1 = new Consumer("queue");
        Consumer consumer2 = new Consumer("queue");
        Thread providerThread = new Thread(provider);
        Thread consumerThread1 = new Thread(consumer1);
        Thread consumerThread2 = new Thread(consumer2);
        providerThread.start();
        consumerThread1.start();
        consumerThread2.start();
    }

}

参考链接

1、一文搞懂 RabbitMQ 的重要概念以及安装2、Java中简单使用RabbitMQ进行消息收发3、java调用rabbitmq消息队列发送和接收消息实例4、WINDOWS环境下RABBITMQ的启动和停止命令5、RabbitMq 之queueDeclare 方法详解6、RabbitMQ之basicConsume、basicCancel、basicPublish等方法详解