rabbitmq springboot整合

本文采用directExchange,为保证针对同个用户的消息要有消费顺序,采用多队列,每条队列单线程消费进行配置

消息发送端配置

  配置参数接收类

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;

/**
* 配置类
*/
@Configuration
@ConfigurationProperties(prefix = "spring.rabbitmq")
public class RabbitMqProperties {
    private String addresses;//地址
    private String username;//用户名
    private String password;//密码
    private Boolean publisherConfirms;//是否发送校验
    private String virtualHost;//虚拟地址
    private Boolean defaultDurable;// 是否持久化
    private Boolean autoDelete;//当所有消费客户端连接断开后,是否自动删除队列

    public String getAddresses() {
        return addresses;
    }

    public void setAddresses(String addresses) {
        this.addresses = addresses;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public Boolean getPublisherConfirms() {
        return publisherConfirms;
    }

    public void setPublisherConfirms(Boolean publisherConfirms) {
        this.publisherConfirms = publisherConfirms;
    }

    public String getVirtualHost() {
        return virtualHost;
    }

    public void setVirtualHost(String virtualHost) {
        this.virtualHost = virtualHost;
    }

	public Boolean getDefaultDurable() {
        return defaultDurable;
    }

    public void setDefaultDurable(Boolean defaultDurable) {
        this.defaultDurable = defaultDurable;
    }

    public Boolean getAutoDelete() {
        return autoDelete;
    }

    public void setAutoDelete(Boolean autoDelete) {
        this.autoDelete = autoDelete;
    }
}

  配置参数

#rabbitmq配置信息
spring.rabbitmq.addresses=127.0.0.1:5672
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest
spring.rabbitmq.publisherConfirms=true
spring.rabbitmq.virtualHost=/rabbit
spring.rabbitmq.defaultDurable=true
spring.rabbitmq.autoDelete=false
rabbitmq.routingKey.count=3
rabbitmq.exchange=local.exchange
rabbitmq.routingKey=local.queue_

  配置类

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.rabbit.connection.CachingConnectionFactory;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitAdmin;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.rabbit.support.CorrelationData;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;
import org.springframework.messaging.converter.MappingJackson2MessageConverter;


@Configuration
public class AmqpConfig {

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

    @Autowired
    private RabbitMqProperties rabbitMqProperties;

    @Bean
    public ConnectionFactory connectionFactory(){
        CachingConnectionFactory connectionFactory=new CachingConnectionFactory();
        connectionFactory.setAddresses(rabbitMqProperties.getAddresses());
        connectionFactory.setUsername(rabbitMqProperties.getUsername());
        connectionFactory.setPassword(rabbitMqProperties.getPassword());
        connectionFactory.setVirtualHost(rabbitMqProperties.getVirtualHost());
       connectionFactory.setPublisherConfirms(rabbitMqProperties.getPublisherConfirms());
        return connectionFactory;
    }

    // 这里作用域设置为原型模式  每次获取都会得到一个新的实例
    @Bean
    @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
    public RabbitTemplate rabbitTemplate(){
        RabbitTemplate rabbitTemplate=new RabbitTemplate(connectionFactory());
        //数据转换为json存入消息队列
        rabbitTemplate.setMessageConverter(new Jackson2JsonMessageConverter());
        //发布确认
        rabbitTemplate.setConfirmCallback((CorrelationData correlationData, boolean ack, String cause) -> {
            if (!ack){
                log.error("发送到消息失败");
                throw new RuntimeException("send error " + cause);
            }
        });
        return rabbitTemplate;
    }

    /**
     * rabbitAdmin代理类
     * @return
     */
    @Bean
    public RabbitAdmin rabbitAdmin(ConnectionFactory connectionFactory){
        return new RabbitAdmin(connectionFactory);
    }
}

  发送消息util类

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageDeliveryMode;
import org.springframework.amqp.core.MessageProperties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.io.UnsupportedEncodingException;

/**
* 消息发送util
*/
@Component
public class SendMsgUtils {

    private Logger logger = LoggerFactory.getLogger(getClass());

    @Autowired
    private AmqpTemplate rabbitTemplate;

  
    public void sendMsg(String exchange, String routingKey,String content){
        MessageProperties messageProperties = new MessageProperties();
        // 设置消息持久化
        messageProperties.setDeliveryMode(MessageDeliveryMode.PERSISTENT);
        try {
            Message message = new Message(content.getBytes("utf-8"),messageProperties);
            rabbitTemplate.send(exchange, routingKey, message);
        } catch (UnsupportedEncodingException e) {
            logger.info("发送消息失败 exchange{},routingKey:{},content",exchange,routingKey,content);
            e.printStackTrace();
        }
    }
}

  测试controller类

@RestController
@RequestMapping(path = "/test")
public class TestController {
    
        @Value("${rabbitmq.exchange}")
	private String AUDIENCE_EXCHANGE;// 交换器名

	@Value("${rabbitmq.routingKey}")
	private String ROUTING_KEY;// 路由键

	@Value("${rabbitmq.routingKey.count}")
	private Integer ROUTING_KEY_COUNT;// 路由键个数

        @Autowired
	private SendMsgComponent sendMsgComponent;

