/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package io.netty.bootstrap; import io.netty.channel.Channel; import io.netty.channel.ChannelException; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelFutureListener; import io.netty.channel.ChannelHandler; import io.netty.channel.ChannelOption; import io.netty.channel.ChannelPromise; import io.netty.channel.DefaultChannelPromise; import io.netty.channel.EventLoop; import io.netty.channel.EventLoopGroup; import io.netty.util.AttributeKey; import io.netty.util.concurrent.GlobalEventExecutor; import io.netty.util.internal.StringUtil; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.SocketAddress; import java.util.LinkedHashMap; import java.util.Map; /** * {@link AbstractBootstrap} is a helper class that makes it easy to bootstrap a {@link Channel}. It support * method-chaining to provide an easy way to configure the {@link AbstractBootstrap}. * * <p>When not used in a {@link ServerBootstrap} context, the {@link #bind()} methods are useful for connectionless * transports such as datagram (UDP).</p> */ /** */ public abstract class AbstractBootstrap<B extends AbstractBootstrap<B, C>, C extends Channel> implements Cloneable { private volatile EventLoopGroup group; //该eventloopgroup主要用于处理子类ServerBootstrap accpet 客户端的连接 private volatile ChannelFactory<? extends C> channelFactory; //创建Channel工厂类 private volatile SocketAddress localAddress; //端口地址 //设定Channel相关配置参数的集合 private final Map<ChannelOption<?>, Object> options = new LinkedHashMap<ChannelOption<?>, Object>(); private final Map<AttributeKey<?>, Object> attrs = new LinkedHashMap<AttributeKey<?>, Object>(); private volatile ChannelHandler handler; //TODO:要理解这个父类handler的作用 /** * 构造函数 */ AbstractBootstrap() { // Disallow extending from a different package. } //核心构造函数 AbstractBootstrap(AbstractBootstrap<B, C> bootstrap) { group = bootstrap.group; channelFactory = bootstrap.channelFactory; handler = bootstrap.handler; localAddress = bootstrap.localAddress; synchronized (bootstrap.options) { options.putAll(bootstrap.options); } synchronized (bootstrap.attrs) { attrs.putAll(bootstrap.attrs); } } /** * The {@link EventLoopGroup} which is used to handle all the events for the to-be-creates * {@link Channel} */ //设置group属性 @SuppressWarnings("unchecked") public B group(EventLoopGroup group) { if (group == null) { throw new NullPointerException("group"); } if (this.group != null) { throw new IllegalStateException("group set already"); } this.group = group; return (B) this; } /** * The {@link Class} which is used to create {@link Channel} instances from. * You either use this or {@link #channelFactory(ChannelFactory)} if your * {@link Channel} implementation has no no-args constructor. */ //设置channelClass,然后通过静态内部类BootstrapChannelFactory来产生hannel public B channel(Class<? extends C> channelClass) { if (channelClass == null) { throw new NullPointerException("channelClass"); } /** * 1.BootstrapChannelFactory是一个静态内部类,对传入的Channel的class进行封装 * 2.调用channelFactory()方法,设置属性channelFactory * 本质就是:this.channelFactory = new BootstrapChannelFactory(channelClass) */ return channelFactory(new BootstrapChannelFactory<C>(channelClass)); } /** * {@link ChannelFactory} which is used to create {@link Channel} instances from * when calling {@link #bind()}. This method is usually only used if {@link #channel(Class)} * is not working for you because of some more complex needs. If your {@link Channel} implementation * has a no-args constructor, its highly recommend to just use {@link #channel(Class)} for * simplify your code. */ /** * 给this.channelFactory属性赋值 */ @SuppressWarnings("unchecked") public B channelFactory(ChannelFactory<? extends C> channelFactory) { if (channelFactory == null) { throw new NullPointerException("channelFactory"); } if (this.channelFactory != null) { throw new IllegalStateException("channelFactory set already"); } this.channelFactory = channelFactory; return (B) this; } /** * The {@link SocketAddress} which is used to bind the local "end" to. * */ @SuppressWarnings("unchecked") public B localAddress(SocketAddress localAddress) { this.localAddress = localAddress; return (B) this; } /** * @see {@link #localAddress(SocketAddress)} */ public B localAddress(int inetPort) { return localAddress(new InetSocketAddress(inetPort)); } /** * @see {@link #localAddress(SocketAddress)} */ public B localAddress(String inetHost, int inetPort) { return localAddress(new InetSocketAddress(inetHost, inetPort)); } /** * @see {@link #localAddress(SocketAddress)} */ public B localAddress(InetAddress inetHost, int inetPort) { return localAddress(new InetSocketAddress(inetHost, inetPort)); } /** * Allow to specify a {@link ChannelOption} which is used for the {@link Channel} instances once they got * created. Use a value of {@code null} to remove a previous set {@link ChannelOption}. */ /** * 对this.options进行负值。 * 如果对应的key的option的value为null,则从options删除该属性 * 否则直接put */ @SuppressWarnings("unchecked") public <T> B option(ChannelOption<T> option, T value) { if (option == null) { throw new NullPointerException("option"); } if (value == null) { synchronized (options) { options.remove(option); } } else { synchronized (options) { options.put(option, value); } } return (B) this; } /** * Allow to specify an initial attribute of the newly created {@link Channel}. If the {@code value} is * {@code null}, the attribute of the specified {@code key} is removed. */ /* 对this.attrs进行负值。 * 如果对应的key的value为null,则从attrs删除该属性 * 否则直接put */ public <T> B attr(AttributeKey<T> key, T value) { if (key == null) { throw new NullPointerException("key"); } if (value == null) { synchronized (attrs) { attrs.remove(key); } } else { synchronized (attrs) { attrs.put(key, value); } } @SuppressWarnings("unchecked") B b = (B) this; return b; } /** * Validate all the parameters. Sub-classes may override this, but should * call the super method in that case. */ //对group和channelFactory进行检查,是否为null @SuppressWarnings("unchecked") public B validate() { if (group == null) { throw new IllegalStateException("group not set"); } if (channelFactory == null) { throw new IllegalStateException("factory not set"); } return (B) this; } /** * Returns a deep clone of this bootstrap which has the identical configuration. This method is useful when making * multiple {@link Channel}s with similar settings. Please note that this method does not clone the * {@link EventLoopGroup} deeply but shallowly, making the group a shared resource. */ @Override @SuppressWarnings("CloneDoesntDeclareCloneNotSupportedException") public abstract B clone(); /** * Create a new {@link Channel} and register it with an {@link EventLoop}. */ public ChannelFuture register() { validate(); return initAndRegister(); } /** * Create a new {@link Channel} and bind it. */ public ChannelFuture bind() { //检查group和channelFactory属性是否为null validate(); SocketAddress localAddress = this.localAddress; if (localAddress == null) { throw new IllegalStateException("localAddress not set"); } return doBind(localAddress); } /** * Create a new {@link Channel} and bind it. */ public ChannelFuture bind(int inetPort) { return bind(new InetSocketAddress(inetPort)); } /** * Create a new {@link Channel} and bind it. */ public ChannelFuture bind(String inetHost, int inetPort) { return bind(new InetSocketAddress(inetHost, inetPort)); } /** * Create a new {@link Channel} and bind it. */ public ChannelFuture bind(InetAddress inetHost, int inetPort) { return bind(new InetSocketAddress(inetHost, inetPort)); } //绑定监听端口的对外接口 /** * Create a new {@link Channel} and bind it. */ public ChannelFuture bind(SocketAddress localAddress) { validate(); if (localAddress == null) { throw new NullPointerException("localAddress"); } return doBind(localAddress); } //真正的绑定监听端口的方法 private ChannelFuture doBind(final SocketAddress localAddress) { //1.初始化channel并将初始化好的channel注册到事件循环 final ChannelFuture regFuture = initAndRegister(); final Channel channel = regFuture.channel(); if (regFuture.cause() != null) { return regFuture; } final ChannelPromise promise; /** * 2.判断初始化且注册任务是否已经完成,如果已经完成,则调用bind端口方法 * 注意这里regFuture.isDone()方法,返回ture,只是标示任务是否已经完成,完成的情况可能有: * 1.正常终止、2.异常、3.取消 */ if (regFuture.isDone()) { promise = channel.newPromise(); doBind0(regFuture, channel, localAddress, promise); } else { // Registration future is almost always fulfilled already, but just in case it's not. promise = new DefaultChannelPromise(channel, GlobalEventExecutor.INSTANCE); regFuture.addListener(new ChannelFutureListener() { @Override public void operationComplete(ChannelFuture future) throws Exception { doBind0(regFuture, channel, localAddress, promise); } }); } return promise; } final ChannelFuture initAndRegister() { //1.通过反射创建netty的channel对象,netty的channel对象是对sun提供的原生态的NIO SelectableChannel的一个封装 /** * 在这里因为本质this.channelFactory = new BootstrapChannelFactory(channelClass) * 同时BootstrapChannelFactory实例的newChannel()方法本质是,通过反射调用传入的参数 * channelClass来创建一个channel实例, * NioServer端一般使用的是NioServerSocketChannel * NioClient端使用的NioSocketChannel */ final Channel channel = channelFactory().newChannel(); try { //2.初始化Channel实例:对channel实例进行相关参数设置。这里调用的是对应子类的实现 init(channel); } catch (Throwable t) { channel.unsafe().closeForcibly(); return channel.newFailedFuture(t); } /** * 3.将Channel注册到事件循环组中: * 注意AbstractBootstrap和Bootstrap、ServerBootstrap这两个父子类,父类AbstractBootstrap有一个属性名是group的EventLoopGroup, * 子类ServerBootstrap有一个属性名是childGroup的EventLoopGroup, * 子类Bootstrap直接继承AbstractBootstrap,没有额外的EventLoopGroup属性. * TODO:彻底理解group和childGroup的职责 * 注意这ServerBootstrap两个EventLoopGroup的职责: * group:主要是Server对accpet事件的处理 * childGroup:主要是Server对write and read事件的处理 */ ChannelFuture regFuture = group().register(channel); //4.如果注册失败,regFuture.cause会返回失败的异常对象 //如果注册出现异常,并channel已经注册,那么关闭。如果没有注册,那么强行关闭 //TODO:这里要弄清楚channel.close()和channel.unsafe().closeForcibly()区别 ? if (regFuture.cause() != null) { if (channel.isRegistered()) { channel.close(); } else { channel.unsafe().closeForcibly(); } } // If we are here and the promise is not failed, it's one of the following cases: // 1) If we attempted registration from the event loop, the registration has been completed at this point. // i.e. It's safe to attempt bind() or connect() now beause the channel has been registered. // 2) If we attempted registration from the other thread, the registration request has been successfully // added to the event loop's task queue for later execution. // i.e. It's safe to attempt bind() or connect() now: // because bind() or connect() will be executed *after* the scheduled registration task is executed // because register(), bind(), and connect() are all bound to the same thread. return regFuture; } //子类ServerBootstrap实现该方法 abstract void init(Channel channel) throws Exception; private static void doBind0( final ChannelFuture regFuture, final Channel channel, final SocketAddress localAddress, final ChannelPromise promise) { // This method is invoked before channelRegistered() is triggered. Give user handlers a chance to set up // the pipeline in its channelRegistered() implementation. //判断注册事件是否成功,如果注册成功,则把bind任务丢到任务队列 channel.eventLoop().execute(new Runnable() { @Override public void run() { //channel注册到eventloop成功后,才开始调用Channel的bind方法 if (regFuture.isSuccess()) { //调用Channel的bind方法 channel.bind(localAddress, promise).addListener(ChannelFutureListener.CLOSE_ON_FAILURE); } else { promise.setFailure(regFuture.cause()); } } }); } /** * the {@link ChannelHandler} to use for serving the requests. */ @SuppressWarnings("unchecked") public B handler(ChannelHandler handler) { if (handler == null) { throw new NullPointerException("handler"); } this.handler = handler; return (B) this; } final SocketAddress localAddress() { return localAddress; } final ChannelFactory<? extends C> channelFactory() { return channelFactory; } final ChannelHandler handler() { return handler; } /** * Return the configured {@link EventLoopGroup} or {@code null} if non is configured yet. */ public final EventLoopGroup group() { return group; } final Map<ChannelOption<?>, Object> options() { return options; } final Map<AttributeKey<?>, Object> attrs() { return attrs; } @Override public String toString() { StringBuilder buf = new StringBuilder(); buf.append(StringUtil.simpleClassName(this)); buf.append('('); if (group != null) { buf.append("group: "); buf.append(StringUtil.simpleClassName(group)); buf.append(", "); } if (channelFactory != null) { buf.append("channelFactory: "); buf.append(channelFactory); buf.append(", "); } if (localAddress != null) { buf.append("localAddress: "); buf.append(localAddress); buf.append(", "); } synchronized (options) { if (!options.isEmpty()) { buf.append("options: "); buf.append(options); buf.append(", "); } } synchronized (attrs) { if (!attrs.isEmpty()) { buf.append("attrs: "); buf.append(attrs); buf.append(", "); } } if (handler != null) { buf.append("handler: "); buf.append(handler); buf.append(", "); } if (buf.charAt(buf.length() - 1) == '(') { buf.append(')'); } else { buf.setCharAt(buf.length() - 2, ')'); buf.setLength(buf.length() - 1); } return buf.toString(); } private static final class BootstrapChannelFactory<T extends Channel> implements ChannelFactory<T> { private final Class<? extends T> clazz; BootstrapChannelFactory(Class<? extends T> clazz) { this.clazz = clazz; } @Override public T newChannel() { try { return clazz.newInstance(); } catch (Throwable t) { throw new ChannelException("Unable to create Channel from class " + clazz, t); } } @Override public String toString() { return StringUtil.simpleClassName(clazz) + ".class"; } } }