学习 java netty -- ServerBootstrap

Posted 夏天的技术博客

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了学习 java netty -- ServerBootstrap相关的知识,希望对你有一定的参考价值。

前言:我们自己使用java nio开发网络程序是非常繁琐的,netty为我们做好了一切,其中ServerBootstrap是一个启动辅助类,了解它我们就能开发出简单的nio 服务端程序。


不理解Nio中channel和handler等可参考上一篇文章
学习 java netty (一) – java nio


ServerBootstrap():

//创建一个ServerBootstrap对象
ServerBootstrap server = new ServerBootstrap;

ServerBootstrap只有一个无参构造函数,这里使用了构建器模式,原因是ServerBootstrap的参数过多,构建器模式就是用来处理构造函数参数过多而导致需要多个构造函数的问题。
简单来看:
当参数过多我们写出来的构造函数可能是
ServerBootstrap(int i);
ServerBootstrap(int i, double b);
ServerBootstrap(int i, double b, char c);

使用构建器模式后
ServerBootstrap(); 只有一个无参构造函数,其余需要构建的部分我们写到成员函数里,那么使用起来就像这样。
ServerBootstrap server = ServerBootstrap();
server
.construct1()
.construct2()
.consturct3()

当然也可以
server.construct1().construct3()…
我们使用哪个构建哪个即可,这就是构建器模式
构建器模式缺点:
写起来比较复杂,用起来开销很大,只适用于构造函数参数过多的情况。
注意构建器模式要返回this


ServerBootstrap继承自AbstractBootstrap
看一下ServerBootstrap class内部的变量和方法

public class ServerBootstrap extends AbstractBootstrap<ServerBootstrap, ServerChannel>
    //记录异常日志等错误,用了java的反射机制和工厂模式
    private static final InternalLogger logger = InternalLoggerFactory.getInstance(ServerBootstrap.class);
    //netty4.0引入了名为ChannelOption的新的类型,它提供了类型安全地访问socket选项。ChannelOption class内部就是socket套接字配置参数,例如SO_KEEPALIVE,SO_RECVBUF等
    private final Map<ChannelOption<?>, Object> childOptions = new LinkedHashMap<ChannelOption<?>, Object>();
    //实体的属性
    private final Map<AttributeKey<?>, Object> childAttrs = new LinkedHashMap<AttributeKey<?>, Object>();
    //事件循环,并绑定线程池
    private volatile EventLoopGroup childGroup;
    //处理channel的handler
    private volatile ChannelHandler childHandler;

    //方法
    //只有一个事件循环体,来接受accept和处理IO
    public ServerBootstrap group(EventLoopGroup group);
    //有两个事件循环体,一个用来accept请求,另外一个用来处理clinet的io
    public ServerBootstrap group(EventLoopGroup parentGroup, EventLoopGroup childGroup);
    //设置channel属性
    public <T> ServerBootstrap childOption(ChannelOption<T> childOption, T value);
    //设置那些符合给定属性的channel
    public <T> ServerBootstrap childAttr(AttributeKey<T> childKey, T value) ;
    //child处理channel的handler
    public ServerBootstrap childHandler(ChannelHandler childHandler);
    //return childGroup
    public EventLoopGroup childGroup();
    //初始化并配置一些参数
    void init(Channel channel) throws Exception
    public ServerBootstrap validate();

还有一些不太重要方法上面没有列举出来,还有些方法来自于父类AbstractBootstrap,代码太长就不贴了,感兴趣可以去git上看源码
AbstractBootstrap.java
但是从ServerBootstrap启动辅助类和ServerBootstrap class内部的参数和接口可以看出ServerBootstrap主要是用来配置服务端的。仅仅使用了一个对象ServerBootstrap就完成了复杂的服务端配置,让我们编程简化了许多。


看个例子:

public class EchoServer 
    private final int port;

    public EchoServer(int port) 
        this.port = port;
    

    public void run() throws Exception
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        try 
            //创建一个ServerBootstrap,下面开始配置
            ServerBootstrap b = new ServerBootstrap();
            //创建了两个EventLoopGroup(线程池和selector,reactor模型)一个main loop一个child loop通过ServerBoootstrap的group方法组合起来
            //接着通过option方法传递服务端NioserverSocketChannel(服务端套接字)设置它的backlog参数。
            //再通过handler设置服务端socket(ServerSocketChannel)的处理事件的handler是记录日志logger
            //最后childhandler设置每一个连接到服务端的socket(socketchannel)的handler(childhandler),是创建一个EchoServerHandler类去处理。(利用channelhandler我们可以完成功能定制)
            //channelpipeline负责管理和执行channelhandler,可以向channelpipeline中add添加channelhandler
            //(注意ServerBootstrap部分方法来自父类)
            b.group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class)
                    .option(ChannelOption.SO_BACKLOG, 100)
                    .handler(new LoggingHandler(LogLevel.INFO))
                    .childHandler(new ChannelInitializer<SocketChannel>() 
                        public void initChannel(SocketChannel ch) throws Exception 
                            //abstractBoostStrap中的Handler是个工厂类,它为每个新接入的客户端都创建一个新的Handler
                            //下面代码每新连接一个socket,都会创建一个EchoServerHandler
                            System.out.println("hello");
                            ch.pipeline().addLast(new EchoServerHandler());
                            //ch.pipeline().addLast(new LoggingHandler(LogLevel.INFO));
                        
                    );
            //绑定端口,netty中所有IO操作都是异步的,它会立即返回,但不能保证完成操作
            ChannelFuture f = b.bind(port).sync();
            System.out.println("bind....");
            f.channel().closeFuture().sync();
        catch(Exception e)
            e.printStackTrace();
        finally 
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        
    


    public static void main(String[] args) throws Exception 
        int port;
        if(args.length > 0)
            port = Integer.parseInt(args[0]);
        else
            port = 10000;
        
        new EchoServer(port).run();
    

上面仅仅一行代码就完成了很多参数的设置,为我们编程简化了很多。

ServerBootstrap创建时序图:

图片非原创

补充工厂模式:
工厂模式利用java的反射,参数为Class<>,我们传递参数为.class(构建对象的类型)而不是类对象实例,然后根据需要在方法里构建相应的对象,这也延迟了对象的创建,简单来说就是我们需要什么类型的物品,告诉工厂,工厂产生给我们相应的实体。

backlog等参数的含义

以上是关于学习 java netty -- ServerBootstrap的主要内容,如果未能解决你的问题,请参考以下文章

学习 java netty -- ServerBootstrap

从Netty到EPollSelectorImpl学习Java NIO

刚学习netty和java,不会用,但现在急需,您有没有用netty编写的服务器和客户端的例子,要能互相发送包

Netty学习2(学习笔记)

Java BIONIO与AIO的介绍(学习过程)

netty学习总结