0

用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<SocketChannel>()
            {
                @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<String>
{
    private long comingTime;
    private long leaveTime;
    private Map<String, Integer> users = new HashMap<String, Integer>();

    @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 总超时");
            }
        }
    }

}
jiawen 84
2016-06-18 提问
1 个回答
0

已采纳

注意这几块代码:

@Component
public class ServerHandler extends SimpleChannelInboundHandler<String>{
    ...
}

你的原意是想通过@Component进行注入,但是

xxx.addLast(new IdleStateHandler(60, 0, 0), new ServerHandler());

你这里的ServerHandler是自己new的,所以Spring就无能为力了
所以你这里的ServerHandler应该通过Spring创建,交给Spring容器管理

撰写答案

你可能感兴趣的

推广链接