springboot集成netty实战

pom依赖

<dependency>
	<groupId>io.netty</groupId>
	<artifactId>netty-all</artifactId>
</dependency>

Netty服务器配置

import java.util.concurrent.TimeUnit;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
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;

/**
 * NettyServer Netty服务器配置
 * @author
 * @date
 */
public class NettyServer {
    
    private static Logger logger = LoggerFactory.getLogger(NettyServer.class);
    
    private final int port;
    private EventLoopGroup bossGroup = new NioEventLoopGroup();
    private EventLoopGroup group = new NioEventLoopGroup();
    private ChannelFuture cf;
    
    public NettyServer(int port) {
        this.port = port;
    }
 
    public void start() throws Exception {
        bossGroup = new NioEventLoopGroup();
        group = new NioEventLoopGroup();
        ServerBootstrap sb = new ServerBootstrap();
        sb.option(ChannelOption.SO_BACKLOG, 20);
        sb.group(group, bossGroup) // 绑定线程池
                .channel(NioServerSocketChannel.class) // 指定使用的channel
                .localAddress(this.port)// 绑定监听端口
                .childHandler(new ChannelInitializer<SocketChannel>() { // 绑定客户端连接时候触发操作
                    @Override
                    protected void initChannel(SocketChannel ch) throws Exception {
                        logger.info("收到新的客户端连接: {}",ch.toString());
                        //websocket协议本身是基于http协议的,所以这边也要使用http解编码器
                        ch.pipeline().addLast(new HttpServerCodec());
                        //心跳检测,参数说明:[长时间未写:长时间未读:长时间未读写:时间单位]~[读写是对连接本生而言,写:未向服务端发送消息,读:未收到服务端的消息]
                        ch.pipeline().addLast(new IdleStateHandler(0,5*60,0, TimeUnit.SECONDS));
                        ch.pipeline().addLast(new IdleStateHandlerInitializer());
                        //以块的方式来写的处理器
                        ch.pipeline().addLast(new ChunkedWriteHandler());
                        ch.pipeline().addLast(new HttpObjectAggregator(8192));
                        ch.pipeline().addLast(new ChatWebSocketHandler());
                        //最后一个参数为数据包大小
                        ch.pipeline().addLast(new WebSocketServerProtocolHandler("/ws", null, true, 65536 * 10));
                    }
                });
        cf = sb.bind().sync(); // 服务器异步创建绑定
        logger.info(NettyServer.class + " 启动正在监听: " + cf.channel().localAddress());
    }
    
    public void destroy() {
    	logger.info(NettyServer.class + " netty服务监听关闭: " + cf.channel().localAddress());
    	try {
    		cf.channel().closeFuture().sync();// 关闭服务器通道
    	} catch (Exception e) {
    		e.printStackTrace();
    	}finally{   		
    		bossGroup.shutdownGracefully().syncUninterruptibly();
    		group.shutdownGracefully().syncUninterruptibly();
    	}

    }
}

注意:

cf.channel().closeFuture().sync(); // 关闭服务器通道 ~~~~~会阻塞主进程,一般用于单元测试

心跳检测

import java.util.Collection;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.timeout.IdleStateEvent;
import io.netty.util.CharsetUtil;

public class IdleStateHandlerInitializer extends ChannelInboundHandlerAdapter {
	
     private static final ByteBuf HEARTBEAT_SEQUENCE = Unpooled.unreleasableBuffer(
             Unpooled.copiedBuffer("HEARTBEAT", CharsetUtil.UTF_8));
     
     @Override
     public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
         if(evt instanceof IdleStateEvent) {
			 ctx.writeAndFlush(HEARTBEAT_SEQUENCE.duplicate()).addListener(ChannelFutureListener.CLOSE_ON_FAILURE);    // 关闭连接
         } else {
             // 传递给下一个处理程序
             super.userEventTriggered(ctx, evt);
         }
     }

}

使用监听器启动

import java.util.Calendar;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


public class NettyServerListener implements ServletContextListener{
	
	private static final Logger logger = LoggerFactory.getLogger(NettyServerListener.class);
    private NettyServer nettyServer;
    
    @Override
    public void contextInitialized(ServletContextEvent sce) {
    	nettyServer =  new NettyServer(8091);
    	try {
        	nettyServer.start();
        } catch (Exception e) {
        	logger.error("netty server abnormal startup {netty服务启动异常}", e);
        }
    }
    
    /**
     * @Author      销毁  
     * @Date        2020年8月27日 上午10:57:53   
     * @param sce   
     * @see javax.servlet.ServletContextListener#contextDestroyed(javax.servlet.ServletContextEvent)
     */
    @Override
    public void contextDestroyed(ServletContextEvent sce) {
        logger.info("destroy() of netty"+ Calendar.getInstance().getTime()+"  flag:"+(null==nettyServer));
        nettyServer.destroy();
    }
}

装配用于启动netty服务的监听器

import org.springframework.boot.web.servlet.ServletListenerRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;


@Configuration
public class WebMvcConfig  implements WebMvcConfigurer{
    /**
     * 
     * @Description 配置用于启动netty服务的监听器  
     * @Author      xd  
     * @Date        2020年8月27日 上午10:13:47  
     * @return
     * @return ServletListenerRegistrationBean 返回类型
     */
    @Bean(name = "nettyServerListener")
    public ServletListenerRegistrationBean<NettyServerListener> nettyListenerRegist() {
        ServletListenerRegistrationBean<NettyServerListener> srb = new ServletListenerRegistrationBean<NettyServerListener>();
        srb.setListener(new NettyServerListener());
        return srb;
    }
}
  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值