RabbitMQ入门(三、RabbitMQ的Java使用)

准备工作

首先需要安装配置好rabbitmq,网上很多教程,在此不再赘述。

创建用户hpsyche,密码:xxxxxx,同时创建host域(可以看做新建数据库),之后就可以进入代码阶段了(

首先导入包(此处创建的是maven工程)

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

新建一个utils工具类

package com.hpsyche.rabbitmq_learn.utils;

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

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

/**
 * @author fuzihao
 * @date 2019/8/23 16:52
 */
public class ConnectionUtils {
    private static class SingletonInstance{
        private static final ConnectionFactory factory=new ConnectionFactory();
    }

    private static ConnectionFactory getConncetionFactory(){
        return SingletonInstance.factory;
    }

    public static Connection getConnection() throws IOException, TimeoutException {
        ConnectionFactory factory=getConncetionFactory();
        factory.setUsername("hpsyche");
        factory.setPassword("XXXXXX");
        factory.setHost("127.0.0.1");
        factory.setVirtualHost("/vhost_test");
        factory.setPort(5672);
        return factory.newConnection();
    }
}

如果使用的是SpringBoot项目,注入bean

package com.hpsyche.rabbitmq_learn.utils;

import com.rabbitmq.client.ConnectionFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;

/**
 * @author fuzihao
 * @date 2019/8/23 16:33
 */
@Component
public class GetRabbitConn {
    @Bean
    public ConnectionFactory getConnectionFactory(){
        ConnectionFactory connectionFactory=new ConnectionFactory();
        connectionFactory.setUsername("hpsyche");
        connectionFactory.setPassword("XXXXXX");
        connectionFactory.setHost("127.0.0.1");
        connectionFactory.setVirtualHost("/vhost_test");
        connectionFactory.setPort(5672);
        return connectionFactory;
    }
}

简单队列

首先是生产者

package com.hpsyche.rabbitmq_learn.simple;

import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

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

/**
 * @author fuzihao
 * @date 2019/8/26 11:39
 */
@RunWith(SpringRunner.class)
@SpringBootTest
public class Producer {
    private static final String QUEUE_NAME="test_simple_queue";

    @Autowired
    private ConnectionFactory connectionFactory;

    @Test
    public void SimpleQueue() throws IOException, TimeoutException {
        //获得连接
        Connection connection = connectionFactory.newConnection();
        //获得信道
        Channel channel = connection.createChannel();
        //创建队列声明
        channel.queueDeclare(QUEUE_NAME,false,false,false,null);
        //发送消息
        String msg="hello queue";
        channel.basicPublish("",QUEUE_NAME,null,msg.getBytes());
        System.out.println("send msg");
        //关闭连接
        channel.close();
        connection.clearBlockedListeners();
    }
}

消费者

package com.hpsyche.rabbitmq_learn.simple;

import com.rabbitmq.client.*;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.TimeoutException;

/**
 * @author fuzihao
 * @date 2019/8/26 11:40
 */
@RunWith(SpringRunner.class)
@SpringBootTest
public class Receive {
    private static final String QUEUE_NAME="test_simple_queue";

    @Autowired
    private ConnectionFactory connectionFactory;

    @Test
    public void SimpleQueue() throws IOException, TimeoutException {
        //获得连接
        Connection connection = connectionFactory.newConnection();
        //获得信道
        Channel channel = connection.createChannel();
        //创建队列声明
        channel.queueDeclare(QUEUE_NAME,false,false,false,null);
        //定义消费者
        Consumer consumer=new DefaultConsumer(channel){
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                String msg=new String(body, StandardCharsets.UTF_8);
                System.out.println(msg);
            }
        };
        channel.basicConsume(QUEUE_NAME,true,consumer);
    }
}

首先启动生产者类,访问http://localhost:15672/#/queues
在这里插入图片描述
可以看到,该队列里已经有一个“准备好未消费”的消息了。

此时启动消费者类,再次查看,发现消息已经被消费了,total再次清为0;

