RabbitMQ学习

信息手动应答

在建立的生产者消费者案例中。

消费端

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

        Channel Channel = getConn.getchannel();

        /**
         * 
         * meeage表示接收的消息
         */
        DeliverCallback DeliverCallback=(consumer,meeage)->{
            System.out.println(new String(meeage.getBody())+"已拿到");
            try {
                Thread.sleep(20000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            /**
             * meeage.getEnvelope().getDeliveryTag()  消息标记Tag
             * false表示不批量应答,只应答这一个消息
             */
            System.out.println(new String(meeage.getBody())+"确认完成");
            Channel.basicAck(meeage.getEnvelope().getDeliveryTag(),false);
        };
        CancelCallback CancelCallback=consumer->{
            System.out.println("消息消费被中断");
        };
        /**
         * 一:消息队列名称
         * 二:是否自动应答
         * true
         * 就是当生产者发送消息之后,RabbitMq就会将队列中的消息删除,不会管消费者是否已经处理完了消息
         * 弊端就是当生产者发送数据之后,如果在消费者没有处理完消息就宕机了,那这个消息就丢失了
         *
         * false
         * 就是当生产者发送消息之后,RabbitMq不会立刻将队列中的消息删除,而是等消费者发送ACk(表示确认已经处理完毕),才
         * 会将队列中的消息删除,假若在没有发送ACK时,消费者宕机了,则这条消息会重新入队,被其他消费者获取。保证了消息不会丢失
         *
         * 三:没有消费成功的反馈
         * 四:拿取消费的回调
         */
        boolean AutoACk=false;
        System.out.println( "C3等待消息");
        Channel.basicConsume(DL,AutoACk,DeliverCallback,CancelCallback);

    }

在 Channel.basicConsume设置中,我们将消息应答改为false(手动应答)只有发送了ACk之后,

RabbitMQ才会删除消息,否则会重新入队

这里我们消费者发送了2条消息

"C:\Program Files\Java\jdk-14.0.1\bin\java.exe" "-javaagent:D:\IntelliJ IDEA 2021.3.3\lib\idea_rt.jar=56306:D:\IntelliJ IDEA 2021.3.3\bin" -Dfile.encoding=UTF-8 -classpath E:\IDEA_Project\com.hwx.java\target\classes;C:\Users\lxkj\.m2\repository\com\rabbitmq\amqp-client\5.9.0\amqp-client-5.9.0.jar;C:\Users\lxkj\.m2\repository\org\slf4j\slf4j-api\1.7.30\slf4j-api-1.7.30.jar;C:\Users\lxkj\.m2\repository\commons-io\commons-io\2.8.0\commons-io-2.8.0.jar;C:\Users\lxkj\.m2\repository\log4j\log4j\1.2.17\log4j-1.2.17.jar;C:\Users\lxkj\.m2\repository\com\guicedee\services\sl4j\1.0.13.5\sl4j-1.0.13.5.jar;C:\Users\lxkj\.m2\repository\com\guicedee\services\log4j-core\1.0.13.5\log4j-core-1.0.13.5.jar RabbitMQ.provider
发送消息
hello hwx
hello已发送
发送消息
hwx已发送

消费者一

"C:\Program Files\Java\jdk-14.0.1\bin\java.exe" "-javaagent:D:\IntelliJ IDEA 2021.3.3\lib\idea_rt.jar=56312:D:\IntelliJ IDEA 2021.3.3\bin" -Dfile.encoding=UTF-8 -classpath E:\IDEA_Project\com.hwx.java\target\classes;C:\Users\lxkj\.m2\repository\com\rabbitmq\amqp-client\5.9.0\amqp-client-5.9.0.jar;C:\Users\lxkj\.m2\repository\org\slf4j\slf4j-api\1.7.30\slf4j-api-1.7.30.jar;C:\Users\lxkj\.m2\repository\commons-io\commons-io\2.8.0\commons-io-2.8.0.jar;C:\Users\lxkj\.m2\repository\log4j\log4j\1.2.17\log4j-1.2.17.jar;C:\Users\lxkj\.m2\repository\com\guicedee\services\sl4j\1.0.13.5\sl4j-1.0.13.5.jar;C:\Users\lxkj\.m2\repository\com\guicedee\services\log4j-core\1.0.13.5\log4j-core-1.0.13.5.jar RabbitMQ.consumer
C1等待消息
hello已拿到

进程已结束,退出代码130

消费者二

"C:\Program Files\Java\jdk-14.0.1\bin\java.exe" "-javaagent:D:\IntelliJ IDEA 2021.3.3\lib\idea_rt.jar=56318:D:\IntelliJ IDEA 2021.3.3\bin" -Dfile.encoding=UTF-8 -classpath E:\IDEA_Project\com.hwx.java\target\classes;C:\Users\lxkj\.m2\repository\com\rabbitmq\amqp-client\5.9.0\amqp-client-5.9.0.jar;C:\Users\lxkj\.m2\repository\org\slf4j\slf4j-api\1.7.30\slf4j-api-1.7.30.jar;C:\Users\lxkj\.m2\repository\commons-io\commons-io\2.8.0\commons-io-2.8.0.jar;C:\Users\lxkj\.m2\repository\log4j\log4j\1.2.17\log4j-1.2.17.jar;C:\Users\lxkj\.m2\repository\com\guicedee\services\sl4j\1.0.13.5\sl4j-1.0.13.5.jar;C:\Users\lxkj\.m2\repository\com\guicedee\services\log4j-core\1.0.13.5\log4j-core-1.0.13.5.jar RabbitMQ.consumer
C2等待消息
hwx已拿到
hwx确认完成
hello已拿到
hello确认完成

进程已结束,退出代码130

消费者C1拿到hello之后,在还没有处理完成,没有发送ACK时我们关闭程序,此时我们发现hello被

消费者C2拿到了,这说明在消费者没有发送ACK之前,RabbitMQ不会删除队列中的这个消息,没有处理完毕重新入队,被C2拿到。

不公平分发

在生产者发送消息之后,默认情况下,消费者采用轮询分发,每一个消费端轮流处理每一个消息,

但是在这种情况下,有些消费者可能处理速度很慢,有些很快,这样造成快的消费端浪费的资源,这里我们可以设置分发方式。

设置分发方式在消费端的信道设置

//      true表示自动应答,false表示手动应答
        boolean AutoACk=false;

//      1表示不公平分发(能者多劳) ,0表示轮询分发
        int  pp=1;
        Channel.basicQos(pp);
        System.out.println( "C3等待消息");
        Channel.basicConsume(DL,AutoACk,DeliverCallback,CancelCallback);

其中的 Channel.basicQos()方法就是设置分发方式,默认是0。

发布确认

RabbitMQ学习_第1张图片

刚刚说到,假若在信息设置为持久化发送之后,但是在RabbitMQ还没有持久化的间隙时间内,RabbitMQ发送宕机,那么信息就丢失了,所以需要发布确认,即当RabbitMQ确实已经持久化之后,向生产者发布一个信息确认。

开启方式在创建信道后,使用

Channel.confirmSelect();

进行发布确认。

异步发布确认

交换机

FANOUT(消息/订阅)模式

消费者1

package RabbitMQ.three;


import com.rabbitmq.client.CancelCallback;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.DeliverCallback;
import comp.getConn;

public class provider {
    public static final String  EX="logs";

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

        Channel getchannel = getConn.getchannel();


//     声明交换机
       getchannel.exchangeDeclare(EX,"fanout");

//       获取临时队列 ,消费者断开连接就删除了
        String queue = getchannel.queueDeclare().getQueue();

//        第一个队列,第二个交换机,第三个队列与交换机绑定的key
        getchannel.queueBind(queue,EX,"");

        DeliverCallback DeliverCallback=(one,two)->{
            System.out.println(new String(two.getBody(),"UTF-8"));
        };

        CancelCallback CancelCallback=consumer->{

        };

//        队列名,是否开启自动应答,
        getchannel.basicConsume(queue,true,DeliverCallback,CancelCallback);
    }
}

