SpringBoot+Netty 防止主线程阻塞

1 篇文章 0 订阅
1 篇文章 0 订阅
SpringApplication
@SpringBootApplication
@MapperScan("com.lhb.dao") // mybatis扫描
@EnableAsync//注意这里,这个注解启用了线程池
public class Application extends SpringApplication {
    public static void main(String[] args) {
        SpringApplication.run(Application.class);
        System.out.println("SpringBoot start");
    }
}

NettyServer

package com.lhb.netty;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.CommandLineRunner;
import org.springframework.core.annotation.Order;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

import javax.annotation.PreDestroy;

/**
 * 作者:Haibo.Liu
 * 描述:
 * 日期: 2019/4/23
 * QQ:836915746
 */
@Component//当成组件处理
@Order(value = 1)//这里表示启动顺序
public class Server implements CommandLineRunner {

    private Logger logger = LoggerFactory.getLogger(this.getClass());

    private EventLoopGroup bossGroup;
    private EventLoopGroup workerGroup;
    private Channel channel;

    public void start() {
        bossGroup = new NioEventLoopGroup(); //监听线程组,监听客户请求
        workerGroup = new NioEventLoopGroup();//处理客户端相关操作线程组,负责处理与客户端的数据通讯
        try {
            ServerBootstrap serverBootstrap = new ServerBootstrap();
            //设置监听组,线程组,初始化器
            serverBootstrap.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class).childHandler(new ChannelInitializer() {
                @Override
                protected void initChannel(Channel channel) {
                    ChannelPipeline pipeline = channel.pipeline();
                    pipeline.addLast(new ServerHandler());
                    logger.info("Client :" + channel.remoteAddress() + "已经连接上");
                }
            });
            logger.info("Netty Server start");
            //绑定端口号
            ChannelFuture f = serverBootstrap.bind(6300).sync();
            channel = f.channel().closeFuture().sync().channel();//这里绑定端口启动后,会阻塞线程,也就是为什么要用线程池启动的原因

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            workerGroup.shutdownGracefully();
            bossGroup.shutdownGracefully();
            stop();
            logger.info("Netty Server close");
        }
    }

    @PreDestroy
    public void stop() {
        if (channel != null) {
            logger.info("Netty Server close");
            workerGroup.shutdownGracefully();
            bossGroup.shutdownGracefully();
        }
    }

    @Async//注意这里,组件启动时会执行run,这个注解是让线程异步执行,这样不影响主线程
    @Override
    public void run(String... args) {
        start();
    }
}
ServerHandler
package com.lhb.netty;

import com.lhb.dao.WtsrEquipmentMapper;
import com.lhb.redis.RedisUtil;
import io.netty.buffer.ByteBuf;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.math.BigInteger;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 作者:Haibo.Liu
 * 描述:
 * 日期: 2019/4/23
 * QQ:836915746
 */
@Component//ServerHandler 当成组件处理,这样可以直接注入bean
public class ServerHandler extends ByteToMessageDecoder {

    private static Logger logger = LoggerFactory.getLogger(ServerHandler.class);

    //这里是你要注入的bean
    private static RedisUtil redisUtil;
    private static WtsrEquipmentMapper wtsrEquipmentMapper;

    @Resource
    public void setWtsrEquipmentMapper(WtsrEquipmentMapper wtsrEquipmentMapper) {
        ServerHandler.wtsrEquipmentMapper = wtsrEquipmentMapper;
    }

    @Resource
    public void setRedisUtil(RedisUtil redisUtil) {
        ServerHandler.redisUtil = redisUtil;
    }


    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) {
        byte[] bytes = new byte[in.readableBytes()];
        in.readBytes(bytes);
        
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        Channel incoming = ctx.channel();
        cause.printStackTrace();
        ctx.close();
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        logger.info("tcp断开");
        ctx.fireChannelInactive();
        Channel channel = ctx.channel();
        if (channel != null && channel.isActive()) {
            ctx.close();
        }
    }

  

    public static void sendDeviceMsg(ChannelHandlerContext ctx, String msg) {
        if (ctx != null) {
            byte[] bytes = msg.getBytes();
            ByteBuf encoded = ctx.alloc().buffer(bytes.length);
            encoded.writeBytes(bytes);
            ctx.channel().writeAndFlush(encoded);
        }
    }


}

 

  • 5
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值