01_Springboot整合RabbitMQ

Springboot整合RabbitMQ和基本操作

引入RabbitMQ依赖

需要在pox.xml中引入RabbitMQ的相关依赖包

<!-- rabbitmq依赖 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-amqp</artifactId>
    <version>2.3.9.RELEASE</version>
</dependency>

配置RabbitMQ信息

在application.properties文件中添加RabbitMQ的相关配置项,
包括RabbitMQ服务器host、端口号、用户名和密码等信息。

## rabbitmq相关配置
spring.rabbitmq.virtual-host=/
# RabbitMQ服务器地址
spring.rabbitmq.host=localhost
# RabbitMQ服务器端口号
spring.rabbitmq.port=5672
# RabbitMQ用户名
spring.rabbitmq.username=guest
# RabbitMQ密码
spring.rabbitmq.password=guest

配置RabbitMQ相关Bean

为了更方便使用RabbitMQ的相关操作组件,可在项目中自定注入和配置Bean相关组件,

/**
 * RabbitMQ相关配置类
 * @author huangqiqin
 * @date 2021/04/13 00:31
 **/
@Configuration
public class RabbitmqConfig {

    private static final Logger log = LoggerFactory.getLogger(RabbitmqConfig.class);

    /**
     * 注入 RabbitMQ 的链接工厂
     */
    @Autowired
    private CachingConnectionFactory connectionFactory;

    /**
     * 注入 RabbitMQ 消息监听器所在的容器工厂配置类
     */
    @Autowired
    private SimpleRabbitListenerContainerFactoryConfigurer containerFactoryConfigurer;

    /**
     * 创建单个消息者实例下的消息监听器的容器工厂
     * @return
     */
    @Bean(name = "singleListenerContainer")
    public SimpleRabbitListenerContainerFactory singleListenerContainerFactory(){

        // 创建消息监听器所有容器工厂
        SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
        // 设置容器工厂所使用的容器
        factory.setConnectionFactory(connectionFactory);
        // 设置消息传输的格式(这里采用JSON格式)
        //factory.setMessageConverter(new Jackson2JsonMessageConverter());
        // 设置并发消费者实例的初始数量
        factory.setConcurrentConsumers(1);
        // 设置并发消费者实例的最大数量
        factory.setMaxConcurrentConsumers(1);
        // 设置并发消费者实例中每个实例拉取的消息数量
        factory.setPrefetchCount(1);

        return factory;
    }

    /**
     * 创建多个消息者实例下的消息监听器的容器工厂,主要针对高并发业务场景
     * @return
     */
    @Bean(name = "multiListenerContainer")
    public SimpleRabbitListenerContainerFactory multiListenerContainerFactory(){

        // 创建消息监听器所有容器工厂
        SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
        // 设置容器工厂所使用的容器
        factory.setConnectionFactory(connectionFactory);
        // 设置消息传输的格式(这里采用JSON格式)
        factory.setMessageConverter(new Jackson2JsonMessageConverter());
        // 设置并发消费者实例的初始数量
        factory.setConcurrentConsumers(10);
        // 设置并发消费者实例的最大数量
        factory.setMaxConcurrentConsumers(15);
        // 设置并发消费者实例中每个实例拉取的消息数量
        factory.setPrefetchCount(10);
        // 设置消息的确认消费模式。这里设置为NONE,表示不需要确认(MANUAL手动确认,AUTO自动确认)
        factory.setAcknowledgeMode(AcknowledgeMode.NONE);

        return factory;
    }

    /**
     * 配置RabbitMQ发送消息模板
     * @return
     */
    @Bean
    public RabbitTemplate rabbitTemplate(){
        // 设置发送消息后进行确认
        connectionFactory.setPublisherConfirmType(CachingConnectionFactory.ConfirmType.CORRELATED);
        // 设置发送消息返回确认消息
        connectionFactory.setPublisherReturns(true);

        RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
        rabbitTemplate.setMandatory(true);

        // 设置消息发送成功后的回调
        rabbitTemplate.setConfirmCallback(new RabbitTemplate.ConfirmCallback() {
            @Override
            public void confirm(CorrelationData correlationData, boolean ack, String cause) {
                log.info("==> 消息发送到RabbitMQ是否成功:{},失败原因:{}。", ack, cause);
            }
        });

        // 设置消息发送失败后的回调
        rabbitTemplate.setReturnCallback(new RabbitTemplate.ReturnCallback() {
            @Override
            public void returnedMessage(Message message, int replayCode, String replayText,
                                        String exchange, String routingKey) {
                log.error("==> 消息发送失败:replayCode={}, replayText={}, exchange={}, routingKey={}",
                        replayCode, replayText, exchange, routingKey);
            }
        });

        return rabbitTemplate;
    }
}

