Rabbitmq消息队列:HelloWorld消息直传模式简单应用

一、引入依赖

  新建一个maven项目,在pom.xml配置文件中加入以下依赖。

    <dependencies>
        <dependency>
            <groupId>com.rabbitmq</groupId>
            <artifactId>amqp-client</artifactId>
            <version>4.5.0</version>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.3.2</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
    </dependencies>

二、封装工具类

  新建一个用于rabbitmq连接工具类RabbitmqConUtil,内容如下:

package utils;

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

public class RabbitmqConUtil {

    //rabbitmq服务器地址(此处的*应该为个人服务器的ip地址)
    private static String ipAddress = "*.*.*.*";
    //rabbitmq端口
    private static Integer port = 5672;
    //rabbitmq自建的测试专用用户名
    private static String userName = "test";
    //rabbitmq自建的测试专用用户密码
    private static String password = "test";
    //rabbitmq自建的测试虚拟主机地址
    private static String virtualHost = "test";

    //获取rabbitmq链接
    public static Connection getConnection() throws Exception{
        ConnectionFactory connectionFactory = new ConnectionFactory();
        //给链接工厂配置信息
        connectionFactory.setHost(ipAddress);
        connectionFactory.setPort(port);
        connectionFactory.setUsername(userName);
        connectionFactory.setPassword(password);
        connectionFactory.setVirtualHost(virtualHost);
        //实例化链接
        Connection connection = connectionFactory.newConnection();
        return connection;
    }
}

三、测试HelloWorld直传模式

  直传模式不需要交换机,只需要最基本的生产者和消费者。

  1、生产者

  创建一个Give类,先使用刚才编写的工具类来获取rabbitmq连接,再创建通道,声明使用的队列并发送内容。

package test.hello;

import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import utils.RabbitmqConUtil;

public class Give {

    //本次测试使用的消息队列名称
    private final static String QUEUE = "test-hello";

    public static void main(String[] args) throws Exception{
        //获取rabbitmq链接
        Connection connection = RabbitmqConUtil.getConnection();
        //创建通道
        Channel channel = connection.createChannel();
        //声明使用的队列
        channel.queueDeclare(QUEUE,false,false,false,null);
        //发送内容
        channel.basicPublish("",QUEUE,null,"生产者-》消费者".getBytes());
    }
}

  在声明使用的队列时,注意要和消费者在同一个队列里,这样才能保证信息的正确传递。

  channel.queueDeclare()方法中的参数分别为:

  第一个参数:队列名称
  第二个参数:是否持久化,boolean类型,如果持久化就会把消息存储到rabbitmq自带的数据库里,不持久化的话消息就会在rabbitmq重启后丢失
  第三个参数:是否排外,如果为true,则只允许这个通道来使用这个队列,其他通道不允许访问
  第四个参数:是否自动删除
  第五个参数:自己额外想带的参数

  channel.basicPublish()方法中的参数分别为:

  第一个参数:要使用的交换机,此处为helloworld直传测试,所以不设置交换机
  第二个参数:要用通道把消息内容发送到哪个队列,填写队列名称
  第三个参数:要带的属性
  第四个参数:消息内容(byte[]格式)

  运行结果如下:

  

  2、消费者

  创建一个Get类,使用刚才编写的工具类来获取rabbitmq连接,再创建通道,声明使用的队列,定义DefaultConsumer类型的消费者并重写其内部的handleDelivery方法,在方法内部接受内容并处理和确认消息,防止数据丢失。

package test.hello;

import com.rabbitmq.client.*;
import utils.RabbitmqConUtil;

import java.io.IOException;

public class Get {

    //本次测试使用的消息队列名称
    private final static String QUEUE = "test-hello";

    public static void main(String[] args) throws Exception {
        //获取rabbitmq链接
        Connection connection = RabbitmqConUtil.getConnection();
        //创建通道
        final Channel channel = connection.createChannel();
        //声明使用的队列
        channel.queueDeclare(QUEUE,false,false,false,null);

        //定义消费者
        DefaultConsumer defaultConsumer = new DefaultConsumer(channel){
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties,byte[] body) throws IOException{
                //收到消息并处理
                String message = new String(body,"UTF-8");
                //确认消息,防止丢失
                channel.basicAck(envelope.getDeliveryTag(),false);

                System.out.println(message);
            }
        };
        //接收消息
        channel.basicConsume(QUEUE,false,defaultConsumer);
    }
}

  获取连接、创建通道、声明队列这块和生产者一致,因为用的是同一个连接下的同一个队列。

  定义消费者的时候,使用DefaultConsumer老版本的QueueingConsumer已过期,在后续版本可能会移除,这个比较新且能手动确认消息。手动确认消息的意义在于,数据安全性。如果是自动确认消息的话,在拿到消息到给到用户的过程中,如果有存在处理消息的逻辑一旦出现故障,用户还没有拿到消息,但此时rabbitmq已经自动确认并且自动删除的话就会造成消息数据的丢失。所以要在处理消息的逻辑走完之后,再去手动确认消息,保证数据安全。

  handleDelivery方法中对接受的消息进行了处理,调整为UTF-8字符集。

  handleDelivery自循环的方法,只要不关闭通道和连接,它就会一直运行,Give类每次运行推出的消息,都会被它直接接收并显示。

  channel.basicAck()方法是手动确认消息,false为确认收到消息,true为拒绝收到消息。

  channel.basicConsume()方法中的参数分别为:

第一个参数:接受消息用的队列名称
第二个参数:是否自动接收消息,这里用false,因为在重写的方法里已经手动确认了,所以这里就不用自动接收
第三个参数:用来接收消息的消费者实例

  运行结果如下:

  

  

四、暂存问题记录

  学完这个之后突然发现一个问题,就是在发送和接收消息后,是否要对通道和连接进行关闭?

  从内存上来说,应该要关闭的,否则会造成内存泄漏。

  但是加上通道和连接的关闭之后,有两点问题。第一点是频繁的创建连接和通道,比较浪费资源,因为本身连接和通道是可以长期使用的,第二点就是在关闭通道和连接的过程中,可能接受发送或者接受消息的操作还没有执行完,这时候可能会造成执行失败或者是报错。这块还需要多了解一些,目前就是浅显的测试学会如何使用。

 

posted @ 2023-11-02 11:11  我命倾尘  阅读(10)  评论(0编辑  收藏  举报