springboot-rabbitmq

依赖

pom.xml

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

配置文件

application.yml

spring:
  rabbitmq:
    host: 10.27.10.63
    port: 5672
    virtual-host: /ems
    username: emsuser
    password: 123
    publisher-confirm-type: simple #开启生产者消息发送确认:生产者到exchange
    publisher-returns: true #开启生产者消息发送确认:exchange到queue
    listener:
      simple:
        acknowledge-mode: manual #开启手动应答
        retry:
          enabled: true #是否支持重试
          max-attempts: 2 #最多重试次数
  redis:
    host: 10.27.20.51
    port: 8888

生产者消息发送

序列化方式:

@Configuration
public class RabbitConfig {
    // json序列化方式
    @Bean
    public MessageConverter messageConverter(){
        return new Jackson2JsonMessageConverter();
    }

}
@SpringBootTest
class RabbitmqApplicationTests {

    @Autowired
    RabbitTemplate rabbitTemplate;

    @Test
    public void provider(){
        rabbitTemplate.convertAndSend("april","人间四月天");
    }

    // work模型
    @Test
    public void worker(){
        for (int i = 0; i < 10; i++) {
            rabbitTemplate.convertAndSend("work","工作模型:"+i);
        }
    }

    // 广播fanout
    @Test
    public void fanout(){
        HashMap<String, Object> stringObjectHashMap = new HashMap<>();
        stringObjectHashMap.put("name","西游记");
        stringObjectHashMap.put("number",100);
        rabbitTemplate.convertAndSend("logs","",stringObjectHashMap);
    }

    // 路由direct
    @Test
    public void direct(){
        rabbitTemplate.convertAndSend("directs","info","路由模式");
    }

    // 发布订阅 topic
    @Test
    public void topic(){
        HashMap<String, Object> stringObjectHashMap = new HashMap<>();
        stringObjectHashMap.put("name","西游记");
        stringObjectHashMap.put("number",100);
        // 较低等级的 send() 方法技巧在于构造要发送的 Message 对象,通过给定字符串的字节数组来构建 Message 实例,
        // 对于 String 值来说,这足够了,但是如果消息的负载是复杂对象的话,那它就会复杂得多
//        MessageProperties messageProperties = new MessageProperties();
//        messageProperties.setDeliveryMode(MessageDeliveryMode.PERSISTENT);
//        // 给消息添加messageId
//        messageProperties.setMessageId(UUID.randomUUID().toString());

//        // 使用json序列化方式会报错
//        Message message = new Message(stringObjectHashMap.toString().getBytes(),messageProperties);
//        rabbitTemplate.send("topics","k.save.user",message);

        // 鉴于上述这种情况,我们有了 convertAndSend() 方法,它会自动将对象转换为 Message。
        // 它需要一个消息转换器的帮助来完成该任务,默认的消息转换器是 SimpleMessageConverter,它适用于 String、Serializable 实例以及字节数组。
        // 给消息添加messageId
        rabbitTemplate.convertAndSend("topics","k.save.user", stringObjectHashMap.toString(),
                message1 -> {
                    message1.getMessageProperties().setDeliveryMode(MessageDeliveryMode.PERSISTENT);
                    return message1;
                },
                new CorrelationData(UUID.randomUUID().toString()));
    }
}

生产者消息发送确认

 
@Component
public class PublisherConfirmAndReturnConfig implements RabbitTemplate.ConfirmCallback,RabbitTemplate.ReturnsCallback {

    @Autowired
    RabbitTemplate rabbitTemplate;

    @PostConstruct// bean创建完成空对象,就开始进行@Autowire、@PostConstruct赋值,也就是在PublisherConfirmAndReturnConfig对象创建完成后会执行此方法
    public void init(){
        rabbitTemplate.setConfirmCallback(this);
        rabbitTemplate.setReturnsCallback(this);
    }
    /*
     消息发送到exchange确认回调
     */
    @Override
    public void confirm(CorrelationData correlationData, boolean b, String s) {
        // ack 消息发送到交换机
        if(b){
            System.out.println("消息被发送到exchange:" + s);
            System.out.println("消息被发送到exchange:" + new String(correlationData.getReturned().getMessage().getBody()));
        } else { // nack 消息未发送到交换机
            System.out.println("消息未被发送到exchange:" + s);
        }
    }
    /*
     消息从exchange发送到queue失败回调
     */
    @Override
    public void returnedMessage(ReturnedMessage returnedMessage) {
        System.out.println("消息没被发送到队列:" + returnedMessage.getExchange()+"||"+returnedMessage.getRoutingKey()+"||"+new String(returnedMessage.getMessage().getBody()));
    }
}

消费者消息消费

常用注解:@RabbitListener:作用在类上时,消费的方法上添加@RabbitHandler;作用在方法上时,无需添加@RabbitHandler

@RabbitHandler:表示消息消费方法

@Component
// 监听队列      声明的队列默认 持久化 非独占 非自动删除
@RabbitListener(queuesToDeclare = @Queue(value = "april",autoDelete = "false"))
public class consumer1 {

    // 消息处理,方法名任意,只需加上@Rabbithandler注解
    @RabbitHandler
    public void receiver1(String message){
        System.out.println(message);
    }
}

worktype:

@Component
public class WorkConsumer {

    /**
     *  @RabbitListener 作用在方法上时,方法不再需要 @RabbitHandler 注解
     *
     */
    @RabbitListener(queuesToDeclare = {@Queue("work")})
    public void consumer1(String message){
        System.out.println("Consumer1:"+message);
    }

    @RabbitListener(queuesToDeclare = @Queue("work"))
    public void consumer2(String message){
        System.out.println("Consumer2:"+message);
    }
}

fanout:

@Component
public class FanoutConsumer {

    /**
     * 绑定临时队列 value = @Queue
     * 绑定非临时队列 value = @Queue(value = "logsfanout")
     */
    @RabbitListener(bindings = @QueueBinding(value = @Queue(value = "logsfanout"),exchange = @Exchange(value = "logs",type = "fanout")))
    public void consumer1(String message){
        System.out.println("fanout模式1:"+message);
    }

    @RabbitListener(bindings = {@QueueBinding(value = @Queue,exchange = @Exchange(value = "logs",type = "fanout"))})
    public void consumer2(String message){
        System.out.println("fanout模式2:"+message);
    }
}

direct:

@Component
public class DirectConsumer {

    @RabbitListener(bindings = @QueueBinding(value = @Queue(),exchange = @Exchange(value = "directs",type = "direct"),key = {"warn","error"}))
    public void consumer1(String message){
        System.out.println("consumer1:"+message);
    }

    @RabbitListener(bindings = @QueueBinding(value = @Queue,exchange = @Exchange(value = "directs",type = "direct"),key = {"info","error"}))
    public void consumer2(String message){
        System.out.println("consumer2:"+message);
    }

}

topic:

@Component
public class TopicConsumer {
    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @RabbitListener(bindings = @QueueBinding(value = @Queue,exchange = @Exchange(value = "topics",type = "topic"),key = {"*.user"}))
    public void topicConsumer1(String message){
        System.out.println("consumer1:"+message);
    }

    @RabbitListener(bindings = @QueueBinding(value = @Queue,exchange = @Exchange(value = "topics",type = "topic"),key = "#.user.#"))
    public void topicConsumer2(String msg, Channel channel, Message message){
        // 获取messageId
        // 适用方式:messageProperties.setMessageId(UUID.randomUUID().toString());
        // String messageId = message.getMessageProperties().getMessageId();

        // 适用方式:new CorrelationData(UUID.randomUUID().toString())
        String messageId = message.getMessageProperties().getHeader("spring_returned_message_correlation");

        System.out.println("messageId:"+messageId);
        System.out.println(new String(message.getBody()));

        // redis中添加消息数据状态为为消费
        Boolean setIfAbsent = stringRedisTemplate.opsForValue().setIfAbsent(messageId, "0", 10, TimeUnit.SECONDS);
        try {
            // 设置成功:没有被消费过
            if(setIfAbsent) {
                System.out.println("consumer2:" + msg);
                channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
                // 消费完成,改变redis中该消息的消费状态为已消费
                stringRedisTemplate.opsForValue().setIfAbsent(messageId, "1", 10, TimeUnit.SECONDS);
            } else {// 设置失败:有被发给其他消费者
                String status = stringRedisTemplate.opsForValue().get(messageId);
                // 消费完成:手动确认;未被消费完成:不做任何操作,给原来的消费者继续消费
                if("1".equalsIgnoreCase(status)){
                    channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
                }
            }
        } catch (Exception e) {
            // 确认失败,发回原队列尾部
            try {
                channel.basicNack(message.getMessageProperties().getDeliveryTag(),false,true);
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }
    }
}

 

 

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值