学习 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等参数的含义

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-11-05 13:30:27

学习 java netty (二) -- ServerBootstrap的相关文章

学习 java netty (三) -- Channel

学习 java netty (三) – Channel 前言:netty封装的channel,看一下官网的定义 A nexus to a network socket or a component which is capable of I/O operations such as read, write, connect, and bind. 可以I/O操作(如读,写,连接和绑定)的连网套接字或组件 A channel provides a user: All I/O operations a

学习 java netty (一) -- java nio

前言:最近在研究java netty这个网络框架,第一篇先介绍java的nio. java nio在jdk1.4引入,其实也算比较早的了,主要引入非阻塞io和io多路复用.内部基于reactor模式. nio核心: - buffer - channel - selector buffer: 类似网络编程中的缓冲区,有 ByteBuffer 字节 CharBuffer 字符 IntBuffer DoubleBuffer- 常用的有ByteBuffer和CharBuffer java nio buf

从零开始学习Java多线程(二)

前面已经简单介绍进程和线程,为后续学习做铺垫.本文讨论多线程传参,Java多线程异常处理机制. 1. 多线程的参数传递 在传统开发过程中,我们习惯在调用函数时,将所需的参数传入其中,通过函数内部逻辑处理返回结果,大多情况下,整个过程均是由一条线程执行,排除运行不必要的的偶发性,似乎并不会出现意料之外的结果.而在多线程环境下,在使用线程时需要对线程进行一些必要的初始化,线程对这些数据进行处理后返回结果,由于线程的运行和结束并不可控,线程传参变得复杂起来,本文就以上问题介绍三种常用的传递参数方式.

java学习之数组(二)

学编程吧java数组学习(二)发布了,欢迎大家通过xuebiancheng8.com来访问. 下面接着来分析数组,前面分析了什么是数组,为什么要用数组,下面来分析下如何使用数组 数组和其他数据类型一样,使用前要先定义.如下 int a[];这样就声明了一个数组 a = new int[10];然后为这个数组申请10个大小的空间 a[0] = 1; a[1] = 2; ....等等来为数组 赋值,为数组赋值完成后就可以通过下标来访问数组 当然数组在定义的时候也可以讲上面操作合并即 int a []

【Java学习笔记之二十六】深入理解Java匿名内部类

在[Java学习笔记之二十五]初步认知Java内部类中对匿名内部类做了一个简单的介绍,但是内部类还存在很多其他细节问题,所以就衍生出这篇博客.在这篇博客中你可以了解到匿名内部类的使用.匿名内部类要注意的事项.如何初始化匿名内部类.匿名内部类使用的形参为何要为final. 一.使用匿名内部类内部类 匿名内部类由于没有名字,所以它的创建方式有点儿奇怪.创建格式如下: new 父类构造器(参数列表)|实现接口() { //匿名内部类的类体部分 } 在这里我们看到使用匿名内部类我们必须要继承一个父类或者

【Python】Java程序员学习Python(二)— 开发环境搭建

巧妇难为无米之炊,我最爱的还是鸡蛋羹,因为我和鸡蛋羹有段不能说的秘密. 不管学啥,都要有环境,对于程序员来说搭建个开发环境应该不是什么难题.按顺序一步步来就可以,我也只是记录我的安装过程,你也可以滴. 一.准备Java环境 我已经说过了,其实我是一个Java程序员,所以学习过程中会有很多Java相关的内容和对比.先介绍下我的基本情况 jdk1.8 eclipse即可,版本最新的 怎么安装java,配置环境变量什么的,我都不会再说了,我这不是小白教程,我相信具备一定的能力. 二.准备Python环

Java集合源码学习笔记(二)ArrayList分析

Java集合源码学习笔记(二)ArrayList分析 >>关于ArrayList ArrayList直接继承AbstractList,实现了List. RandomAccess.Cloneable.Serializable接口,为什么叫"ArrayList",因为ArrayList内部是用一个数组存储元素值,相当于一个可变大小的数组,也就是动态数组. (1)继承和实现继承了AbstractList,实现了List:ArrayList是一个数组队列,提供了相关的添加.删除.修

JAVA的反射机制学习笔记(二)

上次写JAVA的反射机制学习笔记(一)的时候,还是7月22号,这些天就瞎忙活了,自己的步伐完全被打乱了~不能继续被动下去,得重新找到自己的节奏. 4.获取类的Constructor 通过反射机制得到某个类的构造器,然后调用该构造器创建该类的一个实例 Class<T>类提供了几个方法获取类的构造器. public Constructor<T> getConstructor(Class<?>... parameterTypes) 返回一个 Constructor 对象,它反

java基础学习总结——线程(二)

永不放弃,一切皆有可能!!! 只为成功找方法,不为失败找借口! java基础学习总结——线程(二) 一.线程的优先级别 线程优先级别的使用范例: 1 package cn.galc.test; 2 3 public class TestThread6 { 4 public static void main(String args[]) { 5 MyThread4 t4 = new MyThread4(); 6 MyThread5 t5 = new MyThread5(); 7 Thread t1