rabbitMQ学习笔记

不同MQ的特点

1.ActiveMQ

activemq是能力强劲的开源消息总线,它是一个完全支持JMS规范的消息中间件,丰富的api,多种集群架构模式让activemq在业界成为牌的消息中间间,中小企业用的多

缺点:性能不高

命令行的方式操作linux上的rabiitmq

systemctl  start  abbitmq-server             #启动命令

systemctl  restart  rabbitmq-server        #重启命令

systemctl  stop  rabbitmq-server           #停止命令

systemctl   status  rabbitmq-server       #查看状态命令

systemctl    #系统控制命令的简写(contos 的命令)

rabbitmq 提供了一套管理命令

rabbitmqctl     help    #查看帮助命令

rabbitmq 插件管理命令

rabbitmq-plugins

rabbitmq-plugins  list    #查所有插件

 

docker 安装 rabbitmq

1.docker pull rabbitmq:management   #拉取rabbitmq镜像,在dockerhub上搜索rabbitmq,要带management,是带管理界面的。

   docker pull  rabbitmq:3.8.7-management

启动docker

    docker run -d --hostname localhost --name rabbitmq3.8.7 -p 5672:5672 -p 15672:15672 rabbitmq:3.8.7-management

rabbitmq管理界面初识

1.overview:整合个rabbitmq的详细信息有一个概览。

2.connection:连接,当前客户端和rabbitmq的连接,可搜索等

3.channels:通道,通过通道去传递消息。可查询,正则表达式查询,分类。

4.exchanges:交换机(路由),安装完成之后默认7种路由

           

           direct:为直连的意思

             features为D:表示数据存储在磁盘中,数据不会随着rabbitmq重庆而丢失。

              fanout:为广播

               headers:已头的形式

                match:匹配的模式

                 trace:

                 topic:发布订阅模式

还可以通过 add添加自定义交换机

5.queues:队列,可以新增删除等。

6.admin:用户相关,添加用户,分配权限等。

rabbitmq的端口:

amqp:5672:这个端口是我们程序通信的端口

clustering:25672:这个是集群通信的端口

http:15672:这个是访问管理界面的端口

amqp协议

rabbitmq中的虚拟主机(相当于数据库中的库)起到隔离的作用,让数据边界更清晰。还有权限控制等

所以在使用的时候,要先创建用户,在创建虚拟主机,再绑定虚拟主机和用户,最后才是使用。

rabbitmq的集中工作模式

1.直连(hello world)模式

封装连接工具类

public class RabbitMqUtils {

    private static  ConnectionFactory connectionFactory;
    static {
        //重量级的资源,类加载的时候只执行一次
        connectionFactory=new ConnectionFactory();
        connectionFactory.setHost("192.168.31.71");
        connectionFactory.setPort(5672);
        connectionFactory.setVirtualHost("/ems");
        connectionFactory.setUsername("ems");
        connectionFactory.setPassword("123");
    }

    /**
     * 创建工具类
     * @return
     */
    public static Connection getConnection(){
        try{
            //创建链接对理想
            return connectionFactory.newConnection();
        }catch (Exception e){
            e.printStackTrace();
        }
        return  null;
    }

    /**
     * 关闭连接
     * @param channel
     * @param conn
     */
    public static void closeConnetionAndChanel(Channel channel, Connection conn){
        try{
            if(null!=channel){
                channel.close();
            }
            if(null!=conn){
                conn.close();;
            }
        }catch (Exception e){
            e.printStackTrace();
        }

    }
}

1生产者:

public class provider {