但此时怎么查看之前消息的历史呢,此时我们需要引入rabbitmq的消息体日志信息的插件

  • 安装rabbitmq_tracing 插件,进入mq安装目录的sbin目录,执行rabbitmq-plugins enable rabbitmq_tracing

  • 使用MQ的web监控工具添加一个log trace

  • 在这里插入图片描述
    此时trace开始监控消息,再次启动生产者(两次),启动消费者,点击trace中的日志文件,查看日志:
    在这里插入图片描述
    可以看到消息产生及消费的信息
    在这里插入图片描述

工作队列

轮询分发

首先是生产者

package com.hpsyche.rabbitmq_learn.round;

import com.hpsyche.rabbitmq_learn.utils.ConnectionUtils;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;

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

/**
 * @author fuzihao
 * @date 2019/8/26 12:47
 */
public class Producer {
    private static final String QUEUE_NAME="test_work_round_queue";

    public static void main(String[] args) throws IOException, TimeoutException, InterruptedException {
        //获得连接
        Connection connection = ConnectionUtils.getConnection();
        //获得信道
        Channel channel = connection.createChannel();
        //创建队列生命
        channel.queueDeclare(QUEUE_NAME,false,false,false,null);
        //发送消息

        for(int i=0;i<50;i++){
            String msg="hello "+i;
            channel.basicPublish("",QUEUE_NAME,null,msg.getBytes());
            System.out.println("send msg "+i);
            Thread.sleep(10);
        }
        //关闭连接
        channel.close();
        connection.clearBlockedListeners();
        connection.close();

    }
}

消费者1

package com.hpsyche.rabbitmq_learn.round;

import com.hpsyche.rabbitmq_learn.utils.ConnectionUtils;
import com.rabbitmq.client.*;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.TimeoutException;

/**
 * @author fuzihao
 * @date 2019/8/26 11:40
 */
public class Receive1 {
    private static final String QUEUE_NAME="test_work_round_queue";

    public static void main(String[] args) throws IOException, TimeoutException{
        //获得连接
        Connection connection = ConnectionUtils.getConnection();
        //获得信道
        Channel channel = connection.createChannel();
        //创建队列生命
        channel.queueDeclare(QUEUE_NAME,false,false,false,null);

        //定义消费者
        Consumer consumer=new DefaultConsumer(channel){
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                String msg=new String(body, StandardCharsets.UTF_8);
                System.out.println("[1]"+msg);
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        };
        channel.basicConsume(QUEUE_NAME,true,consumer);
        channel.close();
        connection.close();
    }
}

消费者2

package com.hpsyche.rabbitmq_learn.round;

import com.hpsyche.rabbitmq_learn.utils.ConnectionUtils;
import com.rabbitmq.client.*;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.TimeoutException;

/**
 * @author fuzihao
 * @date 2019/8/26 11:40
 */
public class Receive2 {
    private static final String QUEUE_NAME="test_work_round_queue";

    public static void main(String[] args) throws IOException, TimeoutException{
        //获得连接
        Connection connection = ConnectionUtils.getConnection();
        //获得信道
        Channel channel = connection.createChannel();
        //创建队列生命
        channel.queueDeclare(QUEUE_NAME,false,false,false,null);

        //定义消费者
        Consumer consumer=new DefaultConsumer(channel){
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                String msg=new String(body, StandardCharsets.UTF_8);
                System.out.println("[2]"+msg);
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        };
        channel.basicConsume(QUEUE_NAME,true,consumer);
        channel.close();
        connection.close();
    }
}

首先启动消费者1,消费者2,再启动生产者线程,发现两条消费者线程不管谁忙,都不会多给消息,总是你一个我一个。

公平分发

生产者

package com.hpsyche.rabbitmq_learn.fair;

import com.hpsyche.rabbitmq_learn.utils.ConnectionUtils;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;

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

/**
 * @author fuzihao
 * @date 2019/8/26 12:47
 */
public class Producer {
    private static final String QUEUE_NAME="test_work_fair_queue";

    public static void main(String[] args) throws IOException, TimeoutException, InterruptedException {
        //获得连接
        Connection connection = ConnectionUtils.getConnection();
        //获得信道
        Channel channel = connection.createChannel();
        //创建队列生命
        channel.queueDeclare(QUEUE_NAME,false,false,false,null);
        //限制每次只发送不超过1条消息到同一个消费者,消费者必须手动反馈告知队列,才会发送下一个。
        channel.basicQos(1);

        //发送消息
        for(int i=0;i<50;i++){
            String msg="hello "+i;
            channel.basicPublish("",QUEUE_NAME,null,msg.getBytes());
            System.out.println("send msg "+i);
            Thread.sleep(10);
        }
        //关闭连接
        channel.close();
        connection.close();

    }
}

