基于Netty简单手写消息中间件思路

上一篇 <<<消息中间件常见问题汇总
下一篇 >>>消息队列常用名词与中间件对比


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());
    }
}

推荐阅读:
<<<消息中间件的核心思想
<<<消息中间件常见问题汇总
<<<消息队列常用名词与中间件对比
<< << << << << << << << << << << << << << << << << << << << << << << << << << << << << << << << <<

你可能感兴趣的:(基于Netty简单手写消息中间件思路)