    @Test
    public void send() throws IOException, TimeoutException {
        //创建连接mq的连接工厂对象
       /* ConnectionFactory connectionFactory=new ConnectionFactory();
        //设置连接rabbitmq主机
        connectionFactory.setHost("192.168.31.71");
        //设置端口号
        connectionFactory.setPort(5672);
        //设置连接那个虚拟主机
        connectionFactory.setVirtualHost("/ems");
        //设置登录名
        connectionFactory.setUsername("ems");
        //设置登陆密码
        connectionFactory.setPassword("123");
        //获取连接对象
        Connection connection = connectionFactory.newConnection();*/
        Connection connection=RabbitMqUtils.getConnection();
        //获取连接中通道
        Channel channel=connection.createChannel();
        //通道绑定对应消息队列
        //参数1:队列名称,如果队列不存在,自动创建,队列名称为hello
        //参数2:定义队列特性是否要持久化,true持久化队列,false 不持久化, 若为false,rabbitmq重启时队列丢失(不存在),这个参数只是保证对队列持久化,就算为true,消息也会丢失
        //参数3:exclusive 是否独占队列true独占队列,false不独占,独占表示队列只能被当前通道(连接)绑定,如果有其他队列绑定则报错,一般为false
        //参数4:autoable:是否在消费完成后自动删除队列,true自动删除,false不自动删除,自动删除是在断开连接时删除,不是消费完消息。
        //参数5:额外附加参数
        //注意:同一个通道可以向不同的队列发布消息,真正发布消息的是发布方法。
        //消费者和生产者队列参数要保证严格一致
        channel.queueDeclare("hello",false,false,false,null);

        //发布消息
        //参数1:交换机名称
        //参数2:队列名称
        //参数3:额外的消息设置,设置为MessageProperties.PERSISTENT_TEXT_PLAIN表示消息持久化
        //参数4:消息的内容
        channel.basicPublish("","hello", MessageProperties.PERSISTENT_TEXT_PLAIN,"hello rabbitmq".getBytes());

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

    }
}

2.消费者:为什么消费者使用main函数呢,junit不支持程序一直运行,执行完毕就关闭程序,看不见效果。

public class customer {

     public static void main(String[] args) throws IOException, TimeoutException {
        /*ConnectionFactory connectionFactory=new ConnectionFactory();
        connectionFactory.setHost("192.168.31.71");
        connectionFactory.setPort(5672);
        connectionFactory.setVirtualHost("/ems");
        connectionFactory.setUsername("ems");
        connectionFactory.setPassword("123");*/

        //创建链接对理想

         Connection connection= RabbitMqUtils.getConnection();
        //创建通道
        Channel channel=connection.createChannel();
        //通道绑定对象
        channel.queueDeclare("hello",false,false,false,null);
        //消费消息
        channel.basicConsume("hello",true,new DefaultConsumer(channel){
            public  void  handleDelivery(String consumerTag, Envelope envelope,AMQP.BasicProperties properties,byte[] body){
                System.out.printf("new string(body)="+new String(body));
            }
        });
         RabbitMqUtils.closeConnetionAndChanel(channel,connection);
    }

}

这种模式适用于登陆发送验证,加积分等场景。

2.工作模式(work模型)

1.平均消费模型

   work queues,也被称为(task queues)任务模型,当消息处理比较耗时的时候,可能生产消息的速度远远大于消费的速度,长此以往,消息就会堆积越来越多,无法及时处理,此时就可以使用work模型,让多个消费者绑定到一个队列,共同消费队列中的消息,队列中的消息一旦消费,就会消失,因此任务不会被重复执行。

注意:在默认的条件下,我们消费的消息时平均分配的。不管消费者处理的时间长短,处理的消息都是同样多的。

这种模式下:其实消费者已经拿到消息,只是再等待处理,而不是还存储在rabbitmq上的。

生产者:

public class provider {
    public static void main(String[] args) throws IOException {
        //获取连接对象
        Connection connection = RabbitMqUtils.getConnection();
        //获取通道对象
        Channel channel=connection.createChannel();
        //通过通道声明队列
        channel.queueDeclare("work",true,false,false,null);
        //循环生产消息
        for(int i=1;i<=20;i++){
            channel.basicPublish("","work",null,(i+"hello work quene").getBytes());
        }
        RabbitMqUtils.closeConnetionAndChanel(channel,connection);
    }
}

 

消费者1:

public class customer1 {
    public static void main(String[] args) throws IOException {
        Connection connection= RabbitMqUtils.getConnection();
        Channel channel=connection.createChannel();
        //绑定队列
        channel.queueDeclare("work",true,false,false,null);
        channel.basicConsume("work",true,new DefaultConsumer(channel){
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties,byte[] body){
              try{
                  Thread.sleep(2000);
              }catch (Exception e){
                  e.printStackTrace();
              }
                System.out.println("消费者-1:"+new String(body));
            }
        });
    }
}

消费者2:

public class customer2 {
    public static void main(String[] args) throws IOException {
        Connection connection= RabbitMqUtils.getConnection();
        Channel channel=connection.createChannel();
        //绑定队列
        channel.queueDeclare("work",true,false,false,null);
        channel.basicConsume("work",true,new DefaultConsumer(channel){
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties,byte[] body){
                System.out.println("消费者-2:"+new String(body));
            }
        });
    }
}

 

