上一篇 <<<消息中间件常见问题汇总
下一篇 >>>消息队列常用名词与中间件对比
1.设计思路
1.生产者和netty服务器之间建立长连接
2.消费者和netty服务器建立长连接,首次启动时主动拉取netty队列中的消息
3.生产者发送消息
4.消息从netty服务器主动推送给消费者
2.核心代码
2.1 包依赖
org.projectlombok
lombok
1.16.20
com.alibaba
fastjson
1.2.54
io.netty
netty-all
4.1.42.Final
org.jboss.marshalling
jboss-marshalling
1.4.10.Final
org.jboss.marshalling
jboss-marshalling-serial
1.4.10.Final
2.2 消息实体类
/**
* 消息实体类定义【必须实现序列化】
*/
@Data
public class MqEntity implements Serializable {
/**
* 队列名称
*/
public String queueName;
/**
* 消息内容
*/
public String mqMsg;
/**
* 是否生产者
*/
public boolean isProducer;
}
2.3 服务端代码
public class MqNettyServer {
public static void start(){
NioEventLoopGroup bossGroup = new NioEventLoopGroup();
NioEventLoopGroup workGroup = new NioEventLoopGroup();
ServerBootstrap serverBootstrap = new ServerBootstrap();
serverBootstrap.group(bossGroup, workGroup).channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer() {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
//编码解码
socketChannel.pipeline().addLast(MarshallingCodeCFactory.buildMarshallingDecoder());
socketChannel.pipeline().addLast(MarshallingCodeCFactory.buildMarshallingEncoder());
socketChannel.pipeline().addLast(new ServerHandler());
}
});
try {
ChannelFuture future = serverBootstrap.bind(Constants.PORT).sync();
System.out.println("服务器启动成功:" + Constants.PORT);
future.channel().closeFuture().sync();
} catch (Exception e) {
e.printStackTrace();
} finally {
bossGroup.shutdownGracefully();
workGroup.shutdownGracefully();
}
}
public static void main(String[] args) {
start();
}
}
/**
* server消息处理器
*/
public class ServerHandler extends SimpleChannelInboundHandler {
/**
* 客户端列表
*/
private static Map> ctxs = new HashMap>();
/**
* 消息列表
*/
private static Map queueMap = new HashMap();
@Override
protected void channelRead0(ChannelHandlerContext ctx, MqEntity mqEntity) throws Exception {
String queueName = mqEntity.getQueueName();
if(queueName==null||"".equals(queueName)){
return;
}
boolean isProducer = mqEntity.isProducer;
if(isProducer){
producer(mqEntity);
return;
}
consumer(ctx,mqEntity);
}
/**
* 发送给消费者具体操作
* 1、保存客户端队列信息
* 2、如果队列中有值,则主动拉取
*/
private void consumer(ChannelHandlerContext ctx, MqEntity mqEntity) {
String queueName = mqEntity.getQueueName();
Queue queue = queueMap.get(queueName);
List channelHandlerContexts = ctxs.get(queueName);
if(channelHandlerContexts==null){
channelHandlerContexts = new ArrayList();
}
channelHandlerContexts.add(ctx);
ctxs.put(queueName,channelHandlerContexts);
if(queue==null||queue.isEmpty()){
System.out.println("当前队列没有数据,直接返回");
}
ctx.writeAndFlush(queue.poll());
}
/**
* 生产者具体操作
* 1、如果队列不存在的话创建队列并加入数据
* 2、设置队列map
* 3、如果已经存在了客户端列表,则主动推送
*/
private void producer(MqEntity mqEntity) {
String queueName = mqEntity.getQueueName();
Queue queue = queueMap.get(queueName);
if(queue==null){
queue = new LinkedList();
}
queue.offer(mqEntity);
queueMap.put(queueName,queue);
List channelHandlerContexts = ctxs.get(queueName);
if(channelHandlerContexts!=null&&channelHandlerContexts.size()>0){
for(ChannelHandlerContext ctx:channelHandlerContexts){
ctx.writeAndFlush(queue.poll());
}
}
}
}
2.4 生产者
/**
* 生产者
*/
public class MqProducer {
public static void start(MqEntity request){
//创建nioEventLoopGroup
NioEventLoopGroup group = new NioEventLoopGroup();
Bootstrap bootstrap = new Bootstrap();
bootstrap.group(group).channel(NioSocketChannel.class)
.remoteAddress(new InetSocketAddress(Constants.HOST, Constants.PORT))
.handler(new ChannelInitializer() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
//编码解码
ch.pipeline().addLast(MarshallingCodeCFactory.buildMarshallingDecoder());
ch.pipeline().addLast(MarshallingCodeCFactory.buildMarshallingEncoder());
}
});
try {
// 发起同步连接
ChannelFuture sync = bootstrap.connect().sync();
System.out.println("生产者消息发送:"+ JSON.toJSONString(request));
sync.channel().writeAndFlush(request);
sync.channel().closeFuture().sync();
} catch (Exception e) {
} finally {
group.shutdownGracefully();
}
}
public static void main(String[] args) {
MqEntity request = new MqEntity();
request.setMqMsg("我的测试消息"+System.currentTimeMillis());
request.setProducer(true);
request.setQueueName(Constants.QUEUE_NAME);
start(request);
}
}
2.5 消费者
/**
* 消费者
*/
public class MqConsumer {
public static void start(MqEntity request){
//创建nioEventLoopGroup
NioEventLoopGroup group = new NioEventLoopGroup();
Bootstrap bootstrap = new Bootstrap();
bootstrap.group(group).channel(NioSocketChannel.class)
.remoteAddress(new InetSocketAddress(Constants.HOST, Constants.PORT))
.handler(new ChannelInitializer() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
//编码解码
ch.pipeline().addLast(MarshallingCodeCFactory.buildMarshallingDecoder());
ch.pipeline().addLast(MarshallingCodeCFactory.buildMarshallingEncoder());
ch.pipeline().addLast(new ConsumerHandler());
}
});
try {
// 发起同步连接
ChannelFuture sync = bootstrap.connect().sync();
System.out.println("消费者接受消息开始:"+ JSON.toJSONString(request));
sync.channel().writeAndFlush(request);
sync.channel().closeFuture().sync();
} catch (Exception e) {
}
}
public static void main(String[] args) {
MqEntity request = new MqEntity();
request.setProducer(false);
request.setQueueName(Constants.QUEUE_NAME);
start(request);
}
}
public class ConsumerHandler extends SimpleChannelInboundHandler {
@Override
protected void channelRead0(ChannelHandlerContext channelHandlerContext, MqEntity mqEntity) throws Exception {
System.out.println("消费者获取消息:"+mqEntity.getMqMsg());
}
}
推荐阅读:
<<<消息中间件的核心思想
<<<消息中间件常见问题汇总
<<<消息队列常用名词与中间件对比
<<