在主框架为springmvc的项目中使用rabbitmq队列工具的配置和简单使用方法如下:
1、引入必须的4个jar包:
amqp-client-3.3.4.jar
spring-amqp-1.3.6.RELEASE.jar
spring-rabbit-1.3.6.RELEASE.jar
spring-retry-1.1.0.RELEASE.jar
2、在项目中添加amqp的配置文件,我再此命名为:spring-amqp.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:context="http://www.springframework.org/schema/context"
xmlns:rabbit="http://www.springframework.org/schema/rabbit"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/rabbit
http://www.springframework.org/schema/rabbit/spring-rabbit.xsd">
<bean id="taskExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
<!-- 核心线程数,默认为1 -->
<property name="corePoolSize" value="10" />
<!-- 最大线程数,默认为Integer.MAX_VALUE -->
<property name="maxPoolSize" value="50" />
<!-- 队列最大长度,一般需要设置值>=notifyScheduledMainExecutor.maxNum;默认为Integer.MAX_VALUE -->
<property name="queueCapacity" value="1000" />
<!-- 线程池维护线程所允许的空闲时间,默认为60s -->
<property name="keepAliveSeconds" value="300" />
<!-- 线程池对拒绝任务(无线程可用)的处理策略,目前只支持AbortPolicy、CallerRunsPolicy;默认为后者 -->
<property name="rejectedExecutionHandler">
<!-- AbortPolicy:直接抛出java.util.concurrent.RejectedExecutionException异常 -->
<!-- CallerRunsPolicy:主线程直接执行该任务,执行完之后尝试添加下一个任务到线程池中,可以有效降低向线程池内添加任务的速度 -->
<!-- DiscardOldestPolicy:抛弃旧的任务、暂不支持;会导致被丢弃的任务无法再次被执行 -->
<!-- DiscardPolicy:抛弃当前任务、暂不支持;会导致被丢弃的任务无法再次被执行 -->
<bean class="java.util.concurrent.ThreadPoolExecutor$CallerRunsPolicy" />
</property>
</bean>
<!-- 连接服务配置 -->
<rabbit:connection-factory id="connectionFactory" host="127.0.0.1" username="test"
password="test" port="4567" />
<rabbit:admin connection-factory="connectionFactory" />
<!-- queue 队列声明 需要发送消息到哪些队列-->
<!-- 消息系统监听队列 -->
<rabbit:queue id="message_queue" durable="true" auto-delete="false" exclusive="false" name="message_queue"/>
<!-- exchange queue binging key 绑定 -->
<rabbit:topic-exchange name="message-exchange" durable="true" auto-delete="false" id="message-exchange">
<rabbit:bindings>
<rabbit:binding queue="message_queue" pattern="message.*" />
</rabbit:bindings>
</rabbit:topic-exchange>
<!-- spring amqp默认的是jackson 的一个插件,目的将生产者生产的数据转换为json存入消息队列,由于fastjson的速度快于jackson,这里替换为fastjson的一个实现 -->
<bean id="jsonMessageConverter" class="com.tonson.rabbitmq.message.FastJsonMessageConverter"></bean>
<!-- spring template声明-->
<rabbit:template exchange="message-exchange" id="amqpTemplate" connection-factory="connectionFactory" message-converter="jsonMessageConverter"/>
<!-- 默认消息处理类,可以重写 -->
<bean id="messageHandler" class="com.tonson.rabbitmq.MessageHandler"></bean>
<!-- 用于消息的监听的代理类MessageListenerAdapter -->
<bean id="messageQueueListenerAdapter"
class="org.springframework.amqp.rabbit.listener.adapter.MessageListenerAdapter">
<constructor-arg ref="messageHandler" />
<property name="defaultListenerMethod" value="handleMessage"></property>
<property name="messageConverter" ref="jsonMessageConverter"></property>
</bean>
<!-- 监听容器 -->
<rabbit:listener-container
connection-factory="connectionFactory" acknowledge="auto"
task-executor="taskExecutor">
<rabbit:listener queues="message_queue" ref="messageQueueListenerAdapter" />
</rabbit:listener-container>
<bean id="messageSender"
class="com.tonson.rabbitmq.service.MessageSender">
<property name="amqpTemplate" ref="amqpTemplate"></property>
</bean>
</beans>
3、配置文件里提到的自定义的converter的内容如下:
package com.tonson.rabbitmq.message;
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);
}
}
4、消息处理类MessageHandler.java的内容如下:
package com.tonson.message.rabbitmq;
import java.io.IOException;
import java.util.Date;
import java.util.List;
import javax.annotation.Resource;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.http.client.ClientProtocolException;
import com.alibaba.fastjson.JSONObject;
public class MessageHandler {
private Log log = LogFactory.getLog(getClass());
@Override
public void handleMessage(CommonMessage message) {
try{
System.out.println("...." + message);
}catch(Exception e){
e.printStackTrace();
}
}
}
5、发消息的类MessageSender.java内容如下:
package com.tonson.rabbitmq.service;
import org.springframework.amqp.core.AmqpTemplate;
public class MessageSender {
private AmqpTemplate amqpTemplate;
private String routingKey;
public AmqpTemplate getAmqpTemplate() {
return amqpTemplate;
}
public void setAmqpTemplate(AmqpTemplate amqpTemplate) {
this.amqpTemplate = amqpTemplate;
}
public String getRoutingKey() {
return routingKey;
}
public void setRoutingKey(String routingKey) {
this.routingKey = routingKey;
}
public void sendDataToQueue(Object obj) {
amqpTemplate.convertAndSend(this.routingKey, obj);
}
}
6、消息模型类如下:
package com.tonson.rabbitmq.message;
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.tonson.rabbitmq.demo;
import com.alibaba.fastjson.JSONObject;
import com.tonson.rabbitmq.message.CommonMessage;
import com.tonson.rabbitmq.service.MessageSender;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:spring-amqp.xml")
public class RabbitMQDemo {
@Resource
private MessageSender messageSender;
@Test
public void testSendMessage(){
CommonMessage message = new CommonMessage();
message.setSource("tonson");
JSONObject obj = new JSONObject();
obj.put("test", "test json message");
message.setMessage(obj);
messageSender.setRoutingKey("message.tonson");
messageSender.sendDataToQueue(message);
}
}