消费者2

package RabbitMQ.three;


import com.rabbitmq.client.CancelCallback;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.DeliverCallback;
import comp.getConn;

public class provider2 {
    public static final String  EX="logs";

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

        Channel getchannel = getConn.getchannel();


//     声明交换机   fanout  (消息/订阅模式)
       getchannel.exchangeDeclare(EX,"fanout");

//       获取临时队列 ,消费者断开连接就删除了
        String queue = getchannel.queueDeclare().getQueue();

//        第一个队列,第二个交换机,第三个队列与交换机绑定的key
        getchannel.queueBind(queue,EX,"");

        DeliverCallback DeliverCallback=(one,two)->{
            System.out.println(new String(two.getBody(),"UTF-8"));
        };

        CancelCallback CancelCallback=consumer->{

        };

//        队列名,是否开启自动应答,
        getchannel.basicConsume(queue,true,DeliverCallback,CancelCallback);
    }
}

生产者

package RabbitMQ.three;


import com.rabbitmq.client.Channel;
import comp.getConn;

import java.util.Scanner;

public class consumer {

    public static final String  JHJ="logs";

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

        Channel getchannel = getConn.getchannel();


        Scanner in=new Scanner(System.in);
        do{
            System.out.println("输入消息:");
            String  tx=in.next();
            getchannel.basicPublish(JHJ,"",null,tx.getBytes("UTF-8"));
        }while (in.hasNext());

    }
}

