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

RabbitMQ的初步使用_第1张图片

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

RabbitMQ的初步使用_第2张图片

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

// 建立通道
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();
四、routing

RabbitMQ的初步使用_第3张图片

引用块内容

// 建立通道
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();
五、topic

RabbitMQ的初步使用_第4张图片

// 建立通道
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
// 开启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的初步使用)