/*
* 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";
}
}
}