Backend Development 18 min read

Building a High‑Performance Real‑Time Communication System with Netty and Spring Boot 3

This article explains Netty's asynchronous architecture, compares BIO/NIO/AIO models, describes its thread and pipeline designs, evaluates real‑time communication options, and provides complete frontend and backend code examples for creating a WebSocket‑based instant messaging service using Netty and Spring Boot 3.

Architect
Architect
Architect
Building a High‑Performance Real‑Time Communication System with Netty and Spring Boot 3

Netty is an asynchronous event‑driven network framework that simplifies Java NIO programming and supports thousands of concurrent connections, widely used by projects such as Dubbo and Elasticsearch.

The article first explains basic I/O concepts—blocking vs. non‑blocking and synchronous vs. asynchronous—and compares BIO, NIO and AIO models with intuitive analogies.

It then introduces Netty’s thread models (single‑thread, multithread, boss‑worker) and its pipeline processing mechanism, describing how channels and handlers are organized.

Next, the article evaluates three real‑time communication techniques (Ajax polling, long polling, WebSocket) and selects WebSocket as the optimal solution, noting Netty’s native support.

Implementation details are provided for both the frontend (WebSocket connection management in a Uni‑app) and the backend. The backend includes the server bootstrap, channel initializer, user‑channel session manager, and the core ChatHandler that processes TextWebSocketFrames, manages user mappings, and forwards messages.

Key code snippets are shown, for example:

globalData: {
    // WebSocket server address
    chatServerUrl: "ws://127.0.0.1:875/ws",
    CHAT: null,
    chatSocketOpen: false
},

onLaunch: function() {
    this.doConnect(false);
},

doConnect(isFirst) {
    if (isFirst) {
        uni.showToast({icon: "loading", title: "断线重连中...", duration: 2000});
    }
    var me = this;
    if (me.getUserInfoSession()) {
        me.globalData.CHAT = uni.connectSocket({url: me.globalData.chatServerUrl});
        me.globalData.CHAT.onOpen(() => {
            me.globalData.chatSocketOpen = true;
            var chatMsg = {senderId: me.getUserInfoSession().id, msgType: 0};
            var dataContent = {chatMsg: chatMsg};
            me.globalData.CHAT.send({data: JSON.stringify(dataContent)});
        });
        // ... other event handlers ...
    }
}

Backend server bootstrap example:

EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
    ServerBootstrap server = new ServerBootstrap();
    server.group(bossGroup, workerGroup)
          .channel(NioServerSocketChannel.class)
          .childHandler(new WSServerInitializer());
    ChannelFuture cf = server.bind(875).sync();
    cf.channel().closeFuture().sync();
} finally {
    bossGroup.shutdownGracefully();
    workerGroup.shutdownGracefully();
}

Channel initializer example:

protected void initChannel(SocketChannel ch) throws Exception {
    ChannelPipeline p = ch.pipeline();
    p.addLast(new HttpServerCodec());
    p.addLast(new ChunkedWriteHandler());
    p.addLast(new HttpObjectAggregator(1024 * 64));
    p.addLast(new WebSocketServerProtocolHandler("/ws"));
    p.addLast(new ChatHandler());
}

Core ChatHandler snippet (simplified):

public class ChatHandler extends SimpleChannelInboundHandler
{
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame frame) throws Exception {
        DataContent dc = JsonUtils.jsonToPojo(frame.text(), DataContent.class);
        ChatMsg msg = dc.getChatMsg();
        if (msg.getMsgType() == MsgTypeEnum.CONNECT_INIT.type) {
            UserChannelSession.putMultiChannels(msg.getSenderId(), ctx.channel());
        } else if (msg.getMsgType() == MsgTypeEnum.WORDS.type) {
            List
targets = UserChannelSession.getMultiChannels(msg.getReceiverId());
            for (Channel ch : targets) {
                ch.writeAndFlush(new TextWebSocketFrame(JsonUtils.objectToJson(dc)));
            }
        }
        ctx.channel().writeAndFlush(new TextWebSocketFrame(ctx.channel().id().asLongText()));
    }
    // handlerAdded, handlerRemoved, exceptionCaught omitted for brevity
}

Finally, the complete workflow—from server startup, channel initialization, connection establishment, message handling, to disconnection cleanup—is summarized, and suggestions for extending the system (offline storage, persistence, group chat) are given.

JavaBackend DevelopmentNettyWebSocketreal-time communicationIO model
Architect
Written by

Architect

Professional architect sharing high‑quality architecture insights. Topics include high‑availability, high‑performance, high‑stability architectures, big data, machine learning, Java, system and distributed architecture, AI, and practical large‑scale architecture case studies. Open to ideas‑driven architects who enjoy sharing and learning.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.