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();
// 建立通道
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模式(轮询分发)和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);
}
...
});
生产者代码调整,消费者代码不变
// 建立通道
Channel channel = connection.createChannel();
/**
* + 声明交换机
* exchange(String): 交换机名
* type(String): fanout、direct、topic、header(未了解)
* durable(boolean): 交换机持久化
* autoDelete(boolean):
* arguments(Map):
*/
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();
引用块内容
// 建立通道
Channel channel = connection.createChannel();
/**
* + 声明交换机
* exchange(String): 交换机名
* type(String): fanout、direct、topic、header(未了解)
* durable(boolean): 交换机持久化
* autoDelete(boolean):
* arguments(Map):
*/
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();
// 建立通道
Channel channel = connection.createChannel();
/**
* + 声明交换机
* exchange(String): 交换机名
* type(String): fanout、direct、topic、header(未了解)
* durable(boolean): 交换机持久化
* autoDelete(boolean):
* arguments(Map):
*/
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
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);
}
}
});