RabbitMQ的应用

252 阅读2分钟

「这是我参与2022首次更文挑战的第17天,活动详情查看:2022首次更文挑战

1、前言

本次我为大家介绍下,SpringBoot项目中,Rabbit MQ的开发。下面为大家分享下,对MQ的一些封装(抽取公共代码,可配置、可扩展)。

2、maven引入

​ 在pom文件中引入amqp,这里无需指定版本(跟随SpringBoot的版本)。

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

3、增加MQ配置类

​ 将队列、交换机等放入配置文件,交由配置类,在项目启动时,创建交换机、队列。

@Configuration
public class RabbitmqConfig { 

	@Value("${spring.rabbitmq.username:#{null}}")
	private String username;
	@Value("${spring.rabbitmq.password:#{null}}")
	private String password;
	@Value("${spring.rabbitmq.virtual-host}")
	private String virtualHost;
	@Value("${spring.rabbitmq.publisher-confirms}")
	private boolean publisherConfirms;
	@Value("${spring.rabbitmq.host}")
	private String host;
	@Value("${spring.rabbitmq.port}")
	private int port;
	
	@Value("#{'${spring.rabbitmq.queuesconfig:null}'.split(',')}")
	private List<String> queuesConfig;
	@Value("#{'${spring.rabbitmq.directexchangesconfig:null}'.split(',')}")
	private List<String> directExchangesConfig;

	/**
	 * 创建MQ连接 
	 */
	@Bean
	public ConnectionFactory connectionFactory() {
		CachingConnectionFactory connectionFactory = new CachingConnectionFactory();
		// 设置用户名
		connectionFactory.setUsername(username);
		// 设置密码
		connectionFactory.setPassword(password);
		// 虚拟主机
		connectionFactory.setVirtualHost(virtualHost);
		// 消息确认
		connectionFactory.setPublisherConfirms(publisherConfirms);
		// 地址
		connectionFactory.setHost(host);
		connectionFactory.setPort(port);
		return connectionFactory;
	}
	
	/**
	 * 定义rabbitTemplate 
	 * @return
	 */
	@Bean(name="rabbitTemplate")
    public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory) {
        RabbitTemplate template = new RabbitTemplate(connectionFactory);
        return template;
    }

	/**
	 * 按配置创建所有队列 
	 */
	@Bean
	public LinkedList<Queue> builderQueues() {
		LinkedList<Queue> queues = new LinkedList<Queue>();
		if (null != queuesConfig && queuesConfig.size() > 0 && !"null".equals(queuesConfig.get(0))) {
			for (String qConfig : queuesConfig) {
				String[] msgs = qConfig.split("/");
				if(4 != msgs.length) {
					throw new KPromptException("未按格式配置队列,配置信息为["+ qConfig +"]");
				}
				String qName = msgs[0];
				logger.info("正在创建队列[" + qName + "]");
				queues.add(createQueue(qName, Boolean.parseBoolean(msgs[1]), Boolean.parseBoolean(msgs[2]) , Boolean.parseBoolean(msgs[3])));
			}
		}
		return queues;
	}
	
	/**
	 * 按配置创建所有直接交换机 
	 */
	@Bean
	@DependsOn("builderQueues")
	public LinkedList<DirectExchange> builderDirectExchanges() {
		LinkedList<DirectExchange> directExchanges = new LinkedList<DirectExchange>();
		if (null != directExchangesConfig && directExchangesConfig.size() > 0 && !"null".equals(directExchangesConfig.get(0))) {
			for (String dEConfig : directExchangesConfig) {
				String[] msgs = dEConfig.split("/");
				if(3 != msgs.length) {
					throw new KPromptException("未按格式配置直接交换机,配置信息为["+ dEConfig +"]");
				}
				String dEName = msgs[0];
				logger.info("正在创建直接交换机[" + dEName + "]");
				directExchanges.add(createDirectExchange(dEName, Boolean.parseBoolean(msgs[1]), Boolean.parseBoolean(msgs[2])));
			}
		}
		return directExchanges;
	}
	
	/**
	 * 创建rabbitAdmin 
	 */
	@Bean
	public RabbitAdmin rabbitAdmin(ConnectionFactory connectionFactory) {
		return new RabbitAdmin(connectionFactory);
	}

	/**
	 * 根据名称查找队列 
	 * @param name
	 * @param queues
	 * @return
	 */
	public Queue getQueue(String name, LinkedList<Queue> queues) {
		for (Queue q : queues) {
			if (name.equals(q.getName())) {
				return q;
			}
		}
		return null;
	}
	
	/**
	 * 创建队列 
	 * @param queueName
	 * @param queueDurable
	 * @param queueExclusive
	 * @param queueAutoDelete
	 * @return
	 */
	public Queue createQueue(String queueName, boolean queueDurable, boolean queueExclusive, boolean queueAutoDelete) {
		return new Queue(queueName, queueDurable, queueExclusive, queueAutoDelete);
	}
	
	/**
	 * 创建直接模式交换机 
	 * @param exchangeName
	 * @param directExchangeDurable
	 * @param directExchangeAutoDelete
	 * @return
	 */
	public DirectExchange createDirectExchange(String exchangeName, boolean directExchangeDurable, boolean directExchangeAutoDelete) {
		return new DirectExchange(exchangeName, directExchangeDurable, directExchangeAutoDelete);
	}

}

4、示例

​ 向队列发送消息(生产者):

//发送到MQ
rabbitTemplate.convertAndSend(StringUtils.EMPTY,"UserBehaviorMQueue", UserBehavior);

​ 消费者处理消息:

@RabbitHandler
@RabbitListener(queues = "UserBehaviorMQueue", containerFactory = "containerFactory")
public void userBehaviorListener(UserBehavior userBehavior) {
    log.info("用户行为记录,接收到的用户行为信息为:{}", userBehavior);
    try {
        //do something
    }catch(Exception e){
        //消息处理异常、记录下来消息信息、异常信息、然后将此条消息丢掉,或记录数据库中
        log.error("用户行为记录出现异常,接收到的用户行为信息为:{},异常信息为:{}", uerBehavior, e);
    }    
}

​ 这里,消费者处理消息时,一定要加上try/catch,如果不加的话,出现异常,这条消息会一直不断地发送到消费者这里。好了、本期就先介绍到这里,有什么需要交流的,大家可以随时私信我。😊