如何让工具类更加通用,与业务模块解耦合是架构师和产品研发人员一直研究的课题,不管MVC分层设计,SOA面向服务设计,还是为解决高并发的读写分类,前后台分类,集群计算都解决问题的统筹方法。如下实现Spring+RabbitMQ集成工具,使用Spring开发项目更加容易集成RabbitMQ,无论是发送RPC同步调用还是异步调用。
使用步骤:
一、准备Maven POM配置
二、准备SpringBoot Application.properties配置文件
三、导入接口IMsgProcess
package com.test.util;
public interface IMsgProcess {
public Boolean process(Object obj);
}
四、导入消息监听器
package com.test.util;
import java.io.ByteArrayInputStream;
import java.io.ObjectInputStream;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageProperties;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
* 接收RabbitMQ异步消息的监听器
* 当监听的队列上有消息,获取消息并保存到数据库,需要注意Service接口
* @author java
*
*/
@Component
public class RabbitmqListener {
@Autowired
private IMsgProcess serv;
@Autowired
private AmqpTemplate template;
@RabbitListener(queues="test_rpc")
public void receive(Message msg)
{
try
{
byte[] data = msg.getBody();
Object obj = toObject(data);
boolean rtn = serv.process(obj);
//判断是否是同步消息
if(msg.getMessageProperties() != null)
{
String replyTo = msg.getMessageProperties().getReplyTo();
if(replyTo != null && !"".equals(replyTo))
{
String corrId = msg.getMessageProperties().getCorrelationIdString();
MessageProperties mprop = new MessageProperties();
mprop.setCorrelationIdString(corrId);
mprop.setReplyTo(replyTo);
System.out.println("消息处理结果="+rtn+",回复队列replyTo="+replyTo+",关联ID corrId="+corrId);
byte[] body = (rtn+"").getBytes();
Message replyMsg = new Message(body,mprop);
template.send("", replyTo, replyMsg);
System.out.println("接收到同步消息="+new String(data));
}
else
{
System.out.println("接收到异步消息="+new String(data));
}
}
else
{
System.out.println("接收到异步消息="+new String(data));
}
}
catch(Exception e)
{
e.printStackTrace();
}
}
public Object toObject(byte[] data)
{
try
{
ByteArrayInputStream bais = new ByteArrayInputStream(data);
ObjectInputStream ois = new ObjectInputStream(bais);
Object obj = ois.readObject();
bais.close();
return obj;
}
catch(Exception e)
{
e.printStackTrace();
}
return null;
}
}
五、导入消息发送工具类
可以发送异步消息,也可以发送同步消息
package com.test.util;
import java.io.ByteArrayOutputStream;
import java.io.ObjectOutputStream;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import com.rabbitmq.client.AMQP;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.Consumer;
import com.rabbitmq.client.DefaultConsumer;
import com.rabbitmq.client.Envelope;
@Component
public class SendMsg {
@Value("${spring.rabbitmq.host}")
private String host = "localhost";
@Value("${spring.rabbitmq.port}")
private String port = "5672";
@Value("${spring.rabbitmq.username}")
private String userName = "admin2";
@Value("${spring.rabbitmq.password}")
private String pwd = "admin2";
public byte[] toBytes(Object obj)
{
try
{
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(obj);
byte[] data = baos.toByteArray();
baos.close();
return data;
}
catch(Exception e)
{
e.printStackTrace();
}
return null;
}
public void sendObject(Object obj,Integer waitSecond)
{
try
{
System.out.println("host="+host+",port="+port);
//1.creeate ConnectionFactory
ConnectionFactory cf = new ConnectionFactory();
cf.setHost(host);
cf.setPort(Integer.parseInt(port));
cf.setUsername(userName);
cf.setPassword(pwd);
//2.create Conection
Connection con = cf.newConnection();
//3.create Channel
Channel channel = con.createChannel();
//4.create exchage
String exgName = "test_rpc_exg";
channel.exchangeDeclare(exgName, "direct");
String queueName = "test_rpc";
String routeKey = "java.io.File";
boolean durable = true;
boolean exclusive = false;
boolean autoDelete = false;
channel.queueDeclare(queueName, durable, exclusive, autoDelete, null);
//5.bind exchange and queue
channel.queueBind(queueName,exgName,routeKey);
channel.basicPublish(exgName, routeKey, null,toBytes(obj));
channel.close();
con.close();
if(waitSecond == null)
waitSecond = 1;
Thread.sleep(waitSecond*1000);
}
catch(Exception e)
{
e.printStackTrace();
}
}
/**
* 发送同步消息
* @param obj
* @return
*/
public boolean sendSyncObject(Object obj) {
try
{
System.out.println("host="+host+",port="+port);
//1.creeate ConnectionFactory
ConnectionFactory cf = new ConnectionFactory();
cf.setHost(host);
cf.setPort(Integer.parseInt(port));
cf.setUsername(userName);
cf.setPassword(pwd);
//2.create Conection
Connection con = cf.newConnection();
//3.create Channel
Channel channel = con.createChannel();
//4.create exchage
String exgName = "test_rpc_exg";
channel.exchangeDeclare(exgName, "direct");
String queueName = "test_rpc";
String routeKey = "java.io.File";
boolean durable = true;
boolean exclusive = false;
boolean autoDelete = false;
channel.queueDeclare(queueName, durable, exclusive, autoDelete, null);
String replyTo = channel.queueDeclare().getQueue();
final String corrId = java.util.UUID.randomUUID().toString();
//5.bind exchange and queue
channel.queueBind(queueName,exgName,routeKey);
//6.send msg
AMQP.BasicProperties prop = new AMQP.BasicProperties.Builder()
.correlationId(corrId).replyTo(replyTo).build();
channel.basicPublish(exgName, routeKey, prop,toBytes(obj));
final BlockingQueue<byte[]> response = new ArrayBlockingQueue<byte[]>(1);
Consumer csum = new DefaultConsumer(channel){
@Override
public void handleDelivery(java.lang.String consumerTag,
Envelope envelope, AMQP.BasicProperties properties,
byte[] body)
{
String corrId2 = properties.getCorrelationId();
//if(corrId.equals(corrId2))
{
response.offer(body);
}
}
};
channel.basicConsume(replyTo,true,csum);
//从JVM阻塞队列中获取回复消息,如果没收到当前线程阻塞
byte[] result = response.take();
String str = new String(result);
System.out.println("result="+str);
//7.close Connection
channel.close();
con.close();
if("true".equals(str))
return true;
else
return false;
}
catch(Exception e)
{
e.printStackTrace();
}
return false;
}
}
六、实现消息处理类
必须实现IMsgProcess接口