由于最近公司业务需要,对RabbitMQ做了一些研究

引入依赖Jar包



<dependency>
    <groupId>com.rabbitmq</groupId>
    <artifactId>amqp-client</artifactId>
    <version>4.2.0</version>
</dependency>



java rabitmq自动重连 java连接rabbitmq_java


ConnectionFactory


负责创建连接,维护了建立连接需要的信息:url、port、vhost等

ConnectionFactory factory = new ConnectionFactory();
factory.setHost("192.168.0.133");
factory.setPort(5673);
factory.setVirtualHost("/myhost");
factory.setUsername("admin");
factory.setPassword("admin");


Connection


与RabbitMQ的连接

// 创建Connection
Connection connection = factory.newConnection();


Channel 信道


值得一提的是,一个连接可以为不同的线程创建各自的信道,它们是互相独立的,共用一个TCP连接,可以减少系统开销

// 创建Channel
Channel channel = connection.createChannel();


Queue 队列

队列是消息最终到达并被保存的地方,消息的消费者(订阅者)从队列中获取到消息,当多个消费者订阅了同一个队列时,Rabbit会以轮询的方式将队列中的消息给订阅者

队列可以由生产者来声明,也可以由消费者来声明,取决于我们对消息是否允许丢失的重视程度

消息发布时如果没有对应的队列接收,消息就会被丢弃

所以为了保护重要的消息不丢失,我们可以让消费者和创建者都声明耐用的队列(即重启服务器也不会消失),如果消息允许丢失,可以只由消费者来声明队列(生产者只通过交换器来推送消息)

队列只有与交换器绑定才能收到消息(即使我们不主动绑定,队列被声明时就隐式的绑定了默认交换器)

// 声明队列
  // 队列的相关参数需要与第一次声明该队列时相同,否则会抛出异常
  // 参数1:队列名称
  // 参数2:为true时服务重启后队列不会消失
  // 参数3:队列是否是独占的,如果为true只能被一个connection使用,其他连接建立时会抛出异常
  // 参数4:队列不再使用时是否自动删除(没有连接,并且没有未处理的消息)
  // 参数5:建立队列时的其他参数  
 channel.queueDeclare("queueName", true, false, false, null);



Exchange 交换器

交换器是传递消息的核心,消息的生产方通过Exchange来分发消息(不是直接分发到队列中,都是通过Exchange)

队列与交换器绑定时需要指定 routing key

Exchange可以理解为一张映射表,指明了消息要路由到哪些队列中

需要掌握3这种Exchange

1. direct:发布到绑定的队列中routing key 完全匹配的队列

2. fanout:发布到所有绑定了这个交换器的队列,无视routing key

3. topic:发布到绑定的队列中满足routing key规则的队列(不用完全匹配)

// 声明Exchange
// 参数1:exchange命名
// 参数2:分发模式
// 参数3:是否耐用,即重启后依然存在
channel.exchangeDeclare("exchangeName", "fanout", true);



Consumer 消费者

对接收到的消息,进行业务处理



生产者代码示例:

import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.MessageProperties;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * 使用Direct交换器投递消息
 */
public class Send {

    public static void main(String[] args) throws Exception {
        // 使用guest用户连接本地的Rabbit  guest用户默认只能连接本机上的rabbit
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("localhost");
        factory.setPort(5672);
        factory.setVirtualHost("/");
        factory.setUsername("guest");
        factory.setPassword("guest");

        Connection connection = factory.newConnection();
        Channel channel = connection.createChannel();

        // 声明一个耐用的队列, 为了让消息发送的时候就有投递的队列,分清消息生产者不需要创建队列也能发送消息
        channel.queueDeclare("myQueue", true,false, false, null);
        // 声明一个Exchange
        channel.exchangeDeclare("myExchange", "direct", true);
        // 绑定第一个交换器,routingKey为 "myRoutingKey"
        channel.queueBind("myQueue", "myExchange", "myRoutingKey");

        for (int i=0; i<10; i++) {
            // 发送消息
            String message = "消息内容: " + new SimpleDateFormat("HH:mm:ss").format(new Date());
            channel.basicPublish("myExchange", "myRoutingKey", MessageProperties.PERSISTENT_TEXT_PLAIN, message.getBytes("UTF-8"));
            System.out.println("发送了消息:" + i);
            Thread.sleep(2000);
        }

        // 关闭连接
        channel.close();
        connection.close();
    }

}

消费者代码示例:

import com.rabbitmq.client.*;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeoutException;

/**
 * 从指定队列消费消息
 */
public class Consumer {
    
    public static void main(String[] args) throws IOException, TimeoutException {
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("localhost");

        Connection connection = factory.newConnection();
        Channel channel = connection.createChannel();

        // 队列声明保持一致
        channel.queueDeclare("myQueue", true,false, false, null);

        System.out.println("等待接收消息...");
        
        // 创建消费者
        com.rabbitmq.client.Consumer consumer = 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");
                System.out.println("收到消息:" + message);
                
            }
        };
        
        // 消费消息,收到消息后自动回应服务器表示收到了消息
        channel.basicConsume("myQueue", true, consumer);
    }
    
}