这里获取一个临时队列,绑定的key为字符空,这里的两个消费者代码是完全一样的,

生产者向队列绑定交换机的key发送消息,即"",因为消费者一和二绑定的都是"",所以两个人都可以收到。即实现了消息/订阅,即广播。

DIRECT 直接模式

直接模式中,即可以针对性的发送给某些消费端

消费者一

//      DIRECT为直连模式
        getchannel.exchangeDeclare(JHJ, BuiltinExchangeType.DIRECT);

//       设置队列
        getchannel.queueDeclare("ap_one",false,false,false,null);

//        绑定交换机,key值为info
        getchannel.queueBind("ap_one",JHJ,"info");
        getchannel.queueBind("ap_one",JHJ,"warn");

消费者二

//      DIRECT为直连模式
        getchannel.exchangeDeclare(JHJ, BuiltinExchangeType.DIRECT);

//       设置队列
        getchannel.queueDeclare("ap_two",false,false,false,null);

//        绑定交换机,key值为error
        getchannel.queueBind("ap_two",JHJ,"error");

生产者发送消息

getchannel.basicPublish(JHJ,"info",null,iix.getBytes(StandardCharsets.UTF_8));

这里的第一项是交换机名称,第二项是key,这里是向key为info发送消息,即消费者一才能收到,

当然,消费者一绑定了两个key,所以向warn发送也是消费者一才能收到,向eroor发送就只有

消费者二才能收到。

OTPIC 主题模式

主题模式主要就是设置key值改变了

key值的设置必须满足 单词.单词 ,这里的单词可以是小于255的任意字符,只有之间用 .  连接即可

消费者一

        getchannel.queueDeclare("one",false,false,false,null);

        getchannel.queueBind("one",HHH,"*.vip.*");

消费者二

getchannel.queueDeclare("one",false,false,false,null);

        getchannel.queueBind("one",HHH,"*.vip.vip");

消费者三

        getchannel.queueDeclare("two",false,false,false,null);

        getchannel.queueBind("two",HHH,"user.vip.*");

这里分别向

1. user.vip.ee  发送消息

2. er.vip.vip 发送消息

3. erer.common.pp 发送消息

其中,1被消费者三的two队列和one队列接收

2同时满足消费者一和消费者二,但是由于两个消费者是同一个队列,

所以只能有一个获取消息

3.不满足任何一个队列

你可能感兴趣的:(spring,cloud,中间件)