发送和接收基本类型消息

创建队列、交换机、路由和绑定

/**
 * 基本类型消息的队列、交换机、路由、绑定等对象配置类
 * @author huangqiqin
 * @date 2021/04/13 01:08
 **/

@Configuration
public class BasicMessageConfig {

    /**
     * 注入配置文件的环境变量实例
     */
    @Autowired
    private Environment env;

    /**
     * 创建队列
     * @return
     */
    @Bean(name = "basicQueue")
    public Queue basicQueue(){
        return new Queue(env.getProperty("mq.basic.queue.name"), true);
    }

    /**
     * 创建交换机:可持久化数据的交换机
     * @return
     */
    @Bean
    public DirectExchange basicExchange(){
        return new DirectExchange(env.getProperty("mq.basic.exchange.name"), true, false);
    }

    /**
     * 创建绑定:将上面创建的队列绑定到交换机上,并设置路由key
     * @return
     */
    @Bean
    public Binding basicBinding(){
        return BindingBuilder
                .bind(basicQueue())
                .to(basicExchange())
                .with(env.getProperty("mq.basic.routing.key.name"));
    }
}

其中环境变量env中配置(application.properties)信息如下:

# 基本类型消息的队列名称
mq.basic.queue.name=basic.queue
# 交换机名称
mq.basic.exchange.name=basic.exchange
# 路由key
mq.basic.routing.key.name=basic.routing.key

创建消息发送者类

/**
 * 基本类型消息的发送器
 * @author huangqiqin
 * @date 2021/04/13 01:22
 **/

@Component
public class BasicMessagePublisher {

    private static final Logger log = LoggerFactory.getLogger(BasicMessagePublisher.class);

    /**
     * 注入JSON序列化对象
     */
    @Autowired
    private ObjectMapper objectMapper;

    /**
     * 注入RabbitMQ模板对象
     */
    @Autowired
    private RabbitTemplate rabbitTemplate;

    /**
     * 注入properties配置文件变量
     */
    @Autowired
    private Environment env;

    /**
     * 发送消息到RabbitMQ
     * @param message
     */
    public void sendMessage(String message){
        try {
            if (!StringUtils.isEmpty(message)){
                // 设置消息传输格式为Json
                //this.rabbitTemplate.setMessageConverter(new Jackson2JsonMessageConverter(objectMapper));
                // 指定消息发送的交换机
                this.rabbitTemplate.setExchange(env.getProperty("mq.basic.exchange.name"));
                // 指定消息发送的路由key
                this.rabbitTemplate.setRoutingKey(env.getProperty("mq.basic.routing.key.name"));

                // 将字符串转为Message对象
                Message msg = MessageBuilder.withBody(message.getBytes("utf-8")).build();
                // 转换消息格式并发送
                //this.rabbitTemplate.convertAndSend(msg);
                this.rabbitTemplate.send(msg);

                log.info("==> 已发送消息到RabbitMQ,消息内容:{}", msg);
            }
        } catch (Exception e){
            log.error("发送消息到RabbitMQ失败", e);
        }

    }
}

创建消息消费者

/**
 * 基本类型消息的消费者
 * @author huangqiqin
 * @date 2021/04/14 00:37
 **/
@Component
public class BasicMessageConsumer {

    private static final Logger log = LoggerFactory.getLogger(BasicMessageConsumer.class);

    /**
     * 监听并接收消息队列中的消息,这里采用单一容器工厂实例
     * @param message
     */
    @RabbitListener(queues = "${mq.basic.queue.name}", containerFactory = "singleListenerContainer")
    public void consumeMessage(@Payload String message){
        try {
            System.out.println("==> 接收到RabbitMQ消息:" + message);
        } catch (Exception e){
            log.error("==> 接收RabbitMQ队列中消息异常", e);
        }
    }
}

单元测试

运行单元测试时,由于消息生产者发送完消息到RabbitMQ之后,JVM便结束了,
此时消息者可能还没来得及消息呢,所以可能导致看不到有消息者消费消息的输出,
解决办法就是,先正常启动当前springboot应用,然后再运行当前测试单元即可。

@RunWith(SpringRunner.class)
@SpringBootTest
@WebAppConfiguration
public class BasicPublisherTest{

    @Autowired
    private BasicMessagePublisher publisher;

    /**
     * 测试发送基本类型消息到 RabbitMQ中
     */
    @Test
    public void sendMessage() {

        String msg = "哈哈哈,这条消息是通过程序发送到RabbitMQ中的!!!!";

        publisher.sendMessage(msg);

    }
}

