rabbitmq

工作中大概用到,想着以后可能还会使用,所以还是需要记录下。网上的资料确实很多,也很全,毕竟适合自己的也不多,从优秀的里面汲取自己需要的,才是正道。
看了很多博客,文档啊,还有操作指南啥的,我也总结下对我来说简单明了的。概念啥的慢慢再补充,先把简单的操作使用记录下。
项目是springboot跟rabbitMq集成的
依赖

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-amqp</artifactId>
 </dependency>

配置文件

spring:
  rabbitmq:
    host: 192.168.3.95
    port: 5672
    username: admin
    password: admin
    virtual-host: my_vhost
    listener:
      direct:
        acknowledge-mode: manual #开启消息确认机制
      simple:
        acknowledge-mode: manual #开启消息确认机制

生产者代码

    @Autowired
    private RabbitTemplate rabbitTemplate;


	/**
	*  exchange  交换机名称 就是下面图形化配置或者代码配置的交换机名称
	*  routKey 路由key   交换机中队列绑定的路由key
	*  msgId  消息id,唯一标识
	*  msg  消息
	*/
    @Override
    public boolean sendDirectMessage(String exchange, String routKey, String msgId, String msg) {
        rabbitTemplate.convertAndSend(exchange, routKey, msg, message -> {
            message.getMessageProperties().setDeliveryMode(MessageDeliveryMode.PERSISTENT); //持久化
            message.getMessageProperties().setExpiration("10000"); //消息过期时间
            return message;
        }, new CorrelationData(msgId));
        return true;
    }

消费者

    @RabbitListener(queues = "hand_cyc_queue")  //监听的队列名称
    public void handListener(String msg, Channel channel, Message message) {
        try {
            log.info("消息{}", msg);
            channel.basicNack(message.getMessageProperties().getDeliveryTag(), false, false);
        } catch (Exception e) {
            e.printStackTrace();
            //丢弃这条消息
            try {
                //basicReject 和 basicNack区别就是可以多条和单条的区别
                //最后一个参数是:是否重回队列 true重回队列  false不回队列
                channel.basicNack(message.getMessageProperties().getDeliveryTag(), false, false);
            } catch (IOException e1) {
                e1.printStackTrace();
            }
            log.info("消息消费失败:id:{}", message.getMessageProperties().getDeliveryTag());
        }
    }

使用方式(都是direct方式记录的):
1.使用客户端界面添加。也是最简单直观的方式。
(1)创建交换机在这里插入图片描述
(2)创建队列
在这里插入图片描述
(3)交换机绑定队列和路由key
在这里插入图片描述
到这里其实队列,交换机,还有路由key已经都创建绑定成功,使用的话则直接在生产者和消费者分别发送和监听即可。

如果想绑定死信队列的话
<1>死信队列其实就是简单的队列,简单来说 就是普通的队列中取了个不同的名字,稍微区分开了而已。先重复上面的队列,交换机,路由key创建,绑定的操作
在这里插入图片描述

<2>再创建一个队列,为正常业务的队列,创建绑定,交换机,队列,路由key操作,然后给这个队列添加一些特别的属性,意思该队列中消息消费异常,过期等一些消息路由到刚刚创建的死信队列上
在这里插入图片描述

这样针对死信队列的界面话操作就完成了,如果想消费,就和正常的消费者一样。只需要在@RabbitListener(queues = “死信队列名称”)

2.代码实现
rabbitmq的properties配置

#direct模式   正常业务的死信队列,交换机,路由key的相关配置
rabbit.client.direct_exchange=auto_direct_cyc_exchange
rabbit.client.direct_queue=auto_direct_cyc_queue
rabbit.client.direct_routeKey=auto_direct_cyc_routeKey
rabbit.client.fanout_exchange=fanout_exchange
#direct   死信队列,交换机,路由key的相关配置
rabbit.client.dead_direct_exchange=auto_dead_exchange
rabbit.client.dead_direct_queue=auto_dead_queue
rabbit.client.dead_direct_routeKey=auto_dead_routeKey

RabbitProperty配置类

@Component
//自定义配置文件路径
@ConfigurationProperties(prefix = "rabbit.client")
@PropertySource("classpath:rabbit.properties")
@Data
public class RabbitProperty {

    private String directExchange;

    private String directQueue;

    private String directRouteKey;

    private String deadDirectExchange;

    private String deadDirectQueue;

