背景:前期再学习RabbitMq时,只是基于main方法的形式进行学习,但是实际中使用是结合spring 或者是spring boot的,所以就搜索博客查看RabbitMq和Spring的整合方式,开始摸着石头过河,估计是运气不好,找了好多demo都是有bug,或者项目报错,基于看了好多博客,spring配置文件配置的方式大致相同,于是开始边摸索边参考一些文档敲出一下demo;以下demo经测试可以正常运行,直接上代码;
spirng-mq.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.1.xsd
http://www.springframework.org/schema/rabbit
http://www.springframework.org/schema/rabbit/spring-rabbit-1.0.xsd
">
<!-- 加载配置文件 -->
<rabbit:connection-factory id="connectionFactory"
username="root"
password="root"
virtual-host="/"
host="localhost"
port="5672"
/>
<!--定义mq管理-->
<rabbit:admin connection-factory="connectionFactory"/>
<!--声明队列-->
<rabbit:queue name="queue_one" durable="true"/>
<rabbit:queue name="queue_two" durable="true"/>
<!--定义交换机绑定队列-->
<rabbit:direct-exchange name="IExchange" id="IExchange">
<rabbit:bindings>
<rabbit:binding queue="queue_one" key="queue_one_key"></rabbit:binding>
<rabbit:binding queue="queue_two" key="queue_two_key"></rabbit:binding>
</rabbit:bindings>
</rabbit:direct-exchange>
<!--消息对象转json类-->
<bean id="jsonMessageConverter" class="com.hsnn.medstgmini.drug.rabbitmq.FastJsonMessageConverter"/>
<!--定义模板-->
<rabbit:template id="rabbitTemplate" connection-factory="connectionFactory" exchange="IExchange" message-converter="jsonMessageConverter"/>
<!--定义消费者-->
<bean name="Consume1Handler" class="com.hsnn.medstgmini.drug.rabbitmq.Consume1Handler"/>
<bean name="Consume2Handler" class="com.hsnn.medstgmini.drug.rabbitmq.Consume2Handler"/>
<!--消费者监听队列-->
<rabbit:listener-container
connection-factory="connectionFactory">
<rabbit:listener ref="Consume1Handler" queues="queue_one"/>
<rabbit:listener ref="Consume2Handler" queues="queue_two"/>
</rabbit:listener-container>
</beans>
消息对象转json类默认采用的fackjson,但是考虑到效率问题,修改成FastJson进行对象json转换操作,class类内容如下;
package com.hsnn.medstgmini.drug.rabbitmq;
import java.io.UnsupportedEncodingException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageProperties;
import org.springframework.amqp.support.converter.AbstractMessageConverter;
import org.springframework.amqp.support.converter.MessageConversionException;
import com.alibaba.fastjson.JSONObject;
public class FastJsonMessageConverter extends AbstractMessageConverter {
@SuppressWarnings("unused")
private static Log log = LogFactory.getLog(FastJsonMessageConverter.class);
public static final String DEFAULT_CHARSET = "UTF-8";
private volatile String defaultCharset = DEFAULT_CHARSET;
public FastJsonMessageConverter() {
super();
}
public void setDefaultCharset(String defaultCharset) {
this.defaultCharset = (defaultCharset != null) ? defaultCharset
: DEFAULT_CHARSET;
}
public Object fromMessage(Message message)
throws MessageConversionException {
Object o = new CommonMessage();
try{
o = fromMessage(message, new CommonMessage());
}catch(Exception e){
log.error("queue message error : " + message);
e.printStackTrace();
}
return o;
}
@SuppressWarnings("unchecked")
public <T> T fromMessage(Message message, T t) {
String json = "";
try {
json = new String(message.getBody(), defaultCharset);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return (T) JSONObject.parseObject(json, t.getClass());
}
protected Message createMessage(Object objectToConvert,
MessageProperties messageProperties)
throws MessageConversionException {
byte[] bytes = null;
try {
String jsonString = JSONObject.toJSONString(objectToConvert);
bytes = jsonString.getBytes(this.defaultCharset);
} catch (UnsupportedEncodingException e) {
throw new MessageConversionException(
"Failed to convert Message content", e);
}
messageProperties.setContentType(MessageProperties.CONTENT_TYPE_JSON);
messageProperties.setContentEncoding(this.defaultCharset);
if (bytes != null) {
messageProperties.setContentLength(bytes.length);
}
return new Message(bytes, messageProperties);
}
}
message 消息模型类如下:
package com.hsnn.medstgmini.drug.rabbitmq;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.commons.lang.builder.ToStringStyle;
/**
* 消息模型
*
*/
public class CommonMessage {
/**
* 约定的几个消息源名称
*/
private String source;
/**
* 实体表名
*/
private String table;
/**
* 主键
*/
private String primaryKey;
/**
* 消息实体bean
*/
private Object message;
public String getSource() {
return source;
}
public void setSource(String source) {
this.source = source;
}
public String getTable() {
return table;
}
public void setTable(String table) {
this.table = table;
}
public String getPrimaryKey() {
return primaryKey;
}
public void setPrimaryKey(String primaryKey) {
this.primaryKey = primaryKey;
}
public Object getMessage() {
return message;
}
public void setMessage(Object message) {
this.message = message;
}
@Override
public String toString() {
return ToStringBuilder.reflectionToString(this,
ToStringStyle.DEFAULT_STYLE);
}
}
定义两个消费者:进行消费
package com.hsnn.medstgmini.drug.rabbitmq;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageListener;
import java.io.IOException;
/*
*消费者1
*
*/
public class Consume1Handler implements MessageListener {
private static final ObjectMapper mapper = new ObjectMapper();
@Override
public void onMessage(Message message) {
try {
JsonNode jsonNode =mapper.readTree(message.getBody());
System.out.println(jsonNode.get("id").asText()+":"+jsonNode.get("name").asText());
} catch (IOException e) {
e.printStackTrace();
}
}
}
package com.hsnn.medstgmini.drug.rabbitmq;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageListener;
import java.io.IOException;
/*
*消费者2
*/
public class Consume2Handler implements MessageListener {
private static final ObjectMapper mapper = new ObjectMapper();
@Override
public void onMessage(Message message) {
try {
JsonNode jsonNode =mapper.readTree(message.getBody());
System.out.println(jsonNode.get("id").asText()+":"+jsonNode.get("name").asText());
} catch (IOException e) {
e.printStackTrace();
}
}
}
测试类:
@RequestMapping("toCheckList")
public String toCheckList() {
Map map = new HashMap();
map.put("id","001");
map.put("name","酒鬼");
rabbitTemplate.convertAndSend("queue_one_key",map);
map.put("id","002");
map.put("name","撕家");
rabbitTemplate.convertAndSend("queue_two_key",map);
return MODEL_PATH + "checkList";
}
项目启动后,访问相应路径,会在控制台打印:
001:酒鬼
002:撕家
到这里配置就结束了,但是在配置过程中也踩过了一些坑,这里也贴出来,共勉
遇到的坑:启动过程中出现报错,错误信息如下:
org.springframework.amqp.AmqpIOException: java.io.IOException
at org.springframework.amqp.rabbit.support.RabbitExceptionTranslator.convertRabbitAccessException(RabbitExceptionTranslator.java:65)
at org.springframework.amqp.rabbit.connection.AbstractConnectionFactory.createBareConnection(AbstractConnectionFactory.java:218)
遇到问题后百度吗,但是结果都不是我想要的,百度的结果都是RabbitMq权限问题,只需要登录RabbitMq进行重置权限,如下
但是我重置后还是报错,然后开始排查问题,去RabbitMq官网查看,发现是连接时端口号配置错误导致的异常,RabbitMq的端口号信息如下:
4369 -- erlang发现口
5672 --client端通信口 --RabbitMq cliean连接端口号,及spring 配置中连接的prot值
15672 -- 管理界面ui端口 --RabbitMq管理访问端口
25672 -- server间内部通信口