消费者1

package com.hpsyche.rabbitmq_learn.fair;

import com.hpsyche.rabbitmq_learn.utils.ConnectionUtils;
import com.rabbitmq.client.*;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.TimeoutException;

/**
 * @author fuzihao
 * @date 2019/8/26 11:40
 */
public class Receive1 {
    private static final String QUEUE_NAME="test_work_fair_queue";

    public static void main(String[] args) throws IOException, TimeoutException{
        //获得连接
        Connection connection = ConnectionUtils.getConnection();
        //获得信道
        Channel channel = connection.createChannel();
        //创建队列生命
        channel.queueDeclare(QUEUE_NAME,false,false,false,null);

        //保证一次只发送一个
        channel.basicQos(1);

        //定义消费者
        Consumer consumer=new DefaultConsumer(channel){
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                String msg=new String(body, StandardCharsets.UTF_8);
                System.out.println("[1]"+msg);
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }finally {
                    System.out.println("[1] done");
                    //手动返回ack
                    channel.basicAck(envelope.getDeliveryTag(),false);
                }
            }
        };
        //false:自动应答关闭
        channel.basicConsume(QUEUE_NAME,false,consumer);
    }
}

消费者2

package com.hpsyche.rabbitmq_learn.fair;

import com.hpsyche.rabbitmq_learn.utils.ConnectionUtils;
import com.rabbitmq.client.*;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.TimeoutException;

/**
 * @author fuzihao
 * @date 2019/8/26 11:40
 */
public class Receive2 {
    private static final String QUEUE_NAME="test_work_fair_queue";

    public static void main(String[] args) throws IOException, TimeoutException{
        //获得连接
        Connection connection = ConnectionUtils.getConnection();
        //获得信道
        Channel channel = connection.createChannel();
        //创建队列生命
        channel.queueDeclare(QUEUE_NAME,false,false,false,null);

        channel.basicQos(1);

        //定义消费者
        Consumer consumer=new DefaultConsumer(channel){
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                String msg=new String(body, StandardCharsets.UTF_8);
                System.out.println("[2]"+msg);
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    System.out.println("[2] done");
                    //手动返回ack
                    channel.basicAck(envelope.getDeliveryTag(),false);
                }
            }
        };
        //false:自动应答关闭
        channel.basicConsume(QUEUE_NAME,false,consumer);
    }
}

订阅者模式

Fanout(不处理路由键)

生产者

package com.hpsyche.rabbitmq_learn.topic.fanous;

import com.hpsyche.rabbitmq_learn.utils.ConnectionUtils;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;

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

/**
 * @author fuzihao
 * @date 2019/8/27 9:23
 */
public class Producer {
    private static final String EXCHANGE_NAME="test_exchange_fanout";

    public static void main(String[] args) throws IOException, TimeoutException {
        //获得连接
        Connection connection = ConnectionUtils.getConnection();
        //获得信道
        Channel channel = connection.createChannel();
        //声明交换机
        channel.exchangeDeclare(EXCHANGE_NAME,"fanout");

        for(int i=0;i<50;i++){
            String msg="hello ps"+i;
            System.out.println("Send "+i);
            channel.basicPublish(EXCHANGE_NAME,"",null,msg.getBytes());
        }
        channel.close();
        connection.close();
    }
}

消费者1

package com.hpsyche.rabbitmq_learn.topic.fanous;

import com.hpsyche.rabbitmq_learn.utils.ConnectionUtils;
import com.rabbitmq.client.*;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.TimeoutException;

/**
 * @author fuzihao
 * @date 2019/8/27 9:54
 */
public class Receive1 {
    private static final String QUEUE_NAME="test_fanout_queue-1";
    private static final String EXCHANGE_NAME="test_exchange_fanout";

    public static void main(String[] args) throws IOException, TimeoutException {
        //获得连接
        Connection connection = ConnectionUtils.getConnection();
        //获得信道
        Channel channel = connection.createChannel();
        //创建队列生命
        channel.queueDeclare(QUEUE_NAME,false,false,false,null);
        //绑定队列
        channel.queueBind(QUEUE_NAME,EXCHANGE_NAME,"");

        //定义消费者
        Consumer consumer=new DefaultConsumer(channel){
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                String msg=new String(body, StandardCharsets.UTF_8);
                System.out.println("[1-fanout]"+msg);
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        };
        channel.basicConsume(QUEUE_NAME,true,consumer);
    }
}

消费者2

package com.hpsyche.rabbitmq_learn.topic.fanous;

import com.hpsyche.rabbitmq_learn.utils.ConnectionUtils;
import com.rabbitmq.client.*;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.TimeoutException;

/**
 * @author fuzihao
 * @date 2019/8/27 9:54
 */
public class Receive2 {
    private static final String QUEUE_NAME="test_fanout_queue-2";
    private static final String EXCHANGE_NAME="test_exchange_fanout";

    public static void main(String[] args) throws IOException, TimeoutException {
        //获得连接
        Connection connection = ConnectionUtils.getConnection();
        //获得信道
        Channel channel = connection.createChannel();
        //创建队列生命
        channel.queueDeclare(QUEUE_NAME,false,false,false,null);
        //绑定队列
        channel.queueBind(QUEUE_NAME,EXCHANGE_NAME,"");

        //定义消费者
        Consumer consumer=new DefaultConsumer(channel){
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                String msg=new String(body, StandardCharsets.UTF_8);
                System.out.println("[2-fanout]"+msg);
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        };
        channel.basicConsume(QUEUE_NAME,true,consumer);
    }
}

注意:消费者1、2的队列是不一样的。

此时可以看到输出结果,两个消费者都能够完全获取到所有消息。

Direct(路由模式)

生产者如下

package com.hpsyche.rabbitmq_learn.topic.router;

import com.hpsyche.rabbitmq_learn.utils.ConnectionUtils;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;

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

/**
 * @author fuzihao
 * @date 2019/8/27 9:23
 */
public class Producer {
    private static final String EXCHANGE_NAME="test_exchange_direct";

    public static void main(String[] args) throws IOException, TimeoutException {
        //获得连接
        Connection connection = ConnectionUtils.getConnection();
        //获得信道
        Channel channel = connection.createChannel();
        //声明交换机
        channel.exchangeDeclare(EXCHANGE_NAME,"direct");
        
        String msg="hello direct";
        //路由键
        String routerKey="error";
        String msg2="hello direct success";
        //路由键
        String routerKey2="success";
        
        channel.basicPublish(EXCHANGE_NAME,routerKey,null,msg.getBytes());
        channel.basicPublish(EXCHANGE_NAME,routerKey2,null,msg2.getBytes());

        channel.close();
        connection.close();
    }
}

消费者1

package com.hpsyche.rabbitmq_learn.topic.router;

import com.hpsyche.rabbitmq_learn.utils.ConnectionUtils;
import com.rabbitmq.client.*;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.TimeoutException;

/**
 * @author fuzihao
 * @date 2019/8/27 9:54
 */
public class Receive1 {
    private static final String QUEUE_NAME="test_fanout_queue-1";
    private static final String EXCHANGE_NAME="test_exchange_direct";

    public static void main(String[] args) throws IOException, TimeoutException {
        //获得连接
        Connection connection = ConnectionUtils.getConnection();
        //获得信道
        Channel channel = connection.createChannel();
        //创建队列生命
        channel.queueDeclare(QUEUE_NAME,false,false,false,null);
        //绑定队列
        channel.queueBind(QUEUE_NAME,EXCHANGE_NAME,"error");

        //定义消费者
        Consumer consumer=new DefaultConsumer(channel){
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                String msg=new String(body, StandardCharsets.UTF_8);
                System.out.println("[1-direct]"+msg);
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        };
        channel.basicConsume(QUEUE_NAME,true,consumer);
    }
}

消费者2

package com.hpsyche.rabbitmq_learn.topic.router;

import com.hpsyche.rabbitmq_learn.utils.ConnectionUtils;
import com.rabbitmq.client.*;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.TimeoutException;

/**
 * @author fuzihao
 * @date 2019/8/27 9:54
 */
