最近得空,想着把rabbitMQ在项目中的应用记录下来,希望能够帮助需要它的人~~~、
消息队列在我们的业务中主要是用来异步发送邮件,发送短信,文件的导入导出;作用想必大家都知道主要就是为了解耦,做到异步。接下来直接上代码…
噢,稍等!说明一下,以下消息队列的配置使用的是rabbitMQ的路由模式!
1.首先在pom.xml文件中引入依赖
<!--消息队列依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
2.在项目中新建rabbitMQ的配置信息(声明队列、声明交换机、队列和交换机的绑定)和监听类(消费者)
- 2.1 在项目中我配置的rabbit的目录结构是这样的
- 2.2 在config包下面进行rabbitmq的相关配置
/**
* @DESCRIPTION: 消息队列配置
**/
@Configuration
public class RabbitConfig {
/**
* 声明email队列
*/
private static final String EMAIL_TOPIC = "q_topic_email";
/**
* 声明短信队列
*/
private static final String SMS_TOPIC = "q_topic_sms";
/**
* @return 邮件队列
*/
@Bean
public Queue queueEmail() {
return new Queue(EMAIL_TOPIC);
}
/**
* @return 短信队列
*/
@Bean
public Queue queueSms() {
return new Queue(SMS_TOPIC);
}
/**
* @return 交换机
*/
@Bean
TopicExchange exchange() {
return new TopicExchange("messageExchange");
}
/**
* 将队列绑定到交换机,并设置该路由为topic.email
*
* @param queueEmail 邮件队列
* @param exchange 交换机
* @return 队列和交换机绑定
*/
@Bean
Binding bindingExchangeEmail(Queue queueEmail, TopicExchange exchange) {
return BindingBuilder.bind(queueEmail).to(exchange).with("topic.email");
}
/**
* 将队列绑定到交换机,并设置该路由为topic.sms
*
* @param queueSms 短信队列
* @param exchange 交换机
* @return 队列和交换机绑定
*/
@Bean
Binding bindingExchangeSms(Queue queueSms, TopicExchange exchange) {
return BindingBuilder.bind(queueSms).to(exchange).with("topic.sms");
}
}
- 2.3 在监听类(消费者)中写具体的执行逻辑
import cn.cncommdata.message.model.Email;
import cn.cncommdata.message.service.IEmailService;
import com.alibaba.fastjson.JSONArray;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.List;
@Component
@RabbitListener(queues = "q_topic_email")
public class EmailListener {
/**
* emilService
*/
@Resource
private IEmailService emailService;
/**
* 消息监听类
*
* @param message 消息
*/
@RabbitHandler
public void process(String message) {
handler(message);
}
/**
* rabbit监听到信息,异步发送
*
* @param message 消息
*/
private void handler(String message) {
List<Email> emails = JSONArray.parseArray(message, Email.class);
if (emails.size() > 0) {
emailService.sendEmailUtil(emails);
emailService.updateEmailStatus(emails);
}
}
}
注意:消息队列的配置文件和监听类(消费者的对应关系)
至此,消息队列的队列的声明,交换机的声明,交换机和队列的绑定,以及消息队列的config类和监听类(消费者)的对应关系已经建立完成。
3.还有很重要的一步,就是在yml文件中配置rabbitMQ的连接配置
# rabbitmq配置
application:
name: ring-boot-rabbitmq
rabbitmq:
host: ${rabbit_url:你的主机(ip)}
port: ${rabbit_port:5672}
username: ${rabbit_username:guest}
password: ${rabbit_password:guest}
virtual-host: /
listener:
simple:
retry:
## 开启消费者重试
enabled: true
##最大重试次数(默认无数次)
max-attempts: 5
##重试间隔次数
initial-interval: 3000
特别注意:首先声明,上述的代码中,我采用的 动 态 取 值 的 方 法 , 主 要 考 虑 到 在 部 署 到 多 态 服 务 器 的 时 候 能 够 在 不 改 变 y m l 配 置 的 情 况 下 将 参 数 动 态 传 入 到 y m l 中 , 当 然 了 , 也 可 以 直 接 写 r a b b i t M Q 的 连 接 信 息 , 不 使 用 动态取值的方法,主要考虑到在部署到多态服务器的时候能够在不改变yml配置的情况下将参数动态传入到yml中,当然了,也可以直接写rabbitMQ的连接信息,不使用 动态取值的方法,主要考虑到在部署到多态服务器的时候能够在不改变yml配置的情况下将参数动态传入到yml中,当然了,也可以直接写rabbitMQ的连接信息,不使用取值。其次要在在yml中配置消息队列的最大重试次数,不配置的话,一旦由于消费者里面的程序出错,就会不断的重试,一直打印日志,直到将服务器撑爆。配置了最大重试次数以后,将会在最大重试次数完成后自动从队列中异常该条消息,也避免了消息的堆积。以上的结论都是本人测试时实际遇到的情况,如果有更好的解决方案,希望能够得到大家的指正!
4.最后一步,看看生产者是怎样将消息发送到消息队列的
/**
* 注入RabbitTemplate
*/
@Autowired
private RabbitTemplate rabbitTemplate;
/**
* 发送邮件信息到rabbit
* param1:messageExchange 交换机名称
* param2: topic.email 路由键
* param3: JSONObject.toJSONString(emailList) 具体的消息
*/
rabbitTemplate.convertAndSend("messageExchange", "topic.email", JSONObject.toJSONString(emailList));
至此,消息队列的配置、消息生产者发送消息、消息监听者(消费者)的相关配置已经全部完成。以上代码,都是来自本人开发中实际应用的,如果有写的不到位的地方,欢迎指正。