springboot整合netty

    556

    springboot整合netty

    1、引入pom

    <!--集成netty-->
            <dependency>
                <groupId>io.netty</groupId>
                <artifactId>netty-all</artifactId>
            </dependency>
    

    2、引入注册netty服务器,配置端口

    import io.netty.bootstrap.ServerBootstrap;
    import io.netty.channel.ChannelFuture;
    import io.netty.channel.EventLoopGroup;
    import io.netty.channel.nio.NioEventLoopGroup;
    import io.netty.channel.socket.nio.NioServerSocketChannel;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.stereotype.Component;
    
    @Component
    public class WSServer {
    
        protected final static Logger logger = LoggerFactory.getLogger(WSServer.class);
    
    //    @Value("${netty.websocket.port}")
    //    private int port;
    
        private static class SingletionWSServer {
            static final WSServer instance = new WSServer();
        }
    
        public static WSServer getInstance() {
            return SingletionWSServer.instance;
        }
    
        private EventLoopGroup mainGroup;
        private EventLoopGroup subGroup;
        private ServerBootstrap server;
        private ChannelFuture future;
    
        public WSServer() {
            mainGroup = new NioEventLoopGroup();
            subGroup = new NioEventLoopGroup();
            server = new ServerBootstrap();
            server.group(mainGroup, subGroup)
                    .channel(NioServerSocketChannel.class)
                    .childHandler(new WSServerInitialzer());
        }
    
        public void start() {
            this.future = server.bind(8088);
            System.err.println("netty websocket server 启动完毕...");
        }
    }
    

    3、配置自定义Handler类,配置请求路径

    import com.dbgs.blct.config.netty.handler.ChatHandler;
    import com.dbgs.blct.config.netty.handler.HeartBeatHandler;
    import io.netty.channel.ChannelInitializer;
    import io.netty.channel.ChannelPipeline;
    import io.netty.channel.socket.SocketChannel;
    import io.netty.handler.codec.http.HttpObjectAggregator;
    import io.netty.handler.codec.http.HttpServerCodec;
    import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
    import io.netty.handler.stream.ChunkedWriteHandler;
    import io.netty.handler.timeout.IdleStateHandler;
    
    public class WSServerInitialzer extends ChannelInitializer<SocketChannel> {
    
        @Override
        protected void initChannel(SocketChannel ch) throws Exception {
            ChannelPipeline pipeline = ch.pipeline();
    
            // websocket 基于http协议,所以要有http编解码器
            pipeline.addLast(new HttpServerCodec());
            pipeline.addLast(new ChunkedWriteHandler());
            // 几乎在netty中的编程,都会使用到此hanler
            pipeline.addLast(new HttpObjectAggregator(1024 * 64));
            pipeline.addLast(new WebSocketServerProtocolHandler("/ws"));
            // 自定义的handler
            pipeline.addLast(new ChatHandler());
        }
    
    }
    

    4、添加Handler(专门接受信息的类)

    import com.dbgs.blct.entity.enums.MsgActionEnum;
    import io.netty.channel.*;
    import io.netty.channel.group.ChannelGroup;
    import io.netty.channel.group.DefaultChannelGroup;
    import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
    import io.netty.util.concurrent.GlobalEventExecutor;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import java.net.InetSocketAddress
    
    /**
     * @Description: 处理消息的handler
     */
    public class ChatHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {
    
        protected final static Logger logger = LoggerFactory.getLogger(ChatHandler.class);
        // 用于记录和管理所有客户端的channle,ChannelGroup是一个线程安全的集合
        public static ChannelGroup users = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
    
        @Override
        protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg){
            // 获取客户端传输过来的消息
            String content = msg.text();
           
        }
    
        /**
         * 当客户端连接服务端之后(打开连接)
         * 获取客户端的channle,并且放到ChannelGroup中去进行管理
         */
        @Override
        public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
            logger.info("客户端新增,时间为:{}");
            users.add(ctx.channel());
        }
    
        @Override
        public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
            String channelId = ctx.channel().id().asShortText();
            logger.info("客户端被移除,channelId为:{},时间:{}", channelId);
            // 当触发handlerRemoved,ChannelGroup会自动移除对应客户端的channel
            users.remove(ctx.channel());
        }
    
        @Override
        public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
            cause.printStackTrace();
            // 发生异常之后关闭连接(关闭channel),随后从ChannelGroup中移除
            ctx.channel().close();
        }
    

    5、注入到spring容器,启动可加载

    import com.dbgs.blct.config.netty.server.WSServer;
    import org.springframework.context.ApplicationListener;
    import org.springframework.context.event.ContextRefreshedEvent;
    import org.springframework.stereotype.Component;
    
    @Component
    public class NettyBooter implements ApplicationListener<ContextRefreshedEvent> {
    
        @Override
        public void onApplicationEvent(ContextRefreshedEvent event) {
            if (event.getApplicationContext().getParent() == null) {
                try {
                    WSServer.getInstance().start();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }