RabbitMQ --- 从零开始

Hello Word

在这里插入图片描述

/* 
*  连接RabbitMQ
*/
public Connection getConn() throws Exception {
        ConnectionFactory connectionFactory = new ConnectionFactory();
        connectionFactory.setHost("localhost");
        connectionFactory.setPort(5672);
        connectionFactory.setUsername("guest");
        connectionFactory.setPassword("guest");
        //创建连接
        Connection connection = connectionFactory.newConnection();
        return connection;
    }
/*
*  发送消息
*/
  public static void main(String[] args) throws Exception {
        ConnectionFactory connectionFactory = new ConnectionFactory();
        connectionFactory.setHost("localhost");
        try {
            Connection connection = connectionFactory.newConnection();
            //创建通道
            Channel channel = connection.createChannel();
            // 声明队列
            channel.queueDeclare("MyQUEUE",false, false, false, null);
            String message = "my message is LiGuangXi";
            //发布消息
            channel.basicPublish("", "MyQUEUE", null, message.getBytes("UTF-8"));
            System.out.println("sent is up and message" + message);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

/*
*  消费者  消费消息
*/
public static void main(String[] args) {
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("localhost");
        try {
            Connection connection = factory.newConnection();
            Channel channel = connection.createChannel();
            /*
            * 请注意,我们也在这里声明了队列。因为我们可能在发布者之前启动消费者,所以我们希望在尝试使用消息之前确保队列存在。
            * 声明队列:
            * para1.队列名字
            * para2.是否持久化(rabbirmq不允许修改已存在的队列状态,修改时需要创建新的队列)重启服务也不会都是消息
            * para3.独有的
            * para4.自动删除
            * para5.Map<String, Object>参数
            * */
            
            channel.queueDeclare("MyQUEUE", false, false, false, null);
            
            /*
            *   我们即将告诉服务器从队列中传递消息。因为它会异步地向我们发送消息,
            *   所以我们以对象的形式提供一个回调,它将缓冲消息,直到我们准备好使用它们。这就是DeliverCallback子类的作用。
            * */
            DeliverCallback deliverCallback = (consumerTag, delivery) -> {
                String message = new String(delivery.getBody(), "UTF-8");
                System.out.println(" 接受消息: '" + message + "'");
            };
            channel.basicConsume("MyQUEUE", true, deliverCallback, consumerTag -> { });
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


消息队列

在这里插入图片描述

工作队列(任务队列):背后的主要思想是避免立即执行资源密集型任务,并且必须等待它完成。相反,我们安排任务稍后完成。我们将任务封装为消息并将其发送到队列。在后台运行的工作进程将弹出任务并最终执行作业。当你运行许多工作程序时,他们之间将共享任务。

这里出现了一个小插曲 由于一个空格的原因我调试了将近2个小时

循环调度(默认)

rabbitmq 默认情况下是按顺序将任务推送到下一个消费者。平均而言,每个消费者将获得相同数量的消息。这种分发机制称之为循环法。
// 发送者
 public static void main(String[] args) throws Exception {
        Connection conn = connUtil.getConn();
        Channel channel = conn.createChannel();
        channel.queueDeclare(queuesName,false,false,false,null);
        for ( int i =0 ; i < 10; i++ ){
            Thread.sleep(1000);// 假装它很忙!!
            //允许从命令行发送任意消息,将任务放到我们的工作队列中
            String message = i+"test value";
            channel.basicPublish("", queuesName,null,message.getBytes());
            System.out.println("发送:"+message);
        }
        channel.close();
        conn.close();
    }
 
//  接收者  
//启动多个 可以看到rabbitmq 默认情况下是按顺序将任务推送到下一个消费者。平均而言,每个消费者将获得相同数量的消息。这种分发机制称之为循环法。
 public static void main(String[] args)  throws Exception {
        Connection conn = connUtil.getConn();
        Channel channel = conn.createChannel();
        channel.queueDeclare(quenename, false, false, false, null);
        DeliverCallback deliverCallback = (consumerTag, delivery) -> {
            String message = new String(delivery.getBody(), "UTF-8");
            System.out.println(" 接受请求: '" + message + "'");
        };
        //手动消息确认关闭。
        boolean autoAck = true;
        channel.basicConsume(quenename, autoAck, deliverCallback, consumerTag -> {});
    }

消息确认

为了确保消息永不丢失,RabbitMQ支持确认消息。消息者发送ACK(nowledgement)告诉RabbitMQ已经收到了,处理了特定消息,RabbitMQ可以自由的删除它。
如果消费者死亡(其通道关闭,连接关闭或TCP连接丢失)而不能正确发送的,RabbitMQ将理解消息未完全处理并将重新排队。如果同时有其他在线消费者,则会迅速将其重新发送给其他消费者。
默认情况下 手动消息确认已打开。上面代码中 autoACK=true 标志明确关闭了。
 public static void main(String[] args)  throws Exception {
        Connection conn = connUtil.getConn();
        Channel channel = conn.createChannel();
        channel.queueDeclare(quenename, false, false, false, null);
        //告诉rabbitMQ一次只能向一个工作者发送一条消息,在处理并确认前一个消息之前,不要给工作着发送新消息
        // 一次只能接收一个未包装的消息
        channel.basicQos(1);
        DeliverCallback deliverCallback = (consumerTag, delivery) -> {
            String message = new String(delivery.getBody(), "UTF-8");
            System.out.println(" 接受请求: '" + message + "'");
            try{
                doWork(message);
            }catch (Exception e){
                e.printStackTrace();
                System.out.println("异常信息");
            }finally {
                System.out.println("Done");
                 //确认必须在收到交付的同一渠道上发送。尝试使用不同的通道进行确认将导致通道协议异常。
                channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false);
            }
        };
        //打开手动确认消息
        boolean autoAck = false;
        channel.basicConsume(quenename, autoAck, deliverCallback, consumerTag -> {});
    }

    private static void doWork(String task) throws Exception  {
        for (char ch : task.toCharArray()){
            if(ch == '。')
                Thread.sleep(1000);
        }
    }
确认必须在收到交付的同一渠道上发送。尝试使用不同的通道进行确认将导致通道协议异常

消息持久性

RabbitMQ退出或者崩溃后,数据将会丢失,除非你这样做。
1.将队列声明成持久性的

首先保证我的队列是持久性的,为此我们需要声明一个持久性的队列
rabbitmq 不允许你使用不同的参数重新定义一个现有的对列,并且会向试图执行此操作的程序放回错误信息
此代码 应用于生产者 和 消费者

boolean durable = true;
channel.queueDeclare("new_hello", durable, false, false, null);
2.将消息声明成持久性的

现在我们需要将消息标记为持久化 - 通过MessageProperties(实现BasicProperties)设置为值PERSISTENT_TEXT_PLAIN

channel.basicPublish("", "new_hello", MessageProperties.PERSISTENT_TEXT_PLAIN, message.getBytes());
注意:将消息标记为持久性并不能完全保证消息不会丢失,虽然他告诉rabbitmq将消息保存到磁盘,但是当rabbitmq接受消息时,仍然有一个短暂的空窗口。此外,rabbitmq不会为每一条消息执行fsync(2),他可能只是保存到缓存而不是真正得写入磁盘。持久性不保证强。发布者模式将会弥补这一缺憾。

公平派遣

在处理并确认一个消息前,不要向消费者发起新的消息。上面例子已经使用了
告诉rabbitMQ一次只能向一个工作者发送一条消息,在处理并确认前一个消息之前,不要给工作着发送新消息
        // 一次只能接收一个未包装的消息
        channel.basicQos(1);

猜你喜欢

转载自blog.csdn.net/liguangix/article/details/88195977