mq 消息队列对于每个开发人员并不陌生,消息队列实现了解耦 ,提高运行效率 保证系统稳定。但又存在 数据一致性等其他问题。这些问题都有了解决方案。也不是本篇讨论的问题。
我写的模拟消息队列功能 适用于以下场景
1、有些项目虽然用到了 mq 开发周期比较短 。或者公司因为成本问题 提供的服务器比较少,配置低。也行只是做个POC 不需要做那么专业。
2、有时候尽管你 各种第三方工具(kafka redis )用了一堆 但客户现场只有一台机器。
3、或者公司创业期间 前期资金短缺 服务器比较少 用户也不多 ,所以用的太多反而大材小用,把尽力都浪费在维护上,而不能专心开发产品,分析需求。
4、有些项目设计 尽管有些模块需要用mq 但因为 开发成本和客户资金等问题 用了只会增加公司运营开发成本
下面直接上代码吧
首先写一个类里面有一个 线程安全的 list 用于存放消息
import com.aheadframework.core.exception.SysException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class MessageManager<T> {
private static final Logger logger= LoggerFactory.getLogger(MessageManager.class);
/**
* 线程锁
*/
final Lock lock = new ReentrantLock();
/**
* 存放消息队列的类
*/
private List<T> message=new ArrayList<>();
/**
* 消息名称
*/
private String name;
/**
* 构造器
* @param name
*/
public MessageManager(String name){
this.name=name;
}
/**
* 添加消息的方法
* @param messageobj
* @throws SysException
*/
public void add(T messageobj) throws SysException {
lock.lock();
try {
message.add(messageobj);
}catch(Exception e){
e.printStackTrace();
}finally{
lock.unlock();
}
}
/**
* 读取一条最新的消息
* @return
*/
public T getMessage() {
lock.lock();
T obj=null;
try {
if(message.size()>0){
obj=message.get(0);
message.remove(0);
logger.info(name+" 剩余消息 ----->["+message.size()+"]");
}
}catch(Exception e){
e.printStackTrace();
}finally{
lock.unlock();
}
return obj;
}
/**
* 获取消息长度
* @return
*/
public int messageSize(){
lock.lock();
int size=0;
try {
size=message.size();
}catch(Exception e){
e.printStackTrace();
}finally{
lock.unlock();
}
return size;
}
}
然后是一个抽象类 用于 发送和消费消息
import com.aheadframework.core.exception.SysException;
public abstract class MessageService<T> implements Runnable{
/**
* 消息管理类
*/
private MessageManager<T>
dataManager;
/**
* 构造器
* @param name
*/
public MessageService(String name) {
dataManager=new MessageManager<>(name);
}
/**
* 添加一条消息
* @param messageBean
* @throws SysException
*/
public void add(T messageBean) throws SysException {
dataManager.add(messageBean);
}
/**
* 实现 runnable 接口 需要手动创建一个线程 运行起来 他会 不断的获取最新的消息
*/
@Override
public void run() {
while(true){
T messageBean=dataManager.getMessage();
if(messageBean==null){
continue;
}
this.execute(messageBean);
}
}
/**
* 获取的消息会发生给这个方法 实现这个方法 处理业务逻辑
* @param messageBean
*/
public abstract void execute(T messageBean);
}
上面的代码可以直接复制使用 下面需要自己写个实现类来处理消息 实现自己的业务逻辑 (需要自己写个线程启动消息队列)
package core.test;
import com.aheadframework.core.exception.SysException;
import com.aheadframework.core.message.MessageService;
import java.util.Arrays;
import java.util.List;
public class TestMq extends MessageService<String>/* 这里定义消息的数据类型 可以是自定义的bean */ {
/**
* 构造器
*
* @param name
*/
public TestMq(String name) {
super(name);
}
public static void main(String[] args) throws SysException {
TestMq testMq=new TestMq("消息测试");
//初始化 消息队列并启动
Thread thread=new Thread(testMq);
thread.start();
//模拟生产者 发送消息
for(int i=0;i<3;i++){
testMq.add("test message"+3);
}
}
/**
* 处理消息的实现类
* @param messageBean
*/
@Override
public void execute(String messageBean) {
System.out.println("收到了消息 "+messageBean);
}
}
下面是运行结果
以上的代码都封装在了我写的工具包里
源码位置: https://github.com/niupengyu/ahead-framework.git.
有兴趣的可以下载 互相交流。
另外还有其他工具类以后分享给大家。