本文仅展示核心代码,全部代码,请移步:git-soomq
为初学者而来~手工最简MQ(一)设计篇
为初学者而来~手工最简MQ(二)Broker
为初学者而来~手工最简MQ(三)Client
1,服务端
服务端的设计就非常简单了,最核心的就是消息的存取,以及响应生产者和消费者的网络请求
分为2部分:
1.1 消息文件
消息的存储我们参考kafka,并简化其逻辑,因为是最简单的mq,我们只考虑单机的情况的就行,每个topic存储2个文件
topicname.index
topicname.data
.index 文件存储格式为:
消息顺序号:消息截止位置
.data 文件按照顺序存储具体的消息
文件操作:
package com.esoo.mq.server.message;
import com.alibaba.fastjson.JSON;
import com.esoo.mq.common.ProcessorCommand;
import java.io.RandomAccessFile;
/**
* 为每个topic创建一个对象进行管理
*/
public class MessageFile {
private String topic;
private Long offset;
//索引文件
private RandomAccessFile indexFile = null ;
//数据文件
private RandomAccessFile dataFile = null ;
//追加消息(生产者进行调用)
public ProcessorCommand appendMsg(ProcessorCommand in){
try {
//加锁,避免竞争,文件乱码
synchronized (in.getResult().getTopic()) {
//读取index文件最后一行
String lastLine = readLastLine(indexFile, null);
int lastOffset = 1;
//消息体追加到data文件中,并返回文件末尾位置,作为本条消息的offset
long lastindex = writeEndLine(dataFile, in.getResult().getBody());
if (lastLine != null && !lastLine.equals("")) {
String index[] = lastLine.split(":");
lastOffset = Integer.valueOf(index[0]);
lastOffset = lastOffset + 1;
}
//组装本条消息index 序列号:消息体末尾位置
String insertMsgIndex = lastOffset + ":" + lastindex + "\t\n";
writeEndLine(indexFile, insertMsgIndex.getBytes());
in.setSuccess(true);
}
}catch (Exception e){
e.printStackTrace();
in.setSuccess(false);
in.setExmsg(e.getMessage());
}
return in;
}
//读取消息,消费者进行调用
public ProcessorCommand readMsg(ProcessorCommand in){
try {
synchronized (in.getResult().getTopic()) {
// 消息定位位置
int seekIn = 0;
// 消息体大小
int bodySize = 0;
//先定位到开始
indexFile.seek(0);
String indesMap=null;
//遍历index文件,找到上一个消息 offset 与本消息offset 进行相减就是消息体大小
while ((indesMap = indexFile.readLine())!=null){
String index[] = indesMap.split(":");
int inNum = Integer.valueOf(String.valueOf(index[0]).