RabbitMQ教程第一步Hello World

前言: 这篇文章主要讲述如何使用RabbitMQ创建消息应用程序 。 RabbitMQ是一个消息代理,它接受和转发消息。官网建议把它想象成邮局:当你写好收件人并把要邮寄的邮件放在一个邮箱里后,邮局会搜集邮件,并把邮件交给你的收件人。在这个类比中,RabbitMQ是一个邮箱也是一个邮局,同时也是一个邮递员,RabbitMQ和邮局的主要区别在于,它不处理实体邮件,而是接受、存储和转发二进制数据信息

RabitMQ文章目录

1-RabbitMQ Server简介和安装教程

2-RabbitMQ概念 AMQP模型

3-RabbitMQ教程第一步Hello World

4-RabbitMQ教程工作队列Work queues

5-RabbitMQ教程扇出交换器和发布订阅

6-RabbitMQ教程直连交换器和路由Routing

7-RabbitMQ教程主题交换器Topics

8-RabbitMQ教程远程过程调用RPC

9-RabbitMQ教程发布确认PublishConfirm

图例

P(生产者): 生产者属于数据的发送方 ,发送的消息被放入队列里

C(消费者): 消费者属于数据的接收方,发现队列里的消息,将消息从队列中读取出来做业务操作

Queue(队列): RabbitMQ的作用是存储消息,队列的特性是先进先出

第一个应用程序

本示例是一个最简单的示例, 实现 一个发送单一信息的生产者发送消息到RabbitMQ中的队列里,一个接收信息并打印出消息信息,示意图如下:

RabbitMQ讲多种协议。本教程使用AMQP 0-9-1,需要引用amqp-client

<dependency>
    <groupId>com.rabbitmq</groupId>
    <artifactId>amqp-client</artifactId>
    <version>5.6.0</version>
</dependency>

生产者 发送消息参考代码 

public class Producer {

    public final static String QUEUE_NAME = "rabbitMQ.test";

    public static void main(String[] args) throws IOException, TimeoutException {
        //使用工厂创建1个连接
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("localhost"); //设置RabbitMQ 服务器地址
        Connection connection = factory.newConnection();
        Channel channel = connection.createChannel();
        try {
            //创建1个通道,声明要关注的队列
            channel.queueDeclare(QUEUE_NAME, false, false, false, null);

            //发送消息
            String message = "Hello world ";
            channel.basicPublish("", QUEUE_NAME, null, message.getBytes("UTF-8"));
            System.out.println("Producer Send +'" + message + "'");
        } finally {
            //关闭通道和连接
           channel.close();
           connection.close();
        }
    }
}

运行后执行监控http://localhost:15672/可以看到声明的消息队列

1. Channel

Connection可以用来创建多个Channel实例,Channel与线程一一对应Channel实例不能在线程间共享:使用Channel的场景通常为在客户端每个线程使用一个独立的Channel实例来进行数据传输,这样就实现了不同线程之间的隔离。不过由于所有线程都共用一个TCP连接进行数据传输,如果传输的数据量小则问题不大,如果需要进行大数据量传输,则该TCP连接的带宽就会成为性能瓶颈

2. channel#queueDeclare用于声明队列,接口签名如下

/**
 * Declare a queue
 * @param queue 队列名字
 * @param durable  是否持久化队列 ,持久化的队列会存盘,在服务器重启的时候可以保证不丢失相关信息
 * @param exclusive 是否为排他。设置是否排他。为true 则设置队列为排他的。如果一个队列被声明为排他队列,该队列仅对首次声明它的连接可见,并在连接断开时自动删除
 * @param autoDelete 长时间不使用的时候是否自动删除
 * @param arguments  设置队列的其他一些参数,如x-message=ttl、x-expires、x-max-length、x-max-length-bytes、x-dead-letter-exchange、x-dead-letter-routing-key、x-max-priority等
 */
Queue.DeclareOk queueDeclare(String queue, boolean durable, boolean exclusive, boolean autoDelete,
                             Map<String, Object> arguments) throws IOException;

3. channel#basicPublis用于发布1条消息,接口签名如下

    /**
     * Publish a message.
     * @param exchange交换器的名称。如果为空字符串,消息会被发送到RabbitMQ默认交换器中
     * @param routingKey 路由键,交换器根据路由键将消息存储到相应的队列之中
     * @param props 消息属性 - routing headers 等
     * @param body 消息体,真正需要发送的消息
     * @throws java.io.IOException if an error is encountered
     */
    void basicPublish(String exchange, String routingKey, BasicProperties props, byte[] body) throws IOException;