public class Receive2 {
    private static final String QUEUE_NAME="test_fanout_queue-2";
    private static final String EXCHANGE_NAME="test_exchange_direct";

    public static void main(String[] args) throws IOException, TimeoutException {
        //获得连接
        Connection connection = ConnectionUtils.getConnection();
        //获得信道
        Channel channel = connection.createChannel();
        //创建队列生命
        channel.queueDeclare(QUEUE_NAME,false,false,false,null);
        //绑定队列
        channel.queueBind(QUEUE_NAME,EXCHANGE_NAME,"success");

        //定义消费者
        Consumer consumer=new DefaultConsumer(channel){
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                String msg=new String(body, StandardCharsets.UTF_8);
                System.out.println("[2-direct]"+msg);
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        };
        channel.basicConsume(QUEUE_NAME,true,consumer);
    }
}

注意:一个生产者交换机可以绑定多条信息与路由键,而一个消费者队列也可以绑定多个路由键。

此时输出结果为消费者1输出:[1-direct]hello direct;消费者2输出:[2-direct]hello direct success。

Topic(路由键模式匹配)

生产者1

package com.hpsyche.rabbitmq_learn.topic.topic;

import com.hpsyche.rabbitmq_learn.utils.ConnectionUtils;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;

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

/**
 * @author fuzihao
 * @date 2019/8/27 9:23
 */
public class Producer {
    private static final String EXCHANGE_NAME="test_exchange_topic";

    public static void main(String[] args) throws IOException, TimeoutException {
        //获得连接
        Connection connection = ConnectionUtils.getConnection();
        //获得信道
        Channel channel = connection.createChannel();
        //声明交换机
        channel.exchangeDeclare(EXCHANGE_NAME,"topic");

        String msg="商品delete....";
        //路由键
        String routerKey="goods.delete";
        channel.basicPublish(EXCHANGE_NAME,routerKey,null,msg.getBytes());

        channel.close();
        connection.close();
    }
}

生产者2

package com.hpsyche.rabbitmq_learn.topic.topic;

import com.hpsyche.rabbitmq_learn.utils.ConnectionUtils;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;

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

/**
 * @author fuzihao
 * @date 2019/8/27 9:23
 */
public class Producer2 {
    private static final String EXCHANGE_NAME="test_exchange_topic";

    public static void main(String[] args) throws IOException, TimeoutException {
        //获得连接
        Connection connection = ConnectionUtils.getConnection();
        //获得信道
        Channel channel = connection.createChannel();
        //声明交换机
        channel.exchangeDeclare(EXCHANGE_NAME,"topic");

        String msg="商品put....";
        //路由键
        String routerKey="goods.put";
        channel.basicPublish(EXCHANGE_NAME,routerKey,null,msg.getBytes());

        channel.close();
        connection.close();
    }
}

消费者

package com.hpsyche.rabbitmq_learn.topic.topic;

import com.hpsyche.rabbitmq_learn.utils.ConnectionUtils;
import com.rabbitmq.client.*;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.TimeoutException;

/**
 * @author fuzihao
 * @date 2019/8/27 9:54
 */
public class Receive1 {
    private static final String QUEUE_NAME="test_fanout_queue-1";
    private static final String EXCHANGE_NAME="test_exchange_topic";

    public static void main(String[] args) throws IOException, TimeoutException {
        //获得连接
        Connection connection = ConnectionUtils.getConnection();
        //获得信道
        Channel channel = connection.createChannel();
        //创建队列生命
        channel.queueDeclare(QUEUE_NAME,false,false,false,null);
        //绑定队列
        channel.queueBind(QUEUE_NAME,EXCHANGE_NAME,"goods.#");

        //定义消费者
        Consumer consumer=new DefaultConsumer(channel){
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                String msg=new String(body, StandardCharsets.UTF_8);
                System.out.println("[1-topic]"+msg);
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        };
        channel.basicConsume(QUEUE_NAME,true,consumer);
    }
}

启动生产者创建下交换机(若直接启动消费者会报错:IOException);

再依次启动 消费者、两个生产者,此时消费者输出结果如下:

[1-topic]商品delete....
[1-topic]商品put....

事务机制

Transaction模式

package com.hpsyche.rabbitmq_learn.queren.transaction;