	@PostMapping(path = "/sendMessage")
        public void testSend(String userId,String message){
            // 计算路由键  
	    int routeKey = HashUtils.getHash(userId) % ROUTING_KEY_COUNT;
            // 发送消息
	    sendMsgComponent.sendMsg(AUDIENCE_EXCHANGE,ROUTING_KEY+routeKey,message);
    }
  
}
<!-- 整合mq需要加上下面依赖 -->
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>

消息接收端配置

  配置参数

#rabbitmq配置信息
spring.rabbitmq.addresses=127.0.0.1:5672
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest
spring.rabbitmq.publisherConfirms=true
spring.rabbitmq.virtualHost=/rabbitpre
spring.rabbitmq.defaultDurable=true
spring.rabbitmq.autoDelete=false
# exchange
rabbitmq.exchange=local.exchange
# 3个队列消费
rabbitmq.queue_0=local.queue_0
rabbitmq.queue_1=local.queue_1
rabbitmq.queue_2=local.queue_2
#消费队列数
rabbitmq.queue.audience.count=3

  xml配置

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:rabbit="http://www.springframework.org/schema/rabbit"
        xmlns:task="http://www.springframework.org/schema/task"
       xsi:schemaLocation="http://www.springframework.org/schema/rabbit
           http://www.springframework.org/schema/rabbit/spring-rabbit-1.5.xsd
           http://www.springframework.org/schema/task
	  	 http://www.springframework.org/schema/task/spring-task.xsd
           http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans.xsd">

      <!--配置connection-factory,指定连接rabbit server参数 -->
    <rabbit:connection-factory id="connectionFactory"
        username="${spring.rabbitmq.username}" password="${spring.rabbitmq.password}" addresses="${spring.rabbitmq.addresses}" virtual-host="${spring.rabbitmq.virtualHost}"/>
    <!-- 自动声明队列 交换器 -->   
    <rabbit:admin id="rabbitAdmin" connection-factory="connectionFactory" />

    <!-- 队列 durable持久化 auto-delete空闲自动删除  exclusive消费者是否独占队列 -->
    <rabbit:queue id="queue_0" name="${rabbitmq.queue_0}" durable="true" auto-delete="false" exclusive="false"/>
    <rabbit:queue id="queue_1" name="${rabbitmq.queue_1}" durable="true" auto-delete="false" exclusive="false"/>
    <rabbit:queue id="queue_2" name="${rabbitmq.queue_2}" durable="true" auto-delete="false" exclusive="false"/>

    <!-- 将队列绑定到交换路 路由键与队列名一致 -->
    <rabbit:direct-exchange name="${rabbitmq.exchange}" durable="true" auto-delete="false">
        <rabbit:bindings>
            <rabbit:binding queue="queue_0" key="${rabbitmq.queue_0}"/>
            <rabbit:binding queue="queue_1" key="${rabbitmq.queue_1}"/>
            <rabbit:binding queue="queue_2" key="${rabbitmq.queue_2}"/>
        </rabbit:bindings>
    </rabbit:direct-exchange>
    <!-- 线程池 -->
    <task:executor id="taskExecutor" pool-size="3" queue-capacity="200" />

    <!-- 监听配置 保证更新顺序 一个队列只能同时一条线程消费 -->
    <!-- acknowledge确认方式 manual是手动确认  concurrency是消费初始线程数
     max-concurrency最大消费线程数  prefetch消费者一次取多少消息进行消费 -->
    <rabbit:listener-container  connection-factory="connectionFactory" acknowledge="manual" concurrency="1" max-concurrency="1" task-executor="taskExecutor" prefetch="${rabbitmq.queue.audience.count}" >
    <rabbit:listener queues="queue_0"  ref="mqListener"  />
    <rabbit:listener queues="queue_1"  ref="mqListener"  />
    <rabbit:listener queues="queue_2"  ref="mqListener"  />

    </rabbit:listener-container>
</beans>

  消息监听器

import com.alibaba.fastjson.JSON;
import com.rabbitmq.client.Channel;
import com.zbmy.rabbit.workbench.data.server.utils.HashUtils;
import org.elasticsearch.client.transport.TransportClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.core.ChannelAwareMessageListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.Map;

@Component
public class MqListener implements ChannelAwareMessageListener {

    private static final Logger LOGGER = LoggerFactory.getLogger(UpdateAudienceListener.class);

    @Override
    public void onMessage(Message message, Channel channel) throws Exception {
        try {
            byte[] body = message.getBody();
            String messageStr = new String(body, "UTF-8");
            doSomething(parseMessage(messageStr));
            // 确认     false不批量确认
            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
        } catch (Exception e) {
            LOGGER.error("处理消息失败:{}", e);
            // 拒绝消息     false不重新放入队列
            channel.basicReject(message.getMessageProperties().getDeliveryTag(), false);
        }
    }

    private Map<String,Object> parseMessage(String messageStr){
        Map<String,Object> resultMap = new HashMap<>();
        Map<String,Object> map = JSON.parseObject(messageStr);
        for (Map.Entry<String, Object> entry : map.entrySet()) {
            resultMap.put(entry.getKey(),entry.getValue());
        }
        return resultMap;
    }
}

基础知识推荐这篇文章  https://www.jianshu.com/p/79ca08116d57

mq官方各版本文档地址  https://docs.spring.io/spring-amqp/docs/

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值