Netty--核心模块组件 BootStrap ServerBootstrap(一)

BootStrap ServerBootStarp

BootStarp 意思是引导,一个Netty 应用通常由一个BootStarp 开始,主要作用是配置整个Netty程序,串联各个组件,Netty中BootStarp 类是客户端程序的启动引导类,ServerBootStarp 是服务端启动引导类。

常见方法

  1. public ServerBootstrap group(EventLoopGroup parentGroup, EventLoopGroup childGroup),该方法用于Netty服务端,用来设置两个NioEventLoopGroup
  2. public B group(EventLoopGroup group) 该方法用于客户端,用来设置一个NioEventLoopGroup
  3. public B channel(Class<? extends C> channelClass) 该方法用来设置一个服务器端的通道实现 默认NioServerSocketChannel
  4. public B option(ChannelOption option, T value) 用来给 ServerChannel 添加配置
  5. public ServerBootstrap childOption(ChannelOption childOption, T value),用来给接收到的通道添加配置
  6. public ServerBootstrap childHandler(ChannelHandler childHandler),该方法用来设置业务处理类(自定义的Handler)
  7. public ChannelFuture bind(int inetPort) ,该方法用于服务器端,用来设置占用的端口号
  8. public ChannelFuture connect(String inetHost, int inetPort) ,该方法用于客户端,用来连接服务器端

一般在启动一个服务器端的ServerBootStarp时,我们需要指定这几个参数

public static void main(String[] args) throws InterruptedException {
        // BossGroup --- Channel --> WorkerGroup
        // BossGroup 只处理客户端的连接事件
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        // WorkerGroup -> NioEventLoopGroup -> NioEventLoop -> Pipeline
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        try {
            ServerBootstrap bootstrap = new ServerBootstrap();
            bootstrap.group(bossGroup, workerGroup)
                    // NioServerSocketChannel 这个是BossGroup 和 WorkerGroup之间的通道
                    .channel(NioServerSocketChannel.class)
                    // SocketChannel 这个是客户端和服务器端之间的通道 以及添加对这个通道产生数据的handler
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel socketChannel) throws Exception {
                        	// 添加我们自定义的Handler
                            socketChannel.pipeline().addLast(new NettyServerHandler());
                        }
                    });

            System.out.println("服务器 ok");
            // 服务器端绑定监测的端口 并启动Netty服务器端
            ChannelFuture channelFuture = bootstrap.bind(6668).sync();

            channelFuture.channel().closeFuture().sync();
        } finally {
        	// 优雅的关闭两个线程池
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }
bootstrap.group(bossGroup, workerGroup)
ServerBootStarp 类定义的几个常量 都添加了volatile 关键字 保证了线程之间的可见性

 private volatile EventLoopGroup childGroup;
 private volatile ChannelHandler childHandler;


public ServerBootstrap group(EventLoopGroup parentGroup, EventLoopGroup childGroup) {
        /**
        调用父类AbstractBootstrap构造 指定BossGroup
		*/
        super.group(parentGroup);
        ObjectUtil.checkNotNull(childGroup, "childGroup");
        if (this.childGroup != null) {
            throw new IllegalStateException("childGroup set already");
        }
        // 指定WorkerGroup 
        this.childGroup = childGroup;
        return this;
    }
bootstrap.channel(NioServerSocketChannel.class)

// ChannelFactory通过反射的方式创建BossGroup 与 WorkerGroup 之间的通道。在这里我们指定反射创建的通道类型

public B channel(Class<? extends C> channelClass) {
        return channelFactory(new ReflectiveChannelFactory<C>(
                ObjectUtil.checkNotNull(channelClass, "channelClass")
        ));
    }

// 反射Channel工厂 
public ReflectiveChannelFactory(Class<? extends T> clazz) {
        ObjectUtil.checkNotNull(clazz, "clazz");
        try {
        // 得到要创建通道的构造方法
            this.constructor = clazz.getConstructor();
        } catch (NoSuchMethodException e) {
            throw new IllegalArgumentException("Class " + StringUtil.simpleClassName(clazz) +
                    " does not have a public non-arg constructor", e);
        }
    }
   
    @Deprecated
    public B channelFactory(ChannelFactory<? extends C> channelFactory) {
        ObjectUtil.checkNotNull(channelFactory, "channelFactory");
        if (this.channelFactory != null) {
            throw new IllegalStateException("channelFactory set already");
        }
		// 指定了工厂对象
        this.channelFactory = channelFactory;
        return self();
    }

bootstrap.bind(6668).sync()

这个方法在ServerBootStarp 的父类 AbstractBootstarp
启动Netty服务器端并且绑定要监听的端口号

	
	public ChannelFuture bind(InetAddress inetHost, int inetPort) {
        return bind(new InetSocketAddress(inetHost, inetPort));
    }

    
    public ChannelFuture bind(SocketAddress localAddress) {
       /**
       // 判断BossGroup 是否为空
       public B validate() {
        if (group == null) {
            throw new IllegalStateException("group not set");
        }
	  // 判断创建channel的工厂为空 
        if (channelFactory == null) {
            throw new IllegalStateException("channel or channelFactory not set");
        }
        return self();
       
    	}
       */
        validate();
        // 最终会调用这个方法启动Netty服务器端
        return doBind(ObjectUtil.checkNotNull(localAddress, "localAddress"));
    }
doBind(final SocketAddress localAddress)
 private ChannelFuture doBind(final SocketAddress localAddress) {
 		// 初始化 NIOServerSocketChannel
        final ChannelFuture regFuture = initAndRegister();
        final Channel channel = regFuture.channel();
        if (regFuture.cause() != null) {
            return regFuture;
        }

        if (regFuture.isDone()) {
            // At this point we know that the registration was complete and successful.
            ChannelPromise promise = channel.newPromise();
            doBind0(regFuture, channel, localAddress, promise);
            return promise;
        } else {
            // Registration future is almost always fulfilled already, but just in case it's not.
            final PendingRegistrationPromise promise = new PendingRegistrationPromise(channel);
            regFuture.addListener(new ChannelFutureListener() {
                @Override
                public void operationComplete(ChannelFuture future) throws Exception {
                    Throwable cause = future.cause();
                    if (cause != null) {
                        // Registration on the EventLoop failed so fail the ChannelPromise directly to not cause an
                        // IllegalStateException once we try to access the EventLoop of the Channel.
                        promise.setFailure(cause);
                    } else {
                        // Registration was successful, so set the correct executor to use.
                        // See https://github.com/netty/netty/issues/2586
                        promise.registered();

                        doBind0(regFuture, channel, localAddress, promise);
                    }
                }
            });
            return promise;
        }
    }
initAndRegister()
final ChannelFuture initAndRegister() {
        Channel channel = null;
        try {
        // 通过ReflectiveChannelFactory 我们前面指定要创建的NIOServerSocketChannel类型的通道
            channel = channelFactory.newChannel();
            
		跟踪源码发现 该方法创建了NIOServerSocketChannel AbstractChannel 以及 AbstractNioChannel
		
		NIOServerSocketChannel 		
		1、初始化了 SelectorProvider 多路复用I/O 的系统实现
		2、初始化NioServerSocketChannelConfig 用于对外展示一些配置
		
		AbstractChannel 
		1、创建默认的ChannelId 
		2、创建了一个NioMessageUnsafe 用来操作消息
		3、创建了DefaultChannelPipeline 管道 用于管理handler
		
		AbstractNioChannel
		1、指定SelectableChannel 的实现类 ServerSocketChannelImpl
		2、设置为非阻塞模型

		 init(channel);
	init方法这是个抽象方法(AbstractServerBootstarp类定义的) 但是是有ServerBootStarp实现的
		将这个方法在下面单独拿出来说

        } catch (Throwable t) {
            if (channel != null) {
                // channel can be null if newChannel crashed (eg SocketException("too many open files"))
                channel.unsafe().closeForcibly();
                // as the Channel is not registered yet we need to force the usage of the GlobalEventExecutor
                return new DefaultChannelPromise(channel, GlobalEventExecutor.INSTANCE).setFailure(t);
            }
            // as the Channel is not registered yet we need to force the usage of the GlobalEventExecutor
            return new DefaultChannelPromise(new FailedChannel(), GlobalEventExecutor.INSTANCE).setFailure(t);
        }

        ChannelFuture regFuture = config().group().register(channel);
        if (regFuture.cause() != null) {
            if (channel.isRegistered()) {
                channel.close();
            } else {
                channel.unsafe().closeForcibly();
            }
        }
        return regFuture;
    }
init(Channel channel)
void init(Channel channel) {
		// 设置NIOServerSocketChannel 的tcp属性
        setChannelOptions(channel, options0().entrySet().toArray(newOptionArray(0)), logger);
        setAttributes(channel, attrs0().entrySet().toArray(newAttrArray(0)));
		
		// 将在AbstractBootstarp初始化的DefaultChannelPipeline
        ChannelPipeline p = channel.pipeline();

        final EventLoopGroup currentChildGroup = childGroup;
        final ChannelHandler currentChildHandler = childHandler;
        final Entry<ChannelOption<?>, Object>[] currentChildOptions =
                childOptions.entrySet().toArray(newOptionArray(0));
        final Entry<AttributeKey<?>, Object>[] currentChildAttrs = childAttrs.entrySet().toArray(newAttrArray(0));

		// 将channel和pipeline进行关联
		
		1、初始化了DefaultChannelContext 将handler进行了封装	
		
        p.addLast(new ChannelInitializer<Channel>() {
            @Override
            public void initChannel(final Channel ch) {
                final ChannelPipeline pipeline = ch.pipeline();
                ChannelHandler handler = config.handler();
                if (handler != null) {
                    pipeline.addLast(handler);
                }

                ch.eventLoop().execute(new Runnable() {
                    @Override
                    public void run() {
                        pipeline.addLast(new ServerBootstrapAcceptor(
                                ch, currentChildGroup, currentChildHandler, currentChildOptions, currentChildAttrs));
                    }
                });
            }
        });
    }
class DefaultChannelPipeline.addLast()
/**
	因为是一个双向链表 所以做了同步处理
*/
 public final ChannelPipeline addLast(EventExecutorGroup group, String name, ChannelHandler handler) {
        final AbstractChannelHandlerContext newCtx;
        synchronized (this) {
            checkMultiplicity(handler);
			// 将我们自定义的handler 封装为DefaultChannelContext
            newCtx = newContext(group, filterName(name, handler), handler);
			
			// 添加到队列中去 这里 addLast/addFirst 都是添加到tail的前面或者head的后面 因为在初始化DefaultChannelContext 的时候初始化了这两个常量 为了是处理进站和出站的消息。
			
			这里很清楚的看到我们添加的handler的都是添加到了tail的前面
			/**
				private void addLast0(AbstractChannelHandlerContext newCtx) {
			        AbstractChannelHandlerContext prev = tail.prev;
			        newCtx.prev = prev;
			        newCtx.next = tail;
			        prev.next = newCtx;
			        tail.prev = newCtx;
			    }
			*/
            addLast0(newCtx);

            // If the registered is false it means that the channel was not registered on an eventLoop yet.
            // In this case we add the context to the pipeline and add a task that will call
            // ChannelHandler.handlerAdded(...) once the channel is registered.
            if (!registered) {
                newCtx.setAddPending();
                callHandlerCallbackLater(newCtx, true);
                return this;
            }

            EventExecutor executor = newCtx.executor();
            if (!executor.inEventLoop()) {
                callHandlerAddedInEventLoop(newCtx, executor);
                return this;
            }
        }
        callHandlerAdded0(newCtx);
        return this;
    }
  1. addLast()方法在DefaultChannelPipeline类中
  2. 首先检查这个handler是否符合标准
  3. 创建一个DefaultChannelHandllerContext 对象封装handler。这个DefaultChannelHandllerContext 对象是channel 和 pipeline 之间的关联。这个对象包含了handler 和 pipeline 而通过pipeline又可以找到相对应的channel。
  4. 最后将DefaultChannelHandlerContext加入到双向链表中
  5. 最后,同步或异步或者晚点调用callHandlerAdded()方法
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值