消息的生产与发送
- 获取连接工厂 ConnectionFactory
- 获取连接 Connection
- 创建通信信道 Channel
- 声明队列 Queue
- 创建生产者、消费者 Producer、Consumer
我们接下来的代码演示使用idea 创建springboot maven项目进行。
依赖
<dependency>
<groupId>com.rabbitmq</groupId>
<artifactId>amqp-client</artifactId>
<version>4.8.3</version>
</dependency>
<dependency>
<groupId>org.springframework.amqp</groupId>
<artifactId>spring-rabbit</artifactId>
<version>2.1.6.RELEASE</version>
</dependency>
1、编写连接工厂
public class ConnectionsUtils {
/**
* 获取MQ的连接
*/
public static Connection getConnection() throws IOException, TimeoutException {
// 连接工厂
ConnectionFactory factory = new ConnectionFactory();
// 设置服务ip
factory.setHost("127.0.0.1");
// 设置服务端口
factory.setPort(5672);
return factory.newConnection();
}
}
// 通过查看ConnectionFactory源码可以发现设置了默认的一些配置信息,因此我们在这只定义了服务ip和端口号
2、创建消息生产者并发送消息
private static final String routingKey= "test_simple_queue";
public static void main(String[] args) throws IOException, TimeoutException {
//获取一个连接
Connection connection = ConnectionsUtils.getConnection();
//从连接获取通道
Channel channel = connection.createChannel();
String msg = "hello simple message";
channel.basicPublish("", routingKey,null, msg.getBytes());
System.out.println("--send msg-- " + msg);
// *使用完毕后务必关闭通道和连接!*
channel.close();
connection.close();
}
发送消息方法:
/**
* Publish a message.
*
* Publishing to a non-existent exchange will result in a channel-level
* protocol exception, which closes the channel.
*
* Invocations of <code>Channel#basicPublish</code> will eventually block if a
* <a href="http://www.rabbitmq.com/alarms.html">resource-driven alarm</a> is in effect.
*
* @see com.rabbitmq.client.AMQP.Basic.Publish
* @see <a href="http://www.rabbitmq.com/alarms.html">Resource-driven alarms</a>
* @param exchange the exchange to publish the message to 发送至哪个交换机
* @param routingKey the routing key 路由键
* @param props other properties for the message - routing headers etc 消息组成部分
* @param body the message body 消息组成部分
* @throws java.io.IOException if an error is encountered
*/
void basicPublish(String exchange, String routingKey, BasicProperties props, byte[] body) throws IOException;
3、创建消费者接收消息
private static final String QUEUE_NAME = "test_simple_queue";
public static void main(String[] args) throws IOException, TimeoutException {
Connection connection = ConnectionsUtils.getConnection();
// 创建频道
Channel channel = connection.createChannel();
// 队列声明
channel.queueDeclare(QUEUE_NAME, true, 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,"utf-8");
System.out.println("msg: "+msg);
System.out.println("consumerTag: "+consumerTag);
System.out.println("properties: "+properties);
System.out.println("msg: "+msg);
}
};
// 事件监听
channel.basicConsume(QUEUE_NAME, true, consumer);
}
声明队列方法:
/**
* Declare a queue
* @see com.rabbitmq.client.AMQP.Queue.Declare
* @see com.rabbitmq.client.AMQP.Queue.DeclareOk
* @param queue the name of the queue 队列名称
* @param durable true if we are declaring a durable queue (the queue will survive a server restart) 是否持久化这个队列,true的话,该队列在服务重启后依然存在
* @param exclusive true if we are declaring an exclusive queue (restricted to this connection) 独占(顺序消费,只有当前连接才可以监听该队列)
* @param autoDelete true if we are declaring an autodelete queue (server will delete it when no longer in use) 自动删除队列
* @param arguments other properties (construction arguments) for the queue 一些其他的参数
* @return a declaration-confirm method to indicate the queue was successfully declared
* @throws java.io.IOException if an error is encountered
*/
Queue.DeclareOk queueDeclare(String queue, boolean durable, boolean exclusive, boolean autoDelete,
Map<String, Object> arguments) throws IOException;
重写接收消息方法:
/**
* Called when a <code><b>basic.deliver</b></code> is received for this consumer.
* @param consumerTag the <i>consumer tag</i> associated with the consumer与消费者关联的消费者标签
* @param envelope packaging data for the message打包数据
* @param properties content header data for the message消息头部信息
* @param body the message body (opaque, client-specific byte array)消息体内容
* @throws IOException if the consumer encounters an I/O error while processing the message
* @see Envelope
*/
void handleDelivery(String consumerTag,
Envelope envelope,
AMQP.BasicProperties properties,
byte[] body)
throws IOException;
/**
* Start a non-nolocal, non-exclusive consumer, with
* a server-generated consumerTag.
* @param queue the name of the queue
* @param autoAck true if the server should consider messages
* acknowledged once delivered; false if the server should expect
* explicit acknowledgements
* @param callback an interface to the consumer object
* @return the consumerTag generated by the server
* @throws java.io.IOException if an error is encountered
* @see com.rabbitmq.client.AMQP.Basic.Consume
* @see com.rabbitmq.client.AMQP.Basic.ConsumeOk
* @see #basicConsume(String, boolean, String, boolean, boolean, Map, Consumer)
*/
String basicConsume(String queue, boolean autoAck, Consumer callback) throws IOException;
4、执行
- 首先我们运行消费者,完成消息队列的创建和保持监听状态来接收消息
- 启动消息发送者发送消息,如图所示已发送成功
- 查看消费者端控制台发现,已经接收到消息并进行打印
newConsumer: hello simple message
consumerTag: amq.ctag-YpoNNgCrIApZQPV_qHyYnA
properties: #contentHeader<basic>(content-type=null, content-encoding=null, headers=null, delivery-mode=null, priority=null, correlation-id=null, reply-to=null, expiration=null, message-id=null, timestamp=null, type=null, user-id=null, app-id=null, cluster-id=null)
msg: hello simple message
5、总结
上边代码我们可以发现一个问题,那就是消息生产者在发送消息的时候没有指定exchange,只指定了一个routingkey,而我们的消息消费者也接收到了消息,这是为什么呢?
这是因为,rabbitmq他有一个默认的exchange,如果在不指定exchange的时候,默认发送到该default exchange。
它的路由规则是根据routingkey去寻找和routingkey命名完全匹配的消息队列,找到后进行消息的发送。