RabbitMQ之java操作队列,接收和发送消息

1.简单队列模式

1.1模型

在这里插入图片描述P:消息的生产者。
红色的:队列
C:洧费者。

1.2连接上rabbitmq

创建一个工具类来连接

引入jar包或依赖

<dependency>
            <groupId>org.springframework.amqp</groupId>
            <artifactId>spring-rabbit-test</artifactId>
            <scope>test</scope>
</dependency>
public class ConnectionUtil {

    public static Connection getConnection() throws IOException, TimeoutException {
        -----定义一个连接工厂
        ConnectionFactory connectionFactory = new ConnectionFactory();
         -----设置服务地址
        connectionFactory.setHost("127.0.1");
         -----设置端口号地址
        connectionFactory.setPort(5672);
         -----设置数据库
        connectionFactory.setVirtualHost("/rabbitmq");
         -----设置用户名和密码
        connectionFactory.setUsername("MXH");
        connectionFactory.setPassword("123456");
        
         return connectionFactory.newConnection();
    }
}

1.3 创建生产者(消息发送方)

public class send {
    private static final String QUEUE_NAME="MXH";
    public static void main(String[] args) throws IOException, TimeoutException {
        ------创建一个连接
        Connection connection = ConnectionUtil.getConnection();
        ------从连接中获取一个通道
        Channel channel = connection.createChannel();
        ------创建一个消息队列  QUEUE_NAME:队列名
        channel.queueDeclare(QUEUE_NAME,false,false,false,null);

        String msg = "hello,rqbbitmq你好1";
        channel.basicPublish("",QUEUE_NAME,null,msg.getBytes());

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

1.4 创建消息接收方

public class received {
    private static final String QUEUE_NAME="MXH";
    public static void main(String[] args) throws IOException, TimeoutException {
       ------创建一个连接
        Connection connection = ConnectionUtil.getConnection();
        ------创建通道
        Channel channel = connection.createChannel();
        ------创建一个消息队列  QUEUE_NAME:队列名
        channel.queueDeclare(QUEUE_NAME,false,false,false,null);
        ------定义队列消费者
        DefaultConsumer consumer = new DefaultConsumer(channel)
        {
            ------handleDelivery方法可以只要消息队列中有消息,配合监听就能一直读取
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope,
                                       AMQP.BasicProperties properties,
                                       byte[] body) throws IOException
            {
                String msg = new String(body);
                System.out.println("接收到消息:"+msg);
            }
        };
        ------监听队列
        channel.basicConsume(QUEUE_NAME,true, consumer);
    }
}

1.5简单队列的不足点

耦合性高,生产者- - -对应消费者(如果我想有多个消费者消费队列中消息,这时候就不行了)。队列名变更这时候得同时变更.

2.Work Queues模式

2.1轮询分发模式

在这里插入图片描述为什么会出现工作队列
Simple队列是一一对应的,而且我们实际开发,生产者发送消息是毫不费力的,而消费者一般是要跟业务相结合的,消费者接收到消息之后就需要处理可能需要花费时间,这时候队列就会积压了很多消息。

创建一个生产者

public class send {

    private static final String QUEUE_NAME="MXH";
    public static void main(String[] args) throws IOException, TimeoutException {
        //创建一个连接
        Connection connection = ConnectionUtil.getConnection();
        //创建一个通道
        Channel channel = connection.createChannel();
        //创建一个队列,用户名
        channel.queueDeclare(QUEUE_NAME,false,false,false,null);

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

创建第一个消费者

public class received {
    private static final String QUEUE_NAME="MXH";
    public static void main(String[] args) throws IOException, TimeoutException {
        //创建一个连接
        Connection connection = ConnectionUtil.getConnection();
        //创建一个通道
        Channel channel = connection.createChannel();
        //创建一个队列,用户名
        channel.queueDeclare(QUEUE_NAME,false,false,false,null);

        DefaultConsumer consumer = new DefaultConsumer(channel)
        {
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope,
                                       AMQP.BasicProperties properties,
                                       byte[] body) throws IOException
            {
                String msg = new String(body);
                System.out.println("RE"+msg);
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e)
                {
                    e.printStackTrace();
                }finally
                {
                    System.out.println("done");
                }
            }
        };
        channel.basicConsume(QUEUE_NAME,true, consumer);
    }
}

创建第二个消费者

public class receiver2
{
    private static final String QUEUE_NAME="MXH";
    public static void main(String[] args) throws IOException, TimeoutException
    {
        ------创建一个连接
        Connection connection = ConnectionUtil.getConnection();
       ------创建一个通道
        Channel channel = connection.createChannel();
        ------创建一个队列,用户名
        channel.queueDeclare(QUEUE_NAME,false,false,false,null);

        DefaultConsumer consumer = new DefaultConsumer(channel)
        {
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope,
                                       AMQP.BasicProperties properties,
                                       byte[] body) throws IOException
            {
                String msg = new String(body);
                System.out.println("RE"+msg);
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e)
                {
                    e.printStackTrace();
                }finally
                {
                    System.out.println("done");
                }
            }
        };
        channel.basicConsume(QUEUE_NAME,true, consumer);
    }
}

