RabbitMQ的初步使用

概念,混个脸熟

producer(生产者)
connection(连接)
channel(通道,一连接里多个通道)
broker(服务器实例)
virtual host(虚拟主机,可用于用户权限把控,一次连接都是基于虚拟主机)
exchange(交换机)
routing key(路由键)
binding(绑定)
queue(队列)
consumer(消费者)

五种模式

前置准备: 获取通道

// 创建连接工厂
ConnectionFactory connectionFactory = new ConnectionFactory();
// 设置connection所需要的要素,就像jdbc连接四要素一样
// ip地址
connectionFactory.setHost(ip);
// AMQP协议端口号
connectionFactory.setPort(port);
// 虚拟主机的name
connectionFactory.setVirtualHost(virtualHost);
// 访问虚拟主机需要的用户名
connectionFactory.setUsername(username);
// 访问虚拟主机需要的密码
connectionFactory.setPassword(password);
// 创建连接
Connection connection = connectionFactory.newConnection();
// 创建通道(一个连接对多个通道)
Channel channel = connection.createChannel();
一、simple

这里写图片描述

// 建立通道
Channel channel = connection.createChannel();
/**
 * 声明队列
 *      queue(String): 队列名
 *      durable(boolean): 队列是否持久化
 *      exclusive(boolean): 是否排他,若true,该队列为排他队列,之所以叫排他是因为该队列无法被其它 连接 可见(同一个连接下的通道可见),且生命周期就是一个连接,连接断开就自动销毁,
 *      autoDelete(boolean): 队列无消费者是否自动自我销毁
 *      arguments(Map): 欲知此参何用,找度娘娘去吧
 */
channel.queueDeclare(queueName, false, false, false, null);
/**
 * 发消息
 *      exchange(String): 交换机名
 *      routingKey(String): 路由键
 *      mandatory(boolean): 若为true,则当路由的时候没找到匹配的队列,会将消息返回给生产者;若fasle,则当路由的时候没找到匹配的队列,该消息直接丢失
 *      immediate(boolean): 若为true,则当路由匹配的队列没有消费者时,该消息不会给到该队列,而是寻找其他匹配的且有消费者的队列投放,如果都没有,则把消息返回给生产者
 *      props(BasicProperties): 关于headers
 *      body(byte[] ): 发送内容
 */
for (int i = 0; i <= 30; i++){
    String msg = "你好吗? - " + i;
    channel.basicPublish("",queueName,null,msg.getBytes());
    System.out.println("send: "+ msg);
}
// 资源关闭
channel.close();
connection.close();
// 创建通道
Channel channel = connection.createChannel();
/**
 * 消费(监听队列)
 *      queueName(String): 队列名
 *      autoAck(boolean): 是否自动应答(Ack),自动应答存在数据丢失的可能性,因为消息一给消费者就从内存中删除消息,不管消费者是否收到.默认false
 *      callback(Consumer ): 监听回调,这里自己实现了Consumer接口,有个DefaultConsumer类可以用
 */
channel.basicConsume(queueName, true,new Consumer() {
    /**
     * 成功监听走这个
     * @param consumerTag
     */
    public void handleConsumeOk(String consumerTag) {
        System.out.println("handleConsumeOk..."+consumerTag);
    }

    public void handleCancelOk(String consumerTag) {
        System.out.println("handleCancelOk..."+consumerTag);
    }

    public void handleCancel(String consumerTag) throws IOException {
        System.out.println("handleCancel..."+consumerTag);
    }

    /**
     * 发生异常走这个
     * @param consumerTag
     * @param sig 异常信息
     */
    public void handleShutdownSignal(String consumerTag, ShutdownSignalException sig) {
        System.out.println("handleShutdownSignal..."+consumerTag);
        System.out.println("handleShutdownSignal...Exception: "+sig.getMessage());

    }

    public void handleRecoverOk(String consumerTag) {
        System.out.println("handleRecoverOk..."+consumerTag);
    }

    /**
     * 消息接收处理走这个
     * @param consumerTag
     * @param envelope
     * @param properties
     * @param body
     * @throws IOException
     */
    public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
        System.out.println("handleDelivery..."+consumerTag);
        String msg = new String(body);
        System.out.println("msg: "+msg);
    }
});
二、work

这里写图片描述

work模式(轮询分发)和simple模式代码一样,差别在于消费者开多个。
work模式(公平分发 fair),采用“能者多劳”机制,代码如下修改

// 限制给一个消费者发noAck消息的个数,下面代码的意思是一次只发一个消息给消费者,收到ack后再发下一个(生产者代码)
channel.basicQos(1);
// -----------------华丽分割线-----------------
// + 将autoAck改为false,取消自动应达(消费者代码)
channel.basicConsume(queueName, false, new Consumer(){
	...
	
	/**
     * 消息接收处理走这个
     * @param consumerTag
     * @param envelope
     * @param properties
     * @param body
     * @throws IOException
     */
    public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
        System.out.println("handleDelivery..."+consumerTag);
        String msg = new String(body);
        System.out.println("msg: "+msg);
        // + 手动应答
        channel.basicAck(envelope.getDeliveryTag(), false);
	 }
	
	...
});
三、pub/sub

这里写图片描述

生产者代码调整,消费者代码不变

// 建立通道
Channel channel = connection.createChannel();
/**
 * + 声明交换机
 *      exchange(String): 交换机名
 *      type(String): fanout、direct、topic、header(未了解)
 *      durable(boolean): 交换机持久化
 *      autoDelete(boolean):
 *      arguments(Map<String, Object>):
 */
