学会rabbitmq开发项目,一篇文章就够了

本文有整合springboot项目,也有纯rabbitmq的使用介绍

rabbitmq介绍:消息中间件,在很多场景下可将一些复杂业务代码解偶出来的同时,提高系统总体响应速度。

例如业务:用户下单且成功后,需要发送邮件通知用户,最后返回响应。假设每个过程用时1s,总的耗时就是3s,使用rabbitmq将发送邮件的需求抽离出来,下单成功后,发送消息给rabbitmq异步给用户发送邮件,那么总体的响应时间就是2s,快了1s也算是不错滴,嘿嘿

fanout路由模型(广播)

介绍只要生产者发送了消息,所有的消费者都能接收到消息,且效果类似于轮循,交替消费

生产者

发送消息到交换机上即可

ConnectionFactory connectionFactory = new ConnectionFactory();
        connectionFactory.setHost("127.0.0.1");
        connectionFactory.setPort(5672);
        connectionFactory.setVirtualHost("ems");
        connectionFactory.setUsername("ems");
        connectionFactory.setPassword("ems");
        try {
    
    
            Connection connection = connectionFactory.newConnection();
            Channel channel = connection.createChannel();
            //交换机名字、交换机类型
            channel.exchangeDeclare("emsExchange","fanout");
            //参数一:交换机名称
            //参数二:队列名称 routing
            //参数三:持久化消息
            //参数四:消息内容
            for (int i = 0; i < 20; i++) {
    
    
                channel.basicPublish("emsExchange", "", null, (i+"fanout type message").getBytes());
            }
            channel.close();
            connection.close();
        } catch (IOException e) {
    
    
            e.printStackTrace();
        } catch (TimeoutException e) {
    
    
            e.printStackTrace();
        }

消费者一

构建临时队列,临时队列绑定fanout交换机,从临时队列中消费消息即可,且没有要匹配路由的限制

ConnectionFactory connectionFactory = new ConnectionFactory();
        connectionFactory.setHost("127.0.0.1");
        connectionFactory.setPort(5672);
        connectionFactory.setVirtualHost("ems");
        connectionFactory.setUsername("ems");
        connectionFactory.setPassword("ems");
        Connection connection = null;
        try {
    
    
            connection = connectionFactory.newConnection();
            Channel channel = connection.createChannel();
            //交换机名字、交换机类型
            channel.exchangeDeclare("emsExchange","fanout");
            //临时队列
            String queue = channel.queueDeclare().getQueue();
            //此通道交换机绑定队列、参数三:路由
            channel.queueBind(queue, "emsExchange", "");
            //参数一:消费哪个队列的消息
            //参数二:开始消息的自动确认机制
            //参数三:消费时的回掉接口
            channel.basicConsume(queue, true, new DefaultConsumer(channel) {
    
    
                @Override
                public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties,
                                           byte[] body) throws IOException {
    
    
                    System.out.println("消费者一:" + new String(body));
                }
            });
        } catch (IOException e) {
    
    
            e.printStackTrace();
        } catch (TimeoutException e) {
    
    
            e.printStackTrace();
        }

消费者二同上

修改打印语句为消费者二即可

效果

先打开消费者一和消费者二,继而打开生产者,消费者一和二都能消费到这些消息
在这里插入图片描述

work路由模型

介绍简单的路由匹配消息
核心基于路由

生产者

生产者仅指定路由发送消息

String routingKey = "user";
        ConnectionFactory connectionFactory = new ConnectionFactory();
        connectionFactory.setHost("127.0.0.1");
        connectionFactory.setPort(5672);
        connectionFactory.setVirtualHost("ems");
        connectionFactory.setUsername("ems");
        connectionFactory.setPassword("ems");
        try {
    
    
            Connection connection = connectionFactory.newConnection();
            Channel channel = connection.createChannel();

            //参数1:交换机名称 参数2:路由名称 参数3:持久化消息 参数4:消息内容
            for (int i = 0; i < 20; i++) {
    
    
                channel.basicPublish("", routingKey, MessageProperties.PERSISTENT_TEXT_PLAIN, (i + "topic动态路由模型").getBytes());
            }
            channel.close();
            connection.close();
        } catch (IOException e) {
    
    
            e.printStackTrace();
        } catch (TimeoutException e) {
    
    
            e.printStackTrace();
        }

消费者

routingKey匹配上了,就能消费

