四、 业务处理类与心跳包超时处理
业务处理类继承了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);