现象

消费者1和消费者2处理的消息是一样的。
消费者1:偶数。
洧费者2:奇数。
这种方式叫做轮询分发(round-robin)结果就是不管谁忙活着谁清闲都不会多给一个消息
任务消息总是你-一个我-一个。

2.2 公平分发模式

使用公平分发必须
关闭自动应答 ack 改成手动

创建一个生产者
需要加channel.basicQos(1):
注意:channel.basicQos(1):限制发送给同一个消费者不得超过一条消息,每个消费者发送确认消息之前,消息队列不发送下一个消息到消费者

public class send {

    private static final String QUEUE_NAME="MXH";
    public static void main(String[] args) throws IOException, TimeoutException {
        创建一个连接
        Connection connection = ConnectionUtil.getConnection();
        创建一个通道
        Channel channel = connection.createChannel();
        创建一个队列,用户名
        channel.queueDeclare(QUEUE_NAME,false,false,false,null);
      每个消费者发送确认消息之前,消息队列不发送下一个消息到消费者,  一 次只处理一个消息
         限制发送给同一个消费者不得超过一条消息

        int prefetch=1;
        channel.basicQos(prefetch);

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

创建第一个消费者
注意:
//一次应答前只发送一次
channel.basicQos(1);

//手动回执
channel.basicAck(envelope.getDeliveryTag(),false);

//自动应答 true为开启 false为关闭
boolean autoAck = false;
channel.basicConsume(QUEUE_NAME,autoAck, consumer);

public class received {
    private static final String QUEUE_NAME="MXH";
    public static void main(String[] args) throws IOException, TimeoutException {

        //创建一个连接
        Connection connection = ConnectionUtil.getConnection();
        //创建一个通道
        Channel channel = connection.createChannel();
        //一次应答前只发送一次
        channel.basicQos(1);
        //创建一个队列,用户名
        channel.queueDeclare(QUEUE_NAME,false,false,false,null);

        DefaultConsumer consumer = new DefaultConsumer(channel)
        {
            int i =0;
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope,
                                       AMQP.BasicProperties properties,
                                       byte[] body) throws IOException
            {
                int p = i++;
                String msg = new String(body);
                System.out.println("RE"+msg);
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e)
                {
                    e.printStackTrace();
                }finally
                {
                    //手动回执
                    channel.basicAck(envelope.getDeliveryTag(),false);
                }
                System.out.println(i);
            }

        };
        boolean autoAck = false;//自动应答 true为开启 false为关闭
        channel.basicConsume(QUEUE_NAME,autoAck, consumer);
    }
}

创建第二个消费者

public class receiver2
{
    private static final String QUEUE_NAME="MXH";
    public static void main(String[] args) throws IOException, TimeoutException
    {
        //创建一个连接
        Connection connection = ConnectionUtil.getConnection();
        //创建一个通道
        Channel channel = connection.createChannel();
        //一次应答前只发送一次
        channel.basicQos(1);
        //创建一个队列,用户名
        channel.queueDeclare(QUEUE_NAME,false,false,false,null);

        DefaultConsumer consumer = new DefaultConsumer(channel)
        {
            int i=0;
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope,
                                       AMQP.BasicProperties properties,
                                       byte[] body) throws IOException
            {
                i++;
                String msg = new String(body);
                System.out.println("RE"+msg);
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e)
                {
                    e.printStackTrace();
                }finally
                {
                    System.out.println(i);
                    //手动回执
                    channel.basicAck(envelope.getDeliveryTag(),false);

                }
            }
        };
        boolean autoAck = false;//自动应答 true为开启 false为关闭
        channel.basicConsume(QUEUE_NAME,autoAck, consumer);
    }
}

现象:
现象:消费者2处理的消息比消费者1多,能者多劳。

消息应答

boolean autoack= falsez
channel.basicConsume (QUEUENANE, autoAck,consumer)

boolean autonck=true; (自动确认模式)一rabbitnq将消息分发给消费者 ,就会从内存中珊除;。
这种情况下,如果杀死正在执行的消费者,就会丢失正在处理的消息。

boolean autcAck=false; (手动模式),如果有一个消费者挂掉,rabbitmq不会将内存的信息删除,直到下个消费者处理后返回应答信息才会删除
洧息应答默认是打开的,falser;

大家想想如果我rabbitmq挂了我们的消息任然会丢失!!!

消息持久化

可以在rabbitmq挂了下而不丢失数据

//声明队列。
boolean durable= false;fasle为不持久化,true则是允许持久化

channel.queueDeclare (QUEUE_ NAME, durable, false, false, nu11)
我们将程序中的boolean durable= false;改成true;是不可以的 ,尽管代码是正确的,rabbitmq不许重新定义(不同参数)一个已存在的队列。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值