import com.hpsyche.rabbitmq_learn.utils.ConnectionUtils;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;

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

/**
 * @author fuzihao
 * @date 2019/8/27 10:53
 */
public class Producer {
    private static final String QUEUE_NAME="test-transaction-1";

    public static void main(String[] args) throws IOException, TimeoutException {
        //获得连接
        Connection connection = ConnectionUtils.getConnection();
        //获得信道
        Channel channel = connection.createChannel();
        channel.queueDeclare(QUEUE_NAME,false,false,false,null);
        channel.txSelect();//将信道设置为事务模式
        try
        {
            String msg="123";
            channel.basicPublish("",QUEUE_NAME,null,msg.getBytes());
            int i=1/0;
            channel.txCommit();//提交事务
        }
        catch (Exception ex)
        {
            ex.printStackTrace();
            channel.txRollback();
        }
    }
}

这里创建了工作队列,同时添加事务,在commit之前执行1/0,发现事务回滚,在catch中其实可以进行消息重发(此处不做详细介绍)。

Confirm机制

相比于事务的优点:异步的处理

package com.hpsyche.rabbitmq_learn.queren.confirm;

import com.hpsyche.rabbitmq_learn.utils.ConnectionUtils;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;

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

/**
 * @author fuzihao
 * @date 2019/8/27 11:04
 */
public class Producer {
    private static final String QUEUE_NAME="test-confirm-1";

    public static void main(String[] args) throws IOException, TimeoutException, InterruptedException {
        //获得连接
        Connection connection = ConnectionUtils.getConnection();
        //获得信道
        Channel channel = connection.createChannel();
        channel.queueDeclare(QUEUE_NAME,false,false,false,null);
        //生产者设置为confirm模式
        channel.confirmSelect();

        String msg="123";
        channel.basicPublish("",QUEUE_NAME,null,msg.getBytes());

        if(!channel.waitForConfirms()){
            System.out.println("发送失败");
        }else {
            System.out.println("发送成功");
        }

        channel.close();
        connection.close();

    }
}

package com.hpsyche.rabbitmq_learn.queren.confirm;

import com.hpsyche.rabbitmq_learn.utils.ConnectionUtils;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.ConfirmListener;
import com.rabbitmq.client.Connection;

import java.io.IOException;
import java.util.Collections;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.concurrent.TimeoutException;

/**
 * @author fuzihao
 * @date 2019/8/27 11:14
 */
public class Producer2 {
    private static  final  String QUEUE_NAME = "test-confirm-2";
    public static void main(String[] args) throws IOException, TimeoutException, InterruptedException {
        Connection connection = ConnectionUtils.getConnection();
        Channel channel = connection.createChannel();
        channel.queueDeclare(QUEUE_NAME,false,false,false,null);
        //开启confirm模式
        channel.confirmSelect();

        //未确认的消息放入
        SortedSet<Long> confirmSet = Collections.synchronizedSortedSet(new TreeSet<Long>());

        //添加监听通道
        channel.addConfirmListener(new ConfirmListener() {
            //没有问题的handleAck 成功
            @Override
            public void handleAck(long deliveryTag, boolean multiple) throws IOException {
                if(multiple){   //多个的
                    System.out.println("handleAck:multiple");
                    confirmSet.headSet(deliveryTag+1).clear();
                }else{          //单个的
                    System.out.println("handleAck:multiple false");
                    confirmSet.remove(deliveryTag);
                }
            }
            //有问题的反馈Nack 失败
            @Override
            public void handleNack(long deliveryTag, boolean multiple) throws IOException {
                if(multiple){  	//多个的
                    System.out.println("handleNack:multiple");
                    confirmSet.headSet(deliveryTag+1).clear();
                }else{			//单个的
                    System.out.println("handleNack:multiple false");
                    confirmSet.remove(deliveryTag);
                }
            }
        });

        String msg = "test-confirm-2";
        while(true){
            long seqNo = channel.getNextPublishSeqNo();
            channel.basicPublish("",QUEUE_NAME,null,msg.getBytes());
            confirmSet.add(seqNo);
        }
    }
}

发布了63 篇原创文章 · 获赞 29 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/Hpsyche/article/details/100189782
今日推荐