负责创建连接,维护了建立连接需要的信息: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");
与RabbitMQ的连接
// 创建Connection
Connection connection = factory.newConnection();
值得一提的是,一个连接可以为不同的线程创建各自的信道,它们是互相独立的,共用一个TCP连接,可以减少系统开销
// 创建Channel
Channel channel = connection.createChannel();
队列是消息最终到达并被保存的地方,消息的消费者(订阅者)从队列中获取到消息,当多个消费者订阅了同一个队列时,Rabbit会以轮询的方式将队列中的消息给订阅者
队列可以由生产者来声明,也可以由消费者来声明,取决于我们对消息是否允许丢失的重视程度
消息发布时如果没有对应的队列接收,消息就会被丢弃
所以为了保护重要的消息不丢失,我们可以让消费者和创建者都声明耐用的队列(即重启服务器也不会消失),如果消息允许丢失,可以只由消费者来声明队列(生产者只通过交换器来推送消息)
队列只有与交换器绑定才能收到消息(即使我们不主动绑定,队列被声明时就隐式的绑定了默认交换器)
// 声明队列
// 队列的相关参数需要与第一次声明该队列时相同,否则会抛出异常
// 参数1:队列名称
// 参数2:为true时服务重启后队列不会消失
// 参数3:队列是否是独占的,如果为true只能被一个connection使用,其他连接建立时会抛出异常
// 参数4:队列不再使用时是否自动删除(没有连接,并且没有未处理的消息)
// 参数5:建立队列时的其他参数
channel.queueDeclare("queueName", true, false, false, null);
交换器是传递消息的核心,消息的生产方通过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);
生产者代码示例:
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);
}
}