channel.exchangeDeclare(exchangeName,"fanout", true, false, null);
// 声明队列
channel.queueDeclare(queueName, true, false, false,null);
/**
 * + 队列绑定到交换机
 *      queue(String): 队列名
 *      exchange(String): 交换机名
 *      routingKey(String): 路由键
 */
channel.queueBind(queueName, exchangeName, "");
// 发送消息
for (int i = 0; i <= 30; i++){
    String msg = "你好吗? - " + i;
    channel.basicPublish(exchangeName,"",null,msg.getBytes());
    System.out.println("send: "+ msg);
}
// 资源关闭
channel.close();
connection.close();
四、routing

这里写图片描述

引用块内容

// 建立通道
Channel channel = connection.createChannel();
/**
 * + 声明交换机
 *      exchange(String): 交换机名
 *      type(String): fanout、direct、topic、header(未了解)
 *      durable(boolean): 交换机持久化
 *      autoDelete(boolean):
 *      arguments(Map<String, Object>):
 */
channel.exchangeDeclare(exchangeName,"direct", true, false, null);
// 声明队列
channel.queueDeclare(queueName, true, false, false, null);
/**
 * + 队列绑定到交换机
 *      queue(String): 队列名
 *      exchange(String): 交换机名
 *      routingKey(String): 路由键
 */
channel.queueBind(queueName, exchangeName, "error");
// 发送消息
for (int i = 0; i <= 30; i++){
    String msg = "你好吗? - " + i;
    channel.basicPublish(exchangeName,"error",null,msg.getBytes());
    System.out.println("send: "+ msg);
}
// 资源关闭
channel.close();
connection.close();
五、topic

这里写图片描述

// 建立通道
Channel channel = connection.createChannel();
/**
 * + 声明交换机
 *      exchange(String): 交换机名
 *      type(String): fanout、direct、topic、header(未了解)
 *      durable(boolean): 交换机持久化
 *      autoDelete(boolean):
 *      arguments(Map<String, Object>):
 */
channel.exchangeDeclare(exchangeName,"topic", true, false, null);
// 声明队列
channel.queueDeclare(queueName, true, false, false, null);
/**
 * + 队列绑定到交换机
 *      queue(String): 队列名
 *      exchange(String): 交换机名
 *      routingKey(String): 路由键,topic模式可以使用#或者*,网上都说#匹配    多个单词,*匹配一个单词(以.划分为一个单词,然而实际测试结果不尽然,自行多测试体会...)
 */
channel.queueBind(queueName, exchangeName, "log.#");
// 发送消息
for (int i = 0; i <= 30; i++){
    String msg = "你好吗? - " + i;
    channel.basicPublish(exchangeName,"log.error",null,msg.getBytes());
    System.out.println("send: "+ msg);
}
// 资源关闭
channel.close();
connection.close();
消息确认机制(待续)
一、事物

用法就那样…这种方式同步,效率低

// 开启事物
channel.txSelect();
// 提交
channel.txCommit();
// 回滚
channel.txRollback();
二、confirm
// 开启confirm
channel.confirmSelect();
// 同步
if(channel.waitForConfirms()){
    System.out.println("OK");
}else{
    System.out.println("Fail");
}
// 异步,使用监听器
channel.addConfirmListener(new ConfirmListener() {
	// 成功响应
    public void handleAck(long deliveryTag, boolean multiple) throws IOException {

    }
	// 失败响应
    public void handleNack(long deliveryTag, boolean multiple) throws IOException {
        if(multiple){
            sortedSet.headSet(deliveryTag).clear();
        }else{
            sortedSet.remove(deliveryTag);
        }
    }
});
### RabbitMQ 使用教程详解 #### 安装与基本配置 对于希望了解如何安装并初步配置 RabbitMQ 的用户来说,官方文档提供了详尽指导。这不仅涵盖了操作系统级别的设置,还包括了必要的依赖项以及服务启动后的验证方法[^1]。 #### 生产者和消费者的实现 在构建基于消息传递的应用程序时,理解生产者(Producer)向队列发送数据而消费者(Consumer)接收这些数据的过程至关重要。通过具体的编程实例可以更好地掌握这一点,在 Java 中利用 AMQP 协议来连接到服务器,并执行相应的操作如声明交换器、绑定队列等动作完成消息的发布与订阅功能[^2]。 ```java // 创建生产者的简单例子 ConnectionFactory factory = new ConnectionFactory(); factory.setHost("localhost"); try (Connection connection = factory.newConnection(); Channel channel = connection.createChannel()) { String message = "Hello World!"; channel.basicPublish("", QUEUE_NAME, null, message.getBytes()); } ``` ```java // 创建消费者的简单例子 public static class Consumer implements Runnable { private final BlockingQueue<String> queue; public Consumer(BlockingQueue<String> q) { this.queue = q; } @Override public void run() { try { while (true) System.out.println(queue.take()); } catch (InterruptedException e) {} } } ``` #### 消息确认机制 为了确保每条消息都被成功处理而不丢失,RabbitMQ 提供了一种称为手动应答的手法。当客户端接收到一条信息后并不会立即删除它;只有当应用程序显式调用了 `basicAck` 方法之后才会真正移除该记录。这种方式极大地提高了系统的可靠性和稳定性[^3]。 ```xml <!-- 配置监听容器 --> <rabbit:listener-container connection-factory="connectionFactory"> <rabbit:listener ref="foo" method="listen" queue-names="zpcQueue"/> </rabbit:listener-container> <bean id="foo" class="com.zpc.rabbitmq.spring.Foo"/> ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值