springboot+netty+redis框架服务端的实现(二) ------ 业务处理类与心跳包超时处理、redis工具类、netty启动类及遗留问题

四、 业务处理类与心跳包超时处理

业务处理类继承了ChannelInboundHandlerAdapter
通过重载userEventTriggered方法,可以实现心跳超时的设置
代码如下:

public class ServerHandler extends ChannelInboundHandlerAdapter {
   

    private static final Logger log = LoggerFactory.getLogger(ServerHandler.class);
    
    private ChannelCache channelCache = SpringUtil.getBean(ChannelCache.class);
    
    private static ConcurrentHashMap<ChannelId, Integer> channelIdleTime = new ConcurrentHashMap<ChannelId, Integer>();

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
   
        Message message = (Message) msg;
        Result result = new Result();
        // 非登录接口,验证是否已登录过
        if (message.getModule() != 1) {
   
            if (channelCache.getChannel(ctx.channel()) == null) {
   
                result = new Result(0, "need auth");
                ctx.writeAndFlush(result);
                return;
            }
        }
        channelCache.addChannel(ctx.channel(), message.getUid());
        result = MyAnnotionUtil.process(ctx, message);
        log.info("result: " + result.toString());
        ctx.writeAndFlush(result);
    }

    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
   
        if (evt instanceof IdleStateEvent) {
   

            SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

            IdleStateEvent e = (IdleStateEvent) evt;
            if (e.state() == IdleState.READER_IDLE) {
   
                log.warn("---READER_IDLE---" + dateFormat.format(new Date()));
                ChannelId channelId = ctx.channel().id();
                Integer times = channelIdleTime.get(channelId);
                if (times == null) {
   
                    channelIdleTime.put(channelId, 1);
                } else {
   
                    int num = times.intValue() + 1;
                    if (num >= Const.TIME_OUT_NUM) {
   
                        log.error("--- TIME OUT ---");
                        channelIdleTime.remove(channelId);
                        channelCache.removeChannel(ctx.channel());
                        ctx.close();
                    } else {
   
                        channelIdleTime.put(channelId, num);
                    }
                }
            }
        } else {
   
            super.userEventTriggered(ctx, evt);
        }
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
   
        log.error("exceptionCaught:" + cause.getMessage());
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
   
        log.info("====== channelInactive ======");
        channelCache.removeChannel(ctx.channel());
        ctx.close();
        log.info("====== Channel close ======");
    }

}

由于ServerHandler类不是由spring管理的,而是通过new的方式,通过ServerChannelInitializer进行配置的,所以自定义了一个SpringUtil工具类,来获取由spring管理的bean

@Component
public class SpringUtil implements ApplicationContextAware {
   

    private static ApplicationContext applicationContext = null;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
   
        if (SpringUtil.applicationContext == null) {
   
            SpringUtil.applicationContext = applicationContext;
        }
    }

    public static ApplicationContext getApplicationContext() {
   
        return applicationContext;
    }

    public static void setAppCtx(ApplicationContext webAppCtx) {
   
        if (webAppCtx != null) {
   
            applicationContext = webAppCtx;
        }
    }

    /**
     * 拿到ApplicationContext对象实例后就可以手动获取Bean的注入实例对象
     */
    public static <T> T getBean(Class<T> clazz) {
   
        return getApplicationContext().getBean(clazz);
    }

    public static <T> T getBean(String name, Class<T> clazz) throws ClassNotFoundException {
   
        return getApplicationContext().getBean(name, clazz);
    }

    public static final Object getBean(String beanName) {
   
        return getApplicationContext().getBean(beanName);
    }

    public static final Object getBean(String beanName, String className) throws ClassNotFoundException {
   
        Class<?> clz = Class.forName(className);
        return getApplicationContext().getBean(beanName, clz.getClass());
    }

    public static boolean containsBean(String name) {
   
        return getApplicationContext().containsBean(name);
    }

    public static boolean isSingleton(String name) throws NoSuchBeanDefinitionException {
   
        return getApplicationContext().isSingleton(name);
    }

    public static Class<?> getType(String name) throws NoSuchBeanDefinitionException {
   
        return getApplicationContext().getType(name);
    }

    public static String[] getAliases(String name) throws NoSuchBeanDefinitionException {
   
        return getApplicationContext().getAliases(name);
    
  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值