    private String deadDirectRouteKey;
}

正常业务队列,交换机,路由key绑定以及注入

@Configuration
public class RabbitMqConfig {


    @Autowired
    private RabbitProperty rabbitProperty;


    // 创建一个立即消费队列
    @Bean
    public Queue immediateQueue() {
        return QueueBuilder.durable(rabbitProperty.getDirectQueue())
                .withArgument("x-dead-letter-exchange", rabbitProperty.getDeadDirectExchange())//设置死信交换机
//                .withArgument("x-message-ttl", makeCallExpire)
                .withArgument("x-dead-letter-routing-key", rabbitProperty.getDeadDirectRouteKey())//设置死信routingKey
                .build();
    }


    @Bean
    public DirectExchange immediateExchange() {
        // 一共有三种构造方法,可以只传exchange的名字, 第二种,可以传exchange名字,是否支持持久化,是否可以自动删除,
        //第三种在第二种参数上可以增加Map,Map中可以存放自定义exchange中的参数
        return new DirectExchange(rabbitProperty.getDirectExchange(), true, false);
    }

    @Bean
    //把立即消费的队列和立即消费的exchange绑定在一起
    public Binding immediateBinding() {
        return BindingBuilder.bind(immediateQueue()).to(immediateExchange()).with(rabbitProperty.getDirectRouteKey());
    }
}

死信队列相关配置

/**
 * 死信队列相关配置
 * @author cyc
 * @date 2021/4/9 11:37
 */
@Configuration
public class DeadConfig {

    @Autowired
    private RabbitProperty rabbitProperty;


    /**
     * 死信队列
     *
     * @return
     */
    @Bean
    public Queue deadQueue() {
        return new Queue(rabbitProperty.getDeadDirectQueue(), true);
    }

    /**
     * 死信队列交换机
     *
     * @return
     */
    @Bean
    DirectExchange deadExchange() {
        return new DirectExchange(rabbitProperty.getDeadDirectExchange());
    }

    /**
     * 死信队列绑定到交换机对应的路由key上
     *
     * @return
     */
    @Bean
    Binding bindingDeadQueue() {
        return BindingBuilder.bind(deadQueue()).to(deadExchange()).with(rabbitProperty.getDeadDirectRouteKey());
    }
}

生产者

@Service
public class ProducerMessage {

    @Autowired
    private RabbitTemplate rabbitTemplate;

    /**
     * 
     * @param exchange 交换机名称
     * @param routKey 路由key
     * @param msgId 消息id
     * @param msg 消息
     * @return
     */
    
    public boolean sendAutoDirectMessage(String exchange, String routKey, String msgId, String msg) {
        rabbitTemplate.convertAndSend(exchange, routKey, msg, message -> {
            message.getMessageProperties().setDeliveryMode(MessageDeliveryMode.PERSISTENT);
            message.getMessageProperties().setExpiration("10000"); //消息过期时间
            return message;
        }, new CorrelationData(msgId));
        return true;
    }
}

消费者

@Component
@Slf4j
public class ConsumerMessage {
    
    @RabbitListener(queues = "auto_direct_cyc_queue")
    public void chyListener(String msg, Channel channel, Message message) {
        try {
            log.info("消息{}", msg);
            SysUser sysUser = JSONObject.parseObject(msg, SysUser.class);
            if (sysUser.getSex() == 1) {
                //手动ack应答
                //告诉服务器收到这条消息 已经被我消费了 可以在队列删掉 这样以后就不会再发了
                // 否则消息服务器以为这条消息没处理掉 后续还会在发,true确认所有消费者获得的消息
                channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
                log.info("消息消费成功:id:{}", message.getMessageProperties().getDeliveryTag());
            } else {
                channel.basicNack(message.getMessageProperties().getDeliveryTag(), false, true);
                log.info("消息消费失败:id:{}", message.getMessageProperties().getDeliveryTag());
            }
        } catch (IOException e) {
            e.printStackTrace();
            try {
                //最后一个参数是:是否重回队列
                channel.basicNack(message.getMessageProperties().getDeliveryTag(), false, false);
            } catch (IOException e1) {
                e1.printStackTrace();
            }
            log.info("消息消费失败:id:{}", message.getMessageProperties().getDeliveryTag());
        }
    }
}

至于rabbitmq的各种路由方式,生产消息确认,消息消费手动签收,过期啊,延迟等相关特性以后慢慢的进行更新。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值