研究源码的前提建立在:
1、首先我们得知道怎么用这个框架
2、其次以用法为入口进行源码研究
ok,我们首先找到入口函数,官方文档有详细介绍,官方地址:点击打开链接,官方文档有提供的详细例子:
public static void main(String[] args) throws Exception {
String host = args[0];
int port = Integer.parseInt(args[1]);
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
Bootstrap b = new Bootstrap(); // (1)
b.group(workerGroup); // (2)
b.channel(NioSocketChannel.class); // (3)
b.option(ChannelOption.SO_KEEPALIVE, true); // (4)
b.handler(new ChannelInitializer() {
@Override
public void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(new TimeClientHandler());
}
});
// Start the client.
ChannelFuture f = b.connect(host, port).sync(); // (5)
// Wait until the connection is closed.
f.channel().closeFuture().sync();
} finally {
workerGroup.shutdownGracefully();
}
}
这就是官方提供的一个简单的客户端demo,大体上可以了解到,创建客户端必须先创建Bootstrap(英文意思是引导的意思),将
EventLoopGroup的创建绑定到Bootstrap,暂且叫他事件群管理,接下来绑定通道b.channel(NioSocketChannel.class),然后b.option(ChannelOption.SO_KEEPALIVE, true);开始设置socket属性,再初始化管道设置,最后连接。
现在我们点进
connect
实现链接的第一步
publicChannelFuture connect(SocketAddress remoteAddress) {
if (remoteAddress == null) {
throw newNullPointerException("remoteAddress");
}
/**
* 判断有没有设置handler,没有抛异常程序结束
*/
validate();
returndoResolveAndConnect(remoteAddress, config.localAddress());
}
validate方法主要判断初始化的一些必要参数用户有没有设置 if (group == null) {
throw new IllegalStateException("group notset");
}
if (channelFactory == null) {
throw new IllegalStateException("channel orchannelFactory not set");
}
if (config.handler() == null) {
throw new IllegalStateException("handler notset");
}
继续走会进入
private ChannelFuture doResolveAndConnect(final SocketAddress remoteAddress, final SocketAddress localAddress) {
final ChannelFuture regFuture = initAndRegister();
final Channel channel = regFuture.channel();
if (regFuture.isDone()) {
if (!regFuture.isSuccess()) {
return regFuture;
}
return doResolveAndConnect0(channel, remoteAddress, localAddress, channel.newPromise());
} 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 {
// Directly obtain the cause and do a null check so we only need one volatile read in case of a
// failure.
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();
doResolveAndConnect0(channel, remoteAddress, localAddress, promise);
}
}
});
return promise;
}
}
跟进initAndRegister这个方法注册方法很重要, 连接的时候注册初始化
final ChannelFuture initAndRegister() { Channel channel = null; try {
channelFactory
//利用channelFactory创建通道channel ,也就是上面所传入的NioSocketChannel.class
channel = channelFactory.newChannel();
//开始初始化channel跟进
init(channel);
} 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);
}
/**
* 注册通道
*/
ChannelFuture regFuture = config().group().register(channel);
if (regFuture.cause() != null) {
if (channel.isRegistered()) {
channel.close();
} else {
channel.unsafe().closeForcibly();
}
}
return regFuture;
}
//进入init()方法继续
void init(Channel channel) throws Exception {
/**
* 把初始化handler句柄加入管道里
* 用默认的DefaultChannelPipeline管道对象
*/
ChannelPipeline p = channel.pipeline();
p.addLast(config.handler());
final Map, Object> options = options0();
//把属性的一些设置(如前面设置的 bootStrap.option(ChannelOption.SO_KEEPALIVE, true);
bootStrap.option(ChannelOption.TCP_NODELAY, true);)设置到configuration里面
synchronized (options) {
setChannelOptions(channel, options);
}
/**
attrs属性也设置到config配置里面
*/
final Map, Object> attrs = attrs0();
synchronized (attrs) {
for (Entry, Object> e: attrs.entrySet()) {
channel.attr((AttributeKey
果然还是有图更具体,数据通过这个管道处理器一级一级的去处理数据,打个比方,我与服务端定一个自己的数据协议,那么socket传给我们的是byte数据最终我们会必须得转换为我们需要的类,这时候我们自定义一个编码器(通过一系列封装最终发送服务器所需要的数据),一个解码器(通过一系列解析数据,最终拼接成我们所需要的数据)即可。我们接着继续往下走进addLast,既然知道channel是NioSocketChannel了,那么找到
protected AbstractChannel(Channel parent) {
.
pipeline = newChannelPipeline();
}
protected DefaultChannelPipeline newChannelPipeline() {
return new DefaultChannelPipeline(this);
}那么管道一目了然了默认就是DefaultChannelPipeline,进入
public final ChannelPipeline addLast(EventExecutorGroup group, String name, ChannelHandler handler) {
final AbstractChannelHandlerContext newCtx;
synchronized (this) {
//检查handler是否合法
checkMultiplicity(handler);
//handler的包装类
newCtx = newContext(group, filterName(name, handler), handler);
//将newCtx 加入队列中
addLast0(newCtx);
//从上面我们看出init方法在注册方法前面所以此时registered=false
if (!registered) {
newCtx.setAddPending();
callHandlerCallbackLater(newCtx, true);
return this;
}
EventExecutor executor = newCtx.executor();
if (!executor.inEventLoop()) {
newCtx.setAddPending();
executor.execute(new Runnable() {
@Override
public void run() {
callHandlerAdded0(newCtx);
}
});
return this;
}
}
callHandlerAdded0(newCtx);
return this;
}
// 进入
private void callHandlerCallbackLater(AbstractChannelHandlerContext ctx, boolean added) {
assert !registered;
//第一次added肯定为true,那么task =PendingHandlerAddedTask(此类实现了runnble接口)
PendingHandlerCallback task = added ? new PendingHandlerAddedTask(ctx) : new PendingHandlerRemovedTask(ctx);
PendingHandlerCallback pending = pendingHandlerCallbackHead;
if (pending == null) {
pendingHandlerCallbackHead = task;
} else {
// Find the tail of the linked-list.
while (pending.next != null) {
pending = pending.next;
}
pending.next = task;
}
}
最后走callHandlerAdded0(newCtx)方法,进入瞧瞧是干什么的,麻蛋,类实在太多了,最终调用的是
private void callHandlerAdded0(final AbstractChannelHandlerContext ctx) {
try {
ctx.handler().handlerAdded(ctx);
ctx.setAddComplete();
}}那么我们找到handler的handlerAdded,也就是ChannelInitializer类的handlerAdded方法 public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
if (ctx.channel().isRegistered()) {
//最终调用我们的子类的抽象方法实现类
initChannel(ctx);
}
}
bootStrap.handler(new ChannelInitializer() {
@Override
public void initChannel(SocketChannel ch) throws Exception {
//加入我们自己的管道
ch.pipeline().addLast("encoder", new Encoder());
ch.pipeline().addLast("decoder", new Decoder());
ch.pipeline().addLast("handler",
new ClientHandler(NettyCore.this));
}
});
ChannelFuture regFuture = config().group().register(channel);
if (regFuture.cause() != null) {
if (channel.isRegistered()) {
channel.close();
} else {
channel.unsafe().closeForcibly();
}
}
public ChannelFuture register(Channel channel) {
return next().register(channel);
}
经过一系列调用,最终调用了NioEventLoop的register方法,这设计的就有点巧妙了,初始化NioEventLoopGroup的时候调用父 类的构造函数
protected MultithreadEventExecutorGroup(int nThreads, Executor executor,
EventExecutorChooserFactory chooserFactory, Object... args) {
if (nThreads <= 0) {
throw new IllegalArgumentException(String.format("nThreads: %d (expected: > 0)", nThreads));
}
/**
* 传入的线程池为空就采用默认的
*/
if (executor == null) {
executor = new ThreadPerTaskExecutor(newDefaultThreadFactory());
}
//根据线程的数量创建多个EventExecutor,也就是newChild方法返回的NioEventLoop(每个NioEventLoop都持有相同的线程池,持有不同的队列)
children = new EventExecutor[nThreads];
for (int i = 0; i < nThreads; i ++) {
boolean success = false;
try {
children[i] = newChild(executor, args);
success = true;
} catch (Exception e) {
// TODO: Think about if this is a good exception type
throw new IllegalStateException("failed to create a child event loop", e);
} finally {
if (!success) {
for (int j = 0; j < i; j ++) {
children[j].shutdownGracefully();
}
for (int j = 0; j < i; j ++) {
EventExecutor e = children[j];
try {
while (!e.isTerminated()) {
e.awaitTermination(Integer.MAX_VALUE, TimeUnit.SECONDS);
}
} catch (InterruptedException interrupted) {
// Let the caller handle the interruption.
Thread.currentThread().interrupt();
break;
}
}
}
}
}
//创建NioEventLoop的选择器,每次重新注册的时候,根据规则选取一个NioEventLoop
chooser = chooserFactory.newChooser(children);
//添加回调
final FutureListener
chooser
是怎么样的呢
private static final class GenericEventExecutorChooser implements EventExecutorChooser {
private final AtomicInteger idx = new AtomicInteger();
private final EventExecutor[] executors;
GenericEventExecutorChooser(EventExecutor[] executors) {
this.executors = executors;
}
//每次返回随机集合里面的NioEventLoop
public EventExecutor next() {
return executors[Math.abs(idx.getAndIncrement() % executors.length)];
}
}
}
public ChannelFuture register(Channel channel) {
return register(new DefaultChannelPromise(channel, this));
}
public ChannelFuture register(final ChannelPromise promise) {
ObjectUtil.checkNotNull(promise, "promise");
最后又转到unsafe去注册,妈的,想死!
promise.channel().unsafe().register(this, promise);
return promise;
}
最后终于在 NioSocketChannel的内部类 NioSocketChannelUnsafe里找到注册方法
/**
* 注册ChannelPromise
*/
@Override
public final void register(EventLoop eventLoop, final ChannelPromise promise) {
//进行各方面的检测
if (eventLoop == null) {
throw new NullPointerException("eventLoop");
}
//不能重复注册
if (isRegistered()) {
promise.setFailure(new IllegalStateException("registered to an event loop already"));
return;
}
if (!isCompatible(eventLoop)) {
promise.setFailure(
new IllegalStateException("incompatible event loop type: " + eventLoop.getClass().getName()));
return;
}
AbstractChannel.this.eventLoop = eventLoop;
if (eventLoop.inEventLoop()) {
register0(promise);
} else {
try {
eventLoop.execute(new Runnable() {
@Override
public void run() {
register0(promise);
}
});
} catch (Throwable t) {
closeForcibly();
closeFuture.setClosed();
safeSetFailure(promise, t);
}
}
}
方法最终调用doRegister
得到selectionKey
*/
@Override
protected void doRegister() throws Exception {
boolean selected = false;
for (;;) {
try {
//注册nio的选择事件,默认0选择所有的事件(读就绪,已连接,写就绪等)
selectionKey = javaChannel().register(eventLoop().unwrappedSelector(), 0, this);
return;
} catch (CancelledKeyException e) {
if (!selected) {
// Force the Selector to select now as the "canceled" SelectionKey may still be
// cached and not removed because no Select.select(..) operation was called yet.
eventLoop().selectNow();
selected = true;
} else {
// We forced a select operation on the selector before but the SelectionKey is still cached
// for whatever reason. JDK bug ?
throw e;
}
}
}
}
那么最后就剩开始连接服务器了,连接服务器的最终调用方法:
private static void doConnect(
final SocketAddress remoteAddress, final SocketAddress localAddress, final ChannelPromise connectPromie) {
// This method is invoked before channelRegistered() is triggered. Give user handlers a chance to set up
// the pipeline in its channelRegistered() implementation.
final Channel channel = connectPromise.channel();
channel.eventLoop().execute(new Runnable() {
@Override
public void run() {
if (localAddress == null) {
channel.connect(remoteAddress, connectPromise);
} else {
channel.connect(remoteAddress, localAddress, connectPromise);
}
connectPromise.addListener(ChannelFutureListener.CLOSE_ON_FAILURE);
}
});
}
管道最终调用
connect
方法,调来调去又回到
NioSocketChannel
调用方法
protectedboolean doConnect(SocketAddress remoteAddress, SocketAddress localAddress)throws Exception {
if (localAddress != null) {
doBind0(localAddress);
}
boolean success = false;
try {
boolean connected =SocketUtils.connect(javaChannel(), remoteAddress);
if (!connected) {
selectionKey().interestOps(SelectionKey.OP_CONNECT);
}
success = true;
return connected;
} finally {
if (!success) {
doClose();
}
}
}
好了,整个连接走通了,下一篇讲解,数据解析,发送的逻辑管道顺序,本人第一次写帖子,以前实在是很懒去写贴子,写了之后才知道其中的辛酸,和不容易,思路也可以更好的撸清,以后要坚持写帖子了,如果你喜欢这篇文章,请转载。