接收消息参考代码

/**
 * 消费者
 */
public class Customer {


    private final static String QUEUE_NAME = "rabbitMQ.test";

    public static void main(String[] args) throws IOException, TimeoutException {
        System.out.println("Customer PROCESS");
        // 创建连接工厂,设置RabbitMQ地址
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("127.0.0.1");
        System.out.println("connection...");
        //创建一个新的连接
        Connection connection = factory.newConnection();

        Channel channel = connection.createChannel();
        try {
            //声明要关注的队列
            //channel.queueBind(QUEUE_NAME, null, null);
            channel.queueDeclare(QUEUE_NAME, false, false, false, null);
            System.out.println("Customer Waiting Received messages");


            //DefaultConsumer类实现了Consumer接口,通过传入一个频道,
            // 告诉服务器我们需要那个频道的消息,如果频道中有消息,就会执行回调函数handleDeliveryå
            Consumer consumer = new DefaultConsumer(channel) {
                @Override
                public void handleDelivery(String consumerTag, Envelope envelope,
                                           AMQP.BasicProperties properties, byte[] body)
                        throws IOException {

                    //envelope主要存放生产者相关信息(比如交换机、路由key等)body是消息实体
                    String message = new String(body, "UTF-8");
                    System.out.println("Customer Received '" + message + "'");
                }
            };

            //自动回复队列应答 -- RabbitMQ中的消息确认机制
            channel.basicConsume(QUEUE_NAME, true, consumer);

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

执行结果

Customer PROCESS
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
connection...
Customer Waiting Received messages
Customer Received 'Hello world '

1.处理消息channel#basicConsume

RabbitMQ 消费模式分推/拉两种模式, 推模式是最长用的, 接收消息可通过实现Consumer接口或者继承DefaultConsumer类来实现, 当接收到一条消息后就会调用Consumer#handleDelivery

/**
* @param 队列名称
* @param 设置是否自动确认。建议设成false,即不自动确认;
* @param 设置消费者的回调函数。用来处理RabbitMQ 推送过来的消息,比如DefaultConsumer,使用时需要客户端重写(override) 其中的方法
*/
String basicConsume(String queue, boolean autoAck, Consumer callback) throws IOException;

官网实例中建议使用DeverCallBack接口,参考代码如下

public class Customer2 {


    private final static String QUEUE_NAME = "rabbitMQ.test";

    public static void main(String[] args) throws IOException, TimeoutException {
        System.out.println("Customer PROCESS");
        // 创建连接工厂,设置RabbitMQ地址
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("127.0.0.1");
        System.out.println("connection...");
        //创建一个新的连接
        Connection connection = factory.newConnection();

        Channel channel = connection.createChannel();
        try {
            //声明要关注的队列
            //channel.queueBind(QUEUE_NAME, null, null);
            channel.queueDeclare(QUEUE_NAME, false, false, false, null);
            System.out.println("Customer Waiting Received messages");


            DeliverCallback deliverCallback = (consumerTag, delivery) -> {
                String message = new String(delivery.getBody(), "UTF-8");
                System.out.println("Customer Received '" + message + "'");
            };
            channel.basicConsume(QUEUE_NAME, true, deliverCallback, consumerTag -> { });

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


DeviverCallback接口是一个回调接口 ,当队列中有消息的时候会执行回调接口实现处理消息

/**
 * Callback interface to be notified when a message is delivered.
 * Prefer it over {@link Consumer} for a lambda-oriented syntax,
 * if you don't need to implement all the application callbacks.
*/
@FunctionalInterface
public interface DeliverCallback {

    /**
     * Called when a <code><b>basic.deliver</b></code> is received for this consumer.
     * @param consumerTag the <i>consumer tag</i> associated with the consumer
     * @param message the delivered message
     * @throws IOException if the consumer encounters an I/O error while processing the message
     */
    void handle(String consumerTag, Delivery message) throws IOException;

}

参考文献:https://www.rabbitmq.com/tutorials/tutorial-one-java.html

上一篇:RabbitMQ概念 AMQP模型

Guess you like

Origin blog.csdn.net/Beijing_L/article/details/119187816