Skip to content

Spring Boot 整合 Netty-Boot ​

本指南将演示如何在 Spring Boot 应用程序中集成 Netty-Boot,使您能够在 Spring Boot 的上下文中使用 Netty 来处理 HTTP 和 WebSocket 请求。

前提条件 ​

  • JDK 版本:8 或更高
  • 构建工具:Maven 或 Gradle
  • 知识准备:具备 Spring Boot 和 Netty 的基本知识

步骤一:配置 Netty 服务器端口 ​

首先,在 app.properties 配置文件中指定 Netty 服务器运行的端口。

properties
netty.server.port=8869

这将设置 Netty 服务器监听在 8869 端口上。

步骤二:创建 HTTP 处理器 ​

创建一个名为 OkHandler 的处理器类,用于管理 HTTP 请求。

java
package nexus.io.study.netty.boot.handler;

import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.websocketx.BinaryWebSocketFrame;
import io.netty.handler.codec.http.websocketx.CloseWebSocketFrame;
import io.netty.handler.codec.http.websocketx.PingWebSocketFrame;
import io.netty.handler.codec.http.websocketx.PongWebSocketFrame;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.handler.codec.http.websocketx.WebSocketFrame;
import lombok.extern.slf4j.Slf4j;

@Slf4j
public class WsHandler extends SimpleChannelInboundHandler<WebSocketFrame> {

  @Override
  protected void channelRead0(ChannelHandlerContext ctx, WebSocketFrame frame) throws Exception {
    if (frame instanceof TextWebSocketFrame) {
      String requestText = ((TextWebSocketFrame) frame).text();
      // 返回相同的消息
      ctx.channel().writeAndFlush(new TextWebSocketFrame("Server received: " + requestText));

    } else if (frame instanceof BinaryWebSocketFrame) {

    } else if (frame instanceof CloseWebSocketFrame) {
      ctx.channel().close();

    } else if (frame instanceof PingWebSocketFrame) {
      ctx.channel().writeAndFlush(new PongWebSocketFrame(frame.content().retain()));

    } else {
      throw new UnsupportedOperationException("不支持的帧类型: " + frame.getClass().getName());
    }
  }

  @Override
  public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
    log.info("ctx:{}", ctx);
  }

  @Override
  public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
    log.info("ctx:{}", ctx);
  }
}

说明:

  • 处理不同类型的 WebSocket 帧:
    • TextWebSocketFrame:将文本消息回传给客户端。
    • CloseWebSocketFrame:关闭连接。
    • PingWebSocketFrame:响应一个 PongWebSocketFrame。

步骤四:配置 Netty-Boot 服务器 ​

创建一个名为 NettyBootConfig 的配置类,设置 Netty 服务器和处理器。

java
package com.netty;

import nexus.io.context.BootConfiguration;
import nexus.io.jfinal.aop.Aop;
import nexus.io.netty.boot.http.HttpRequestRouter;
import nexus.io.netty.boot.listener.ChannelConnectionListener;
import nexus.io.netty.boot.server.NettyBootServer;
import nexus.io.netty.boot.websocket.WebsocketRouter;
import com.netty.handler.ChatHandler;
import com.netty.handler.OkHandler;
import com.netty.handler.WsHandler;
import com.netty.listener.MyChannelConnectionListener;

public class NettyBootConfig implements BootConfiguration {

    @Override
    public void config() {
        NettyBootServer nettyBootServer = NettyBootServer.me();

        // 创建并设置自定义的 ChannelConnectionListener
        ChannelConnectionListener myChannelConnectionListener = new MyChannelConnectionListener();
        nettyBootServer.setChannelConnectionListener(myChannelConnectionListener);

        // 设置 HTTP 路由
        HttpRequestRouter httpRouter = nettyBootServer.getHttpRequestRouter();
        OkHandler okHandler = Aop.get(OkHandler.class);
        httpRouter.add("/txt", okHandler::txt);
        httpRouter.add("/json", okHandler::json);
        httpRouter.add("/echo", okHandler::echo);

        // 设置 WebSocket 路由
        WebsocketRouter websocketRouter = nettyBootServer.getWebsocketRouter();
        Supplier<SimpleChannelInboundHandler<WebSocketFrame>> wsHandlerSupplier = WsHandler::new;
        websocketRouter.add("/ws", wsHandlerSupplier);
    }
}

说明:

  • 实现 BootConfiguration 接口来配置 Netty 服务器。
  • 设置自定义的 ChannelConnectionListener 来管理连接事件。
  • 使用 HttpRequestRouter 配置 HTTP 路由,将 URL 映射到处理方法。
  • 使用 WebsocketRouter 配置 WebSocket 路由。

步骤五:将 Netty-Boot 集成到 Spring Boot 中 ​

创建一个名为 NettyServerConfig 的 Spring Boot 配置类,将 Netty 服务器运行在 Spring 上下文中。

java
package com.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import nexus.io.context.Context;
import nexus.io.netty.boot.NettyApplication;
import com.netty.NettyBootConfig;

@Configuration
public class NettyServerConfig {

    @Bean(destroyMethod = "close")
    public Context nettyContext() {
        NettyBootConfig bootConfig = new NettyBootConfig();
        return NettyApplication.run(NettyServerConfig.class, bootConfig, new String[] {});
    }
}

说明:

  • 使用 @Configuration 注解,表示这是一个 Spring 配置类。
  • 定义了一个名为 nettyContext 的 Bean,使用 NettyApplication.run 方法来初始化和运行 Netty 服务器。
  • 设置 destroyMethod = "close",确保在应用程序上下文关闭时,Netty 服务器能够正确关闭。

步骤六:启动应用程序并进行测试 ​

所有配置就绪后,以正常方式启动您的 Spring Boot 应用程序。Netty 服务器将被初始化,并开始监听指定的端口(8869)。

测试 HTTP 端点 ​

  • 纯文本响应

    发送 GET 请求到 http://localhost:8869/txt:

    bash
    curl http://localhost:8869/txt

    响应:

    Hello, this is the HTTP response!
  • JSON 响应

    发送 GET 请求到 http://localhost:8869/json:

    bash
    curl http://localhost:8869/json

    响应:

    json
    { "status": "ok", "message": "Success" }
  • Echo 端点

    发送 POST 请求到 http://localhost:8869/echo,并附带数据:

    bash
    curl -X POST http://localhost:8869/echo -d "测试数据"

    响应:

    [包含 "测试数据" 的完整 HTTP 请求详情]

测试 WebSocket 端点 ​

使用 WebSocket 客户端连接到 ws://localhost:8869/ws。

  • 发送文本消息,例如 "Hello WebSocket"。

  • 服务器将响应:

    Server received: Hello WebSocket

结论 ​

您已经成功地将 Netty-Boot 集成到了 Spring Boot 应用程序中,能够处理 HTTP 和 WebSocket 请求。通过这种设置,您可以在熟悉的 Spring Boot 环境中利用 Netty 的高性能网络能力。

附加说明 ​

  • 依赖注入:处理器通过 Aop.get(Class) 方法获取,意味着使用了 AOP 框架进行依赖注入。请确保您的应用程序中已正确配置 AOP(面向切面编程)。
  • ChannelConnectionListener:自定义实现的 ChannelConnectionListener 允许您管理与通道连接相关的事件,例如通道何时激活或不活跃。
  • 线程安全:如果处理器维护状态,请确保它们是线程安全的,因为 Netty 可能会并发处理多个请求。

参考资料 ​

MIT Licensed