ConnectionFactory connectionFactory = new ConnectionFactory();
        connectionFactory.setHost("127.0.0.1");
        connectionFactory.setPort(5672);
        connectionFactory.setVirtualHost("ems");
        connectionFactory.setUsername("ems");
        connectionFactory.setPassword("ems");
        Connection connection = null;
        try {
    
    
            connection = connectionFactory.newConnection();
            Channel channel = connection.createChannel();
            //参数一:消费哪个队列的消息
            //参数二:开始消息的自动确认机制
            //参数三:消费时的回掉接口
            channel.basicConsume("user", true, new DefaultConsumer(channel) {
    
    
                @Override
                public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties,
                                           byte[] body) throws IOException {
    
    
                    System.out.println("消费者:" + new String(body));
                }
            });
        } catch (IOException e) {
    
    
            e.printStackTrace();
        } catch (TimeoutException e) {
    
    
            e.printStackTrace();
        }

direct路由模型

介绍动态路由消息
核心交换机+队列+路由都需指定

生产者

交换机类型声明为direct类型,发送消息指定:路由+交换机

		String routingKey = "user.zzh";
        String exchange = "directExchange";
        ConnectionFactory connectionFactory = new ConnectionFactory();
        connectionFactory.setHost("127.0.0.1");
        connectionFactory.setPort(5672);
        connectionFactory.setVirtualHost("ems");
        connectionFactory.setUsername("ems");
        connectionFactory.setPassword("ems");
        try {
    
    
            Connection connection = connectionFactory.newConnection();
            Channel channel = connection.createChannel();
            //交换机名称、交换机类型
            channel.exchangeDeclare(exchange, "direct");
            //参数1:交换机名称 参数2:路由名称 参数3:持久化消息 参数4:消息内容
            for (int i = 0; i < 20; i++) {
    
    
                channel.basicPublish(exchange, routingKey, MessageProperties.PERSISTENT_TEXT_PLAIN, (i + "direct动态路由模型").getBytes());
            }
            channel.close();
            connection.close();
        } catch (IOException e) {
    
    
            e.printStackTrace();
        } catch (TimeoutException e) {
    
    
            e.printStackTrace();
        }

消费者

通道绑定direct交换机,消费时路由到指定的消息上面

		String routingKey = "user.zzh";
        String exchange = "directExchange";
        ConnectionFactory connectionFactory = new ConnectionFactory();
        connectionFactory.setHost("127.0.0.1");
        connectionFactory.setPort(5672);
        connectionFactory.setVirtualHost("ems");
        connectionFactory.setUsername("ems");
        connectionFactory.setPassword("ems");
        Connection connection = null;
        try {
    
    
            connection = connectionFactory.newConnection();
            Channel channel = connection.createChannel();
            String queue = channel.queueDeclare().getQueue();
            //交换机名称、交换机类型
            channel.exchangeDeclare(exchange, "direct");
            //临时队列绑定交换机指定的路由上面
            channel.queueBind(queue, exchange, routingKey);
            //参数一:消费哪个队列的消息
            //参数二:开始消息的自动确认机制
            //参数三:消费时的回掉接口
            channel.basicConsume(queue, true, new DefaultConsumer(channel) {
    
    
                @Override
                public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties,
                                           byte[] body) throws IOException {
    
    
                    System.out.println("direct消费者一:" + new String(body));
                }
            });
        } catch (IOException e) {
    
    
            e.printStackTrace();
        } catch (TimeoutException e) {
    
    
            e.printStackTrace();
        }

topic路由模型

介绍:用法和direct差不多,就是多了通配符的路由匹配。
假设发送消息的路由为user.zzh.aaa

user.#

#匹配一个,最多匹配user.zzh类型的路由

(user.*)

*匹配多个,可以匹配任意以user.开头的路由

生产者

修改交换机类型为topic,发送消息指定交换机、路由key

String routingKey = "user.zzh";
        String exchange = "topicExchange";
        ConnectionFactory connectionFactory = new ConnectionFactory();
        connectionFactory.setHost("127.0.0.1");
        connectionFactory.setPort(5672);
        connectionFactory.setVirtualHost("ems");
        connectionFactory.setUsername("ems");
        connectionFactory.setPassword("ems");
        try {
    
    
            Connection connection = connectionFactory.newConnection();
            Channel channel = connection.createChannel();
            //交换机名称、交换机类型
            channel.exchangeDeclare(exchange, "topic");
            //参数1:交换机名称 参数2:路由名称 参数3:持久化消息 参数4:消息内容
            for (int i = 0; i < 20; i++) {
    
    
                channel.basicPublish(exchange, routingKey, MessageProperties.PERSISTENT_TEXT_PLAIN, (i + "topic动态路由模型").getBytes());
            }
            channel.close();
            connection.close();
        } catch (IOException e) {
    
    
            e.printStackTrace();
        } catch (TimeoutException e) {
    
    
            e.printStackTrace();
        }

消费者

对比direct修改路由user.*

