introduction
From the beginning of this article, we take a reading Netty
of the source code to achieve, mainly for Netty
the core to achieve further sort out. But then again, if we look directly at Netty
the source code, they may not know where to start, then multiple source packages large and small, like a mess, a multitude of things. Therefore, this article from Netty
start to start, according to the startup process to gradually open the service Netty
of the mystery, clarifying Netty
technical context.
NioEventLoop
create- to sum up
Today is the weekend, but the clock is still on time wake up tired himself. No work day, then have the class write blog, ha ha.
Below is Netty
the Reactor
thread schematic model can facilitate understanding of this part of the follow-up article in this chart will continue to occur, mainly related to the contents of this article contains several of these steps.
(Picture from the network)
A, NioEventLoop create
Netty
Service starts, the most important thing is ready to accept client connections. We look at each custom thread and boss
thread to complete the task and process, as follows:
Here a list of some of the more important class names and their corresponding main functional description, so that everyone at the time reading the source code can quickly understand the corresponding class Features:
class | effect |
---|---|
ServerBootstrap | Server side, start the auxiliary class |
NioEventLoop | Nio event handler (Reactor model) |
NioEventLoopGroup | A group of Nio event handlers (Reactor model) |
In the Netty
source pack, we first look io.netty.example.echo
package EchoServer
class that contains the Netty
service starts the relevant code, source code and source code specific part of the analysis is shown below NOTE:
public final class EchoServer {
static final boolean SSL = System.getProperty("ssl") != null;
static final int PORT = Integer.parseInt(System.getProperty("port", "8007"));
public static void main(String[] args) throws Exception {
// Configure SSL.
final SslContext sslCtx;
if (SSL) {
SelfSignedCertificate ssc = new SelfSignedCertificate();
sslCtx = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey()).build();
} else {
sslCtx = null;
}
//处理连接事件
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
//处理读以及写的事件
EventLoopGroup workerGroup = new NioEventLoopGroup();
final EchoServerHandler serverHandler = new EchoServerHandler();
try {
//服务引导类
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG, 100)
.handler(new LoggingHandler(LogLevel.INFO))
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch) throws Exception {
//初始化channel.pipeline
ChannelPipeline p = ch.pipeline();
if (sslCtx != null) {
p.addLast(sslCtx.newHandler(ch.alloc()));
}
//p.addLast(new LoggingHandler(LogLevel.INFO));
p.addLast(serverHandler);
}
});
// 启动服务,绑定端口
ChannelFuture f = b.bind(PORT).sync();
// Wait until the server socket is closed.
f.channel().closeFuture().sync();
} finally {
// Shut down all event loops to terminate all threads.
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
}
Start Netty
the service process, creating two EventLoopGroup
objects, these two objects are Netty
the core of the object, which bossGroup
is configured to receive a request workerGroup
to process the request. As follows:
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup();
We can look NioEventLoopGroup
class inheritance structure of the case, as follows:
From the figure shows, NioEventLoopGroup
implements ScheduledExecutorService
the interface, it can achieve timing functions related tasks. It also inherits the SingleThreadEventExecutor
class, the class can be seen from the name, this is a single-threaded executor thread. In Netty
by NioEventLoopGroup
creation created to achieve NioEventLoop
the purpose. There reference parameters by constructing NioEventLoopGroup
the object, the actual call is MultithreadEventExecutorGroup
constructor, as follows:
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) {
//ewDefaultThreadFactory()会创建一个线程工厂,该线程工厂的作用就是用来创建线程,同时给线程设置名称:nioEventLoop-1-XX
executor = new ThreadPerTaskExecutor(newDefaultThreadFactory());
}
// 根据传进来的线程数,来创建指定大小的数组大小,这个数组就是用来存放NioEventLoop对象实例
children = new EventExecutor[nThreads];
for (int i = 0; i < nThreads; i ++) {
//异常标志
boolean success = false;
try {
////创建nThreads个nioEventLoop保存到children数组中
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;
}
}
}
}
}
// 通过线程执行器选择工厂来创建一个线程执行器
chooser = chooserFactory.newChooser(children);
final FutureListener<Object> terminationListener = new FutureListener<Object>() {
@Override
public void operationComplete(Future<Object> future) throws Exception {
if (terminatedChildren.incrementAndGet() == children.length) {
terminationFuture.setSuccess(null);
}
}
};
for (EventExecutor e: children) {
e.terminationFuture().addListener(terminationListener);
}
Set<EventExecutor> childrenSet = new LinkedHashSet<EventExecutor>(children.length);
Collections.addAll(childrenSet, children);
readonlyChildren = Collections.unmodifiableSet(childrenSet);
}
Corresponding parameter parsing, as shown in the following table:
parameter | Explanation |
---|---|
nThreads | The number of threads created |
executor | Thread actuator (the user can customize, was not null, subsequent initialized) |
chooserFactory | Event execution selection Plant |
EventLoopGroup
In the creation of the calls NioEventLoop
in the openSelector()
method.
EventLoopGroup
Creating essence is to create more NioEventLoop
, to create here NioEventLoop
is a initialization Reactor
, including selector
and taskQueue
.
NioEventLoop
Source as follows:
public final class NioEventLoop extends SingleThreadEventLoop {
...
private SelectorTuple openSelector() {
final Selector unwrappedSelector;
try {
unwrappedSelector = provider.openSelector();
} catch (IOException e) {
throw new ChannelException("failed to open a new selector", e);
}
if (DISABLE_KEY_SET_OPTIMIZATION) {
return new SelectorTuple(unwrappedSelector);
}
Object maybeSelectorImplClass = AccessController.doPrivileged(new PrivilegedAction<Object>() {
@Override
public Object run() {
try {
return Class.forName(
"sun.nio.ch.SelectorImpl",
false,
PlatformDependent.getSystemClassLoader());
} catch (Throwable cause) {
return cause;
}
}
});
if (!(maybeSelectorImplClass instanceof Class) ||
// ensure the current selector implementation is what we can instrument.
!((Class<?>) maybeSelectorImplClass).isAssignableFrom(unwrappedSelector.getClass())) {
if (maybeSelectorImplClass instanceof Throwable) {
Throwable t = (Throwable) maybeSelectorImplClass;
logger.trace("failed to instrument a special java.util.Set into: {}", unwrappedSelector, t);
}
return new SelectorTuple(unwrappedSelector);
}
final Class<?> selectorImplClass = (Class<?>) maybeSelectorImplClass;
final SelectedSelectionKeySet selectedKeySet = new SelectedSelectionKeySet();
Object maybeException = AccessController.doPrivileged(new PrivilegedAction<Object>() {
@Override
public Object run() {
try {
Field selectedKeysField = selectorImplClass.getDeclaredField("selectedKeys");
Field publicSelectedKeysField = selectorImplClass.getDeclaredField("publicSelectedKeys");
if (PlatformDependent.javaVersion() >= 9 && PlatformDependent.hasUnsafe()) {
// Let us try to use sun.misc.Unsafe to replace the SelectionKeySet.
// This allows us to also do this in Java9+ without any extra flags.
long selectedKeysFieldOffset = PlatformDependent.objectFieldOffset(selectedKeysField);
long publicSelectedKeysFieldOffset =
PlatformDependent.objectFieldOffset(publicSelectedKeysField);
if (selectedKeysFieldOffset != -1 && publicSelectedKeysFieldOffset != -1) {
PlatformDependent.putObject(
unwrappedSelector, selectedKeysFieldOffset, selectedKeySet);
PlatformDependent.putObject(
unwrappedSelector, publicSelectedKeysFieldOffset, selectedKeySet);
return null;
}
// We could not retrieve the offset, lets try reflection as last-resort.
}
Throwable cause = ReflectionUtil.trySetAccessible(selectedKeysField, true);
if (cause != null) {
return cause;
}
cause = ReflectionUtil.trySetAccessible(publicSelectedKeysField, true);
if (cause != null) {
return cause;
}
selectedKeysField.set(unwrappedSelector, selectedKeySet);
publicSelectedKeysField.set(unwrappedSelector, selectedKeySet);
return null;
} catch (NoSuchFieldException e) {
return e;
} catch (IllegalAccessException e) {
return e;
}
}
});
if (maybeException instanceof Exception) {
selectedKeys = null;
Exception e = (Exception) maybeException;
logger.trace("failed to instrument a special java.util.Set into: {}", unwrappedSelector, e);
return new SelectorTuple(unwrappedSelector);
}
selectedKeys = selectedKeySet;
logger.trace("instrumented a special java.util.Set into: {}", unwrappedSelector);
return new SelectorTuple(unwrappedSelector,
new SelectedSelectionKeySetSelector(unwrappedSelector, selectedKeySet));
}
...
}
Second, summary
In this paper, by Netty
the startup code of the service, a preliminary understanding of Netty
what had been done things during the boot process. It focuses on the NioEventLoop
creation process, after the article then describes the startup process, Netty
the other operations.