2.能者多劳

这个和消息确认机制有关。自动消费确认设置为true,接收到消息之后,马上就确认已经消费了,消费者还没有处理完,或者消费者挂了,消息就丢失了,不建议使用自动确认。

处理方法:

所以在实现能者多劳就是,不设置为自动消费同时将每次消费的条数设置为1条,并且处理完成之后,手动确认消息已经消费。

消费者1:

public class customer1 {
    public static void main(String[] args) throws IOException {
        Connection connection= RabbitMqUtils.getConnection();
        Channel channel=connection.createChannel();
        channel.basicQos(1);//设置每次只能消费一条消息。
        //绑定队列
        channel.queueDeclare("work",true,false,false,null);
        //参数1:队列名称
        //参数2.自动确认,消费者自动向rabbitmq确认消息,。设置为false则不会
        channel.basicConsume("work",false,new DefaultConsumer(channel){
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties,byte[] body) throws IOException {
              try{
                  Thread.sleep(2000);
              }catch (Exception e){
                  e.printStackTrace();
              }
                System.out.println("消费者-1:"+new String(body));
                channel.basicAck(envelope.getDeliveryTag(),false);
            }
        });
    }
}

消费者2:

public class customer2 {
    public static void main(String[] args) throws IOException {
        Connection connection= RabbitMqUtils.getConnection();
        Channel channel=connection.createChannel();
        channel.basicQos(1);//设置每次只能消费一条消息。
        //绑定队列
        channel.queueDeclare("work",true,false,false,null);
        channel.basicConsume("work",false,new DefaultConsumer(channel){
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties,byte[] body) throws IOException {
                System.out.println("消费者-2:"+new String(body));
                //开启手动确认。
                //参数1,确认列表中那个具体的消息,通过envelope.getDeliveryTag()拿到消息唯一id,
                //参数2:是否开启多个消息同时确认。
                channel.basicAck(envelope.getDeliveryTag(),false);
            }
        });
    }
}

3.fanout模型(发布订阅模型)也叫广播模型

消息发送到交换机,交换机会将消息发送到绑定了当前交换机的所有消费者。

广播模式下消息发送流程:

可以有多个消费者,

每个消费者有自己的queue(队列)(这里的队列是临时队列)

每个队列都要绑定exchange(交换机)

生产者发送的消息,只能发送到交换机,交换机来决定要发给那个队列,生产者无法决定。

交换机把消息发送给绑定过的队列(所有绑定交换机的队列)

队列的消费者都能拿到消息,是西安一条消息被多个消费者消费。

临时队列:消息消费之后就删除的队列

生产者:

public class provider {
    public static void main(String[] args) throws IOException {
        Connection connection= RabbitMqUtils.getConnection();
        Channel channel=connection.createChannel();

        //将通道声名指定交换机
        //参数1:交换机名称
        //参数2:交换机类型  fanout为广播类型
        channel.exchangeDeclare("logs","fanout");
        //发送消息
        //在广播里面路由key无意义
        channel.basicPublish("logs","",null,"fanout type message".getBytes());
        RabbitMqUtils.closeConnetionAndChanel(channel,connection);
    }
}

消费者:

public class Customer1 {
    public static void main(String[] args) throws IOException {
        //获取连接对上
        Connection connection= RabbitMqUtils.getConnection();
        Channel channel=connection.createChannel();

        //通道绑定交换机
        channel.exchangeDeclare("logs","fanout");
        //创建临时队列
        String queueName=channel.queueDeclare().getQueue();
        //绑定交换机和队列
        channel.queueBind(queueName,"logs","");
        //消费消息
        channel.basicConsume(queueName,true,new DefaultConsumer(channel){
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                System.out.printf("消费者1 "+new String(body));
            }
        });
    }
}

广播模型,多个消费者才体现出效果,将消费者多复制几份就行了。

4.direct模型(路由模型)

再fanout模式中,一条消息,会被所有订阅的队列消费,但是在某些场景下,我们希望不同的消息被不同的队列消费,这时就要用到direct类型的exchange。

再direct模型下:

队列与交换机的绑定,不能是任意绑定了,而是要指定一个routingkey(路由key)

消息的发送方在向exchange发送消息时,也必须指定消息的routingkey。

exchange不再把消息交给每一个绑定的队列,而是根据消息的routing key 进行判断,只有队列的routing key与消费者的routing key 完全一致,才会接受到消息

生产者:

public class provider {
    public static void main(String[] args) throws IOException {
        //获取连接
        Connection connection= RabbitMqUtils.getConnection();
        Channel channel=connection.createChannel();
        //定义交换机的名称
        String exchangeName="logs_direct";
        //通过通道声名交换机,
        //参数1:交换机名称
        //参数2:direct  路由模式
        channel.exchangeDeclare(exchangeName,"direct");
        String routingkey="error";
        channel.basicPublish(exchangeName,routingkey,null,("这是direct模型发布的routekey【"+routingkey+"】").getBytes());

        RabbitMqUtils.closeConnetionAndChanel(channel,connection);
    }
}

消费者1:

public class customer1 {
    public static void main(String[] args) throws IOException {
        Connection connection= RabbitMqUtils.getConnection();
        Channel channel=connection.createChannel();
        //定义交换机的名称
        String exchangeName="logs_direct";
        //通道声名交换机以及交换的类型
        channel.exchangeDeclare(exchangeName,"direct");
        String queueName=channel.queueDeclare().getQueue();
        //基于路由key绑定队列和交换机
        channel.queueBind(queueName,exchangeName,"error");
        //获取消费者的消息
        channel.basicConsume(queueName,true,new DefaultConsumer(channel){
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                System.out.println("消费者1"+new String(body));
            }
        });

    }
}

消费者2:

public class customer2 {
    public static void main(String[] args) throws IOException {
        Connection connection= RabbitMqUtils.getConnection();
        Channel channel=connection.createChannel();
        //定义交换机的名称
        String exchangeName="logs_direct";
        //通道声名交换机以及交换的类型
        channel.exchangeDeclare(exchangeName,"direct");
        String queueName=channel.queueDeclare().getQueue();
        //基于routing key(info)绑定队列和交换机
        channel.queueBind(queueName,exchangeName,"info");
        //基于routing key(error)绑定队列和交换机
        channel.queueBind(queueName,exchangeName,"error");
        //基于routing key(warning)绑定队列和交换机
        channel.queueBind(queueName,exchangeName,"warning");
        //获取消费者的消息
        channel.basicConsume(queueName,true,new DefaultConsumer(channel){
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                System.out.println("消费者1"+new String(body));
            }
        });

    }
}

 

5.topic模型(动态路由模型)

topic类型的exchange与direct相比,都可以根据routingkey 把消息路由到不同的队列,只不过topic类型的exchange可以让队列在绑定routingkey的时候使用通配符,这种模型routingkey 一般都是由一个或多个单词组成,多个单词之间以“.”分割,列如 item.insert

* 表示匹配一个单词

# 表示匹配多个单词

生产者:

public class provider {
    public static void main(String[] args) throws IOException {
        Connection connection= RabbitMqUtils.getConnection();
        Channel channel=connection.createChannel();

        //声名交换机
        channel.exchangeDeclare("topics","topic");
        //发布消息
        String routingkey="user.save";
        channel.basicPublish("topics",routingkey,null,("zheshi topic moxing").getBytes());
        //关闭
        RabbitMqUtils.closeConnetionAndChanel(channel,connection);
    }
}

消费者1:

public class Customer1 {
    public static void main(String[] args) throws IOException {
        Connection connection= RabbitMqUtils.getConnection();
        Channel channel=connection.createChannel();

        //s声名交换机和交换机类型
        channel.exchangeDeclare("topics","topic");
        //创建一个临时队列
        String queue=channel.queueDeclare().getQueue();
        //绑定队列和交换机,同台通配符形式 routing key
        channel.queueBind(queue,"topics","user.*");

        //消费消息
        channel.basicConsume(queue,true,new DefaultConsumer(channel){
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                System.out.printf("消费者1 "+new String(body));
            }
        });
    }
}

消费者2

public class Customer2 {
    public static void main(String[] args) throws IOException {
        Connection connection= RabbitMqUtils.getConnection();
        Channel channel=connection.createChannel();

        //s声名交换机和交换机类型
        channel.exchangeDeclare("topics","topic");
        //创建一个临时队列
        String queue=channel.queueDeclare().getQueue();
        //绑定队列和交换机,同台通配符形式 routing key
        //前面匹配一个,后片匹配多个,中间必须由user
        channel.queueBind(queue,"topics","*.user.#");

        //消费消息
        channel.basicConsume(queue,true,new DefaultConsumer(channel){
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                System.out.printf("消费者1 "+new String(body));
            }
        });
    }
}

6.rpc 模型

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值