ConnectionFactory connectionFactory = new ConnectionFactory();
        connectionFactory.setHost("127.0.0.1");
        connectionFactory.setPort(5672);
        connectionFactory.setVirtualHost("ems");
        connectionFactory.setUsername("ems");
        connectionFactory.setPassword("ems");
        Connection connection = null;
        try {
    
    
            connection = connectionFactory.newConnection();
            Channel channel = connection.createChannel();
            String queue = channel.queueDeclare().getQueue();
            //临时队列绑定交换机指定的路由上面
            channel.queueBind(queue, "topicExchange", "user.*");
            //参数一:消费哪个队列的消息
            //参数二:开始消息的自动确认机制
            //参数三:消费时的回掉接口
            channel.basicConsume(queue, true, new DefaultConsumer(channel) {
    
    
                @Override
                public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties,
                                           byte[] body) throws IOException {
    
    
                    System.out.println("消费者:" + new String(body));
                }
            });
        } catch (IOException e) {
    
    
            e.printStackTrace();
        } catch (TimeoutException e) {
    
    
            e.printStackTrace();
        }

rabbitmq整合springboot

添加配置文件(用户名、密码、虚拟主机、ip、端口号)

spring:
  rabbitmq:
    host: 127.0.0.1
    username: ems
    password: ems
    virtual-host: ems
    port: 5672

四大生产者汇总

@Autowired
    RabbitTemplate rabbitTemplate;
    /**
     * HELLO
     */
    @Test
    void contextLoads() {
    
    
        rabbitTemplate.convertAndSend("user", "hello");
    }
    /**
     * work路由模型
     */
    @Test
    void contextLoad3() {
    
    
        for (int i = 0; i <10; i++) {
    
    
            rabbitTemplate.convertAndSend("work", "work路由模型"+i);
        }
    }
    /**
     * fanout
     */
    @Test
    void contextLoads2() {
    
    
        for (int i = 0; i < 10; i++) {
    
    
            rabbitTemplate.convertAndSend("fanoutExchange", "", "fanout路由模型-" + i);
        }
    }
    /**
     * topic
     */
    @Test
    void contextLoads3() {
    
    
        for (int i = 0; i < 10; i++) {
    
    
            rabbitTemplate.convertAndSend("topicExchange", "user.zzh.zzhh", "topic路由模型-" + i);
        }
    }
    /**
     * direct
     */
    @Test
    void contextLoads4() {
    
    
        for (int i = 0; i < 10; i++) {
    
    
            rabbitTemplate.convertAndSend("directExchange", "warns.zzh", "direct路由模型-" + i);
        }
    }

work路由模式消费者、springboot版本

/**
 * work路由模型:发送消息指定队列即可
 */
@Component
public class workCustomer {
    
    
    @RabbitListener(queuesToDeclare = @Queue("work"))
    public void receivel(String msg) {
    
    
        System.out.println("work消费者一msg:" + msg);
    }
    @RabbitListener(queuesToDeclare = @Queue("work"))
    public void receivel2(String msg) {
    
    
        System.out.println("work消费者二msg:" + msg);
}
}

fanout路由模式消费者、springboot版本

@Queue:临时队列

/**
 * fanout广播:一个生产者发送消息,所有的消费者都能接受到消息
 */
@Component
public class fanoutCustomer {
    
    
    @RabbitListener(bindings = {
    
    
            @QueueBinding(
                    value = @Queue,
                    exchange = @Exchange(value = "fanoutExchange", type = "fanout"))
    })
    public void receivel(String msg) {
    
    
        System.out.println("fanout消费者1msg:" + msg);
    }
    @RabbitListener(bindings = {
    
    
            @QueueBinding(
                    value = @Queue,
                    exchange = @Exchange(value = "fanoutExchange", type = "fanout"))
    })
    public void receivel2(String msg) {
    
    
        System.out.println("fanout消费者2msg:" + msg);
    }
}

topic路由模式消费者、springboot版本

key:匹配路由

@Component
public class topicCustomer {
    
    
    @RabbitListener(bindings = {
    
    
            @QueueBinding(
                    value = @Queue,
                    exchange = @Exchange(value = "topicExchange", type = "topic"),
                    key = "user.*")
    })
    public void receivel(String msg) {
    
    
        System.out.println("topic1消费者msg:" + msg);
    }

    @RabbitListener(bindings = {
    
    
            @QueueBinding(
                    value = @Queue,
                    exchange = @Exchange(value = "topicExchange", type = "topic"),
                    key = ("user.#"))
    })
    public void receivel2(String msg) {
    
    
        System.out.println("topic2消费者msg:" + msg);
    }
}

direct路由模式消费者、springboot版本

/**
 * springBoot整合direct(路由)
 */
@Component
public class directCustomer {
    
    
    @RabbitListener(bindings = {
    
    
            @QueueBinding(
                    value = @Queue,
                    exchange = @Exchange(value = "directExchange",type ="direct"),
                    key = {
    
    "logs","errors"})
    })
    public void receivel(String msg) {
    
    
        System.out.println("direct消费者一msg:" + msg);
    }

    @RabbitListener(bindings = {
    
    
            @QueueBinding(
                    value = @Queue,
                    exchange = @Exchange(value = "directExchange", type = "direct"),
                    key = {
    
    "logs","warns.zzh"})
    })
    public void receivel2(String msg) {
    
    
        System.out.println("direct消费者二msg:" + msg);
    }
}

配置文件写法交换机、队列

声明交换机(指定类型)、队列(指定参数)、绑定(绑定队列、交换机)

 @Bean
    public TopicExchange cTopicExchange() {
    
    
        TopicExchange topicExchange = new TopicExchange("cTopicExchange", true, true, null);
        return topicExchange;
    }

    @Bean
    public Queue cTopicQueue() {
    
    
        Queue queue = new Queue("cTopicQueue", true);
        return queue;
    }

    @Bean
    public Binding bind() {
    
    
        Binding binding = BindingBuilder.bind(cTopicQueue()).to(cTopicExchange()).with("user.*");
        return binding;
    }

配置文件写法消费者

由于我们指定了相关的队列交换机的关系,直接监听对应的队列即可,由于可能消息比较复杂,发送的消息是什么类型就用什么类型接收

  • containerFactory:指定消息监听器的相关配置(例如接收的消息序列化相关配置)
@Component
public class allCustomerDemo {
    
    
    /**
     * cTopicQueue在配置文件中已经经过配置,只要消息发送没问题就能监听的到消息
     * @param user
     */
    @RabbitListener(queues = "cTopicQueue",containerFactory = "simpleRabbitListenerContainerFactory")
    public void listenerTopic(User user) {
    
    
        System.out.println("msg:" + user.getUsername());
    }
}

配置文件生产者

MessagePostProcessor:可以在消息发送的途中对消息进行干预(例如设置消息过期时间、是否持久化…)

	@Autowired
    RabbitTemplate rabbitTemplate;

    /**
     * topic路由模型之发送
     */
    public void topicSend() {
    
    
        User zzh = new User().setAge(21).setUsername("张子行").setId(1872).setVersion("1.0");
        rabbitTemplate.setExchange("cTopicExchange");
        rabbitTemplate.setRoutingKey("user.dshjdjsh");
        rabbitTemplate.setMessageConverter(new Jackson2JsonMessageConverter());
        rabbitTemplate.convertAndSend(zzh, new MessagePostProcessor() {
    
    
            @Override
            public Message postProcessMessage(Message message) throws AmqpException {
    
    
                MessageProperties msgProperties = message.getMessageProperties();
                msgProperties.setDeliveryMode(MessageDeliveryMode.PERSISTENT);
                log.info("发送消息成功!");
                return message;
            }
        });
    }

死信队列

介绍:消息在死信队列中过期了,自动转发至别的队列

死信队列配置

和普通队列区别就是多了额外参数配置:消息过期自动把消息转发到cTopicExchange

params.put("x-dead-letter-exchange", "cTopicExchange");
@Bean
public TopicExchange cdTopicExchange() {
    
    
    TopicExchange topicExchange = new TopicExchange("cdTopicExchange", true, false, null);
    return topicExchange;
}

/**
 * 消息超时发送给cTopicExchange,相当于转发。
 * 故cTopicExchange与cdTopicExchange的路由要相同,或者是包含关系
 *
 * @return
 */
@Bean
public Queue cdTopicQueue() {
    
    
    HashMap<String, Object> params = new HashMap<>();
    params.put("x-dead-letter-exchange", "cTopicExchange");
    Queue queue = new Queue("cdTopicQueue", true, false, false, params);
    return queue;
}

@Bean
public Binding cdBind() {
    
    
    Binding binding = BindingBuilder.bind(cdTopicQueue()).to(cdTopicExchange()).with("user.dead");
    return binding;
}

死信队列生产者

/**
     * 发送至死信队列
     */
    public void deadSend(){
    
    
        User zzh = new User().setAge(21).setUsername("张子行").setId(1872).setVersion("1.0");
        rabbitTemplate.setExchange("cdTopicExchange");
        rabbitTemplate.setRoutingKey("user.dead");
        rabbitTemplate.setMessageConverter(new Jackson2JsonMessageConverter());
        rabbitTemplate.convertAndSend(zzh, new MessagePostProcessor() {
    
    
            @Override
            public Message postProcessMessage(Message message) throws AmqpException {
    
    
                MessageProperties msgProperties = message.getMessageProperties();
                //设置过期时间:10s
                msgProperties.setExpiration("10000");
                //设置持久化
                msgProperties.setDeliveryMode(MessageDeliveryMode.PERSISTENT);
                log.info("发送消息成功!");
                return message;
            }
        });

代码链接

https://github.com/zhangzihang3/rabbitmqCode.git

猜你喜欢

转载自blog.csdn.net/qq_42875345/article/details/114285863