springboot整合netty(二)

[TOC]java

前言

上一篇讲了netty的一个入门的demo;项目上我也把数据处理作好了,就要开始存数据库了;我用的mybatis框架,若是单独使用仍是以为比较麻烦,因此就用了springboot+mybatis+netty;本篇主要讲netty与springboot的整合,以及我在这个过程当中遇到的问题,又是怎么去解决的;git

正文

我在作springboot与netty整合的时候在谷歌,百度找了无数文章,都没有一篇是本身想要的,也达不到本身所想的目的;github

代码

1. 新建一个springboot项目,在pom文件中添加netty依赖:

<dependency>
			<groupId>io.netty</groupId>
			<artifactId>netty-all</artifactId>
			<version>5.0.0.Alpha1</version>
		</dependency>
复制代码

2.新建netty服务

其实能够复制上一篇文章的netty的三个服务类,作一些稍微的修改就好了;这里为了方便演示,且修都是改好了的,就直接贴出来了;spring

  1. DiscardServer类:
@Component
public class DiscardServer {
    @Resource
    private ChildChannelHandler childChannelHandler;
    public void run(int port) throws Exception {
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        System.out.println("准备运行端口:" + port);
        try {
            ServerBootstrap bootstrap = new ServerBootstrap();
            bootstrap.group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class)
                    .option(ChannelOption.SO_BACKLOG, 128)
                    .childHandler(childChannelHandler);
            //绑定端口,同步等待成功
            ChannelFuture f = bootstrap.bind(port).sync();
            //等待服务监听端口关闭
            f.channel().closeFuture().sync();
        } finally {
            //退出,释放线程资源
            workerGroup.shutdownGracefully();
            bossGroup.shutdownGracefully();
        }
    }
}

复制代码
  1. ChildChannelHandler类
@Component
public class ChildChannelHandler extends ChannelInitializer<SocketChannel> {
    @Resource
    private DiscardServerHandler discardServerHandler;

    public void initChannel(SocketChannel socketChannel) throws Exception {
        socketChannel.pipeline().addLast(discardServerHandler);
    }
}
复制代码

3.DiscardServerHandler类数据库

特别注意DiscardServerHandler类上须要加@Sharable注解,若是不加的话会报错;bootstrap

@Component
@Sharable
public class DiscardServerHandler extends ChannelHandlerAdapter {
    @Resource
    private BaseService baseService;
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) {

        try {
            ByteBuf in = (ByteBuf) msg;
            System.out.println("传输内容是");
            System.out.println(in.toString(CharsetUtil.UTF_8));
            //这里调用service服务
            baseService.test();
        }  finally {
            ReferenceCountUtil.release(msg);
        }
    }
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        // 出现异常就关闭
        cause.printStackTrace();
        ctx.close();
    }
}
复制代码

3.netty调用所需的服务类

1.BaseService接口springboot

public interface BaseService {
    /** * 测试接口 */
    void test();
}
复制代码

2.接口实现类BaseServiceImpl:mybatis

@Service
public class BaseServiceImpl implements BaseService {
    @Override
    public void test() {
        System.out.println("调用service服务");
    }
}

复制代码

4 springboot启动类

  1. 因为main方法是静态方法,netty服务启动类不是静态类,在main方法里面须要用new的方式启动;
  2. 也能够将netty服务启动类改成静态类,而后调用其余非静态的类时就得用new方法来构造其余类了;

我也百度到了几篇文章说实现CommandLineRunner接口,因此我用了springboot启动类实现CommandLineRunner接口的run方法,而后在run方法里启动netty服务框架

@SpringBootApplication
public class DemoApplication implements CommandLineRunner {
	@Resource
	private DiscardServer discardServer;

	public static void main(String[] args) {
		SpringApplication.run(DemoApplication.class, args);
	}

	@Override
	public void run(String... args) throws Exception {
		discardServer.run(8080);
	}
}
复制代码

5.测试

写一个能发送数据的socket就能够了;socket

发送的数据为:

public static void main(String[] args){
        try {
            Socket socket=new Socket("localhost",8080);
            OutputStream outputStream = socket.getOutputStream();
            PrintWriter printWriter=new PrintWriter(outputStream);
            printWriter.write("$tmb00035ET3318/08/22 11:5804029.94,027.25,20.00,20.00$");
            printWriter.flush();
            socket.shutdownOutput();
            socket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
复制代码

个人测试结果:

传输内容是
$tmb00035ET3318/08/22 11:5804029.94,027.25,20.00,20.00$
aaaaa
复制代码

到这里,netty与springboot的整合就完成了;

我在整合过程当中遇到的问题

我使用springboot结合netty的流程

springboot启动类中启动netty启动类(DiscardServer),netty启动类(DiscardServer)再调用初始化channel类(ChildChannelHandler),而后初始化channel类再调用(DiscardServerHandler)类;而后DiscardServerHandler类再调用service服务;以下示例图:

avatar

问题

  1. springboot启动类我并无实现CommandLineRunner接口,直接在main方法经过new的方式启动netty服务
  2. 我实现了CommandLineRunner接口,可是我在run方法中用的new的方式启动的netty服务或者我在run方法使用注入的方式启动netty,可是在其余某个地方调用另外一个类使用了new的方式;
  3. DiscardServerHandler类上为标记@Sharable类,会报错误;

以上总结起来的问题就是我在springboot整合netty的过程当中有其中一处的调用其余类时使用的方式是new构造的,这样虽然springboot能启动,netty也能启动,可是netty服务中使用new构造的那个类中没法依赖注入,会报空指针异常;

举个栗子:在图中的过程当中,我在ChildChannelHandler类中经过new的方式调用DiscardServerHandler类,其余的过程都是使用注入的方式调用,就会出现上边的问题;

在遇到空指针的时候,我把spring托管的bean打印了出来,全部的类都在spring的托管中,可是就是没法注入,我也一直没有明白怎么回事,最后用了一个极端的方法,就是在调用服务时,获取spring的上下文,而后再根据名字来获取bean,你谷歌或百度:非托管类调用spring托管类,就能找到不少文章了;虽然用这个方式能解决上述的问题,但老是很差的;

最后的解决办法:因此类之间的调用都使用spring的依赖注入,别用new的方式来调用或者静态方法的方式调用

总结

既然项目中用到了spring,那么类与类之间的调用就用依赖注入,否则会报空指针的问题(就是非托管对象调用spring托管对象);这也算是一个常识性的问题了,只是本身如今才遇到这样的问题,仍是要踩坑才能遇涨记性啊;这些问题困扰了我两三天,仍是要有经验的人带,若是有经验的人带的话,说不几分钟就搞定了;

netty的文章到这里就告一段落了,接下来就是赶项目了;哈哈;

GitHub项目地址:

相关文章
相关标签/搜索