用spring-boot和netty做一个心跳程序,安卓端和服务端连接,服务端检查客户端是否在线,并且记录在线时间和离开时间,并保存到数据库中,现在调用service层的方法时,出现了java.lang.NullPointerException
,下面是部分代码:
@SpringBootApplication public class App { public static void main(String[] args) { SpringApplication.run(App.class, args); HeartbeatServer.start(8089); } }
public class HeartbeatServer { public static void start(int port) { // Configure the server. EventLoopGroup bossGroup = new NioEventLoopGroup(1); EventLoopGroup workerGroup = new NioEventLoopGroup(); ServerBootstrap b = new ServerBootstrap(); try { b.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class).option(ChannelOption.SO_BACKLOG, 10000).childHandler(new ChannelInitializer() { @Override public void initChannel(SocketChannel ch) throws Exception { ch.pipeline().addLast("framer", new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter())).addLast("decoder", new StringDecoder()).addLast("encoder", new StringEncoder()).addLast(new IdleStateHandler(60, 0, 0), // 心跳控制 new ServerHandler()); } }); // Start the server. ChannelFuture f = b.bind(port).sync(); // Wait until the server socket is closed. f.channel().closeFuture().sync(); } catch (InterruptedException e) { e.printStackTrace(); } finally { // Shut down all event loops to terminate all threads. bossGroup.shutdownGracefully(); workerGroup.shutdownGracefully(); } } }
@Component public class ServerHandler extends SimpleChannelInboundHandler{ private long comingTime; private long leaveTime; private Map users = new HashMap (); @Autowired @Qualifier(CompanyAttendanceService.SERVICE_NAME) private CompanyAttendanceService cs; @Override public void channelRegistered(ChannelHandlerContext ctx) throws Exception { comingTime = System.currentTimeMillis(); System.out.println(ctx.channel().remoteAddress() + "连接成功:" + comingTime); ctx.fireChannelRegistered(); } @Override protected void channelRead0(ChannelHandlerContext ctx, String message) throws Exception { Channel incoming = ctx.channel(); Integer userId = users.get(ctx.channel().remoteAddress()); if (userId == null) { cs.updateLeaveTime(Integer.valueOf(message), comingTime); } users.put(incoming.localAddress().toString(), Integer.valueOf(message)); System.out.println("收到客户端" + "[" + incoming.remoteAddress() + "]" + "的消息:" + message); incoming.writeAndFlush("[" + incoming.remoteAddress() + "]" + message + "\n"); } @Override public void channelActive(ChannelHandlerContext ctx) throws Exception { Channel incoming = ctx.channel(); System.out.println(incoming.remoteAddress() + "在线"); } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { Channel incoming = ctx.channel(); System.out.println(incoming.remoteAddress() + "异常"); // 当出现异常就关闭连接 cause.printStackTrace(); ctx.close(); } @Override public void channelInactive(ChannelHandlerContext ctx) throws Exception { leaveTime = System.currentTimeMillis(); Channel incoming = ctx.channel(); int userId = users.get(incoming.localAddress().toString()); System.out.println(incoming.remoteAddress() + "掉线,userId:" + userId); users.remove(incoming.localAddress().toString()); cs.updateOnlineTime(userId, leaveTime, comingTime); } @Override public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception { /* 心跳处理 */ if (evt instanceof IdleStateEvent) { IdleStateEvent event = (IdleStateEvent) evt; if (event.state() == IdleState.READER_IDLE) { /* 读超时 */ System.out.println("READER_IDLE 读超时"); ctx.disconnect(); } else if (event.state() == IdleState.WRITER_IDLE) { /* 写超时 */ System.out.println("WRITER_IDLE 写超时"); } else if (event.state() == IdleState.ALL_IDLE) { /* 总超时 */ System.out.println("ALL_IDLE 总超时"); } } } }
注意这几块代码:
@Component
public class ServerHandler extends SimpleChannelInboundHandler<String>{
...
}
你的原意是想通过@Component
进行注入,但是
xxx.addLast(new IdleStateHandler(60, 0, 0), new ServerHandler());
你这里的ServerHandler
是自己new
的,所以Spring就无能为力了
所以你这里的ServerHandler
应该通过Spring创建,交给Spring容器管理