发送和接收对象类型消息

创建队列、交换机、路由和绑定

/**
 * 对象类型消息的队列、交换机、路由、绑定等对象配置类
 * @author huangqiqin
 * @date 2021/04/16 22:00
 **/
@Configuration
public class ObjectMessageConfig {

    /**
     * 注入配置文件的环境变量实例
     */
    @Autowired
    private Environment env;

    /**
     * 创建队列:可持久化的队列
     * @return
     */
    @Bean(name = "objectQueue")
    public Queue objectQueue(){
        return new Queue(env.getProperty("mq.object.queue.name"), true);
    }

    /**
     * 创建交换机:可持久化数据的交换机
     * @return
     */
    @Bean(name = "objectExchange")
    public DirectExchange objectExchange(){
        return new DirectExchange(env.getProperty("mq.object.exchange.name"), true, false);
    }

    /**
     * 创建绑定:将队列绑定到交换机上,并指定路由key
     * @param objectQueue       注入上面创建的队列
     * @param objectExchange    注入上面创建的交换机
     * @return
     */
    @Autowired
    @Bean(name = "objectBinding")
    public Binding objectBinding(Queue objectQueue, DirectExchange objectExchange){
        return BindingBuilder
                .bind(objectQueue)    // 绑定objectQueue队列
                .to(objectExchange)   // 到objectExchange交换机上
                .with(env.getProperty("mq.object.routing.key.name"));   //指定路由key
    }
}

其中环境变量env中配置(application.properties)信息如下:

# 对象类型消息的队列名称
mq.object.queue.name=object.queue
# 交换机名称
mq.object.exchange.name=object.exchange
# 路由key
mq.object.routing.key.name=object.routing.key

创建消息消费者

/**
 * 对象类型消息的消费者
 * @author huangqiqin
 * @date 2021/04/16 22:13
 **/
@Component
public class ObjectMessageConsumer {

    /**
     * 监听并接收消息队列中的消息,这里采用多消息容器工厂实例
     * @param person
     */
    @RabbitListener(queues = "${mq.object.queue.name}", containerFactory = "multiListenerContainer")
    public void consumeMessage(@Payload Person person){
        System.out.println("==> 接收到RabbitMQ消息:" + person);
    }
}

创建消息发送者

/**
 * 对象类型消息发送者
 * @author huangqiqin
 * @date 2021/04/16 22:32
 **/
@Component
public class ObjectMessagePublisher {

    /**
     * 注入配置文件变量对象
     */
    @Autowired
    private Environment env;

    /**
     * 注入Rabbit模板
     */
    @Autowired
    private RabbitTemplate rabbitTemplate;

    /**
     * 发送对象消息
     * @param person
     */
    public void sendObjectMessage(Person person){
        try {
            if (person != null){
                // 设置消息传输格式(Json)
                this.rabbitTemplate.setMessageConverter(new Jackson2JsonMessageConverter());
                // 指定发送消息到对应的交换机
                this.rabbitTemplate.setExchange(env.getProperty("mq.object.exchange.name"));
                // 指定发送消息时对应的路由key
                this.rabbitTemplate.setRoutingKey(env.getProperty("mq.object.routing.key.name"));

                // 转换格式并发送消息,并重写消息发送后置处理器
                this.rabbitTemplate.convertAndSend(person, new MessagePostProcessor() {
                    @Override
                    public Message postProcessMessage(Message message) throws AmqpException {
                        // 获取消息属性
                        MessageProperties messageProperties = message.getMessageProperties();
                        // 设置消息持久化模式
                        messageProperties.setDeliveryMode(MessageDeliveryMode.PERSISTENT);
                        // 设置消息类型(这里需要指定消息类型为Person类型,否则消费者无法直接接收Person对象消息)
                        messageProperties.setHeader(AbstractJavaTypeMapper.DEFAULT_CONTENT_CLASSID_FIELD_NAME,
                                Person.class
                        );
                        return message;
                    }
                });
            }
        } catch (Exception e){
            e.printStackTrace();
        }
    }
}

单元测试

@RunWith(SpringRunner.class)
@SpringBootTest
@WebAppConfiguration
public class ObjectMessagePublisherTest {

    @Autowired
    private ObjectMessagePublisher publisher;

    @Test
    public void sendObjectMessage() {

        Person person = new Person(1001, "张三丰", 109);

        System.out.println("==> 发送对象消息:");

        this.publisher.sendObjectMessage(person);

    }
}

完整的示例代码:https://gitee.com/huangqiqin/middleware-study/tree/master/rabbitmq

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值