Netty是由JBOSS提供的一个java开源框架,是一个高性能、高可扩展性的异步事件 驱动的网络应用程序框架,它极大地简化了TCP和UDP客户端和服务器开发等网络编程。Netty具有统一的API,支持多种传输类型,阻塞和非阻塞的,它同时拥有简单而强大的Recator线程模型,支持无连接数据报套接字,基于灵活且可扩展的事件模型,可以清晰地分离关注点,我们可以在github的https://github.com/netty/netty/tree/4.1/example这里看到netty实现的大量例子,包括socket,redis,http等实现,比Java的核心API更高的吞吐量以及更低的延迟,是因为实现了池化和复用机制,也具有完整的SSL / TLS和StartTLS支持。
我们看下怎么启动一个Netty应用,并分析下它是怎么一步步的启动的,netty使用的是4.1.34.Final版本的,下面看下这个代码片段
public static void main(String[] args) {
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
NettyServerHandlerTest1 handlerTest1 = new NettyServerHandlerTest1();
ServerBootstrap serverBootstrap = new ServerBootstrap();
serverBootstrap.group(bossGroup,workerGroup)
.channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG,1024)
.handler(new LoggingHandler(LogLevel.INFO))
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
ChannelPipeline pipeline = socketChannel.pipeline();
pipeline.addLast(handlerTest1);
}
});
ChannelFuture channelFuture = serverBootstrap.bind(8010).sync();
channelFuture.channel().closeFuture().sync();
}catch (Exception e) {
e.printStackTrace();
}finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
在上面这个代码中我们创建的是一个服务端的代码,它首先创建了两个EventLoopGroup对象分别是bossGroup和workGroup,bossGroup是用于和客户端连接作用的,workGroup是用于将bossGroup接收到的客户端请求进行分别处理的线程,在这里就要提到一个Reactor线程模型了,它是由Doug Lee提出的一种线程模型,它的大概原理如下图
当有客户端连接到服务端mainReactor主线程的时候,在主线程经过一定的处理后将接收到的信息传递给一个Acceptor线程,在Acceptor中有多个subReactor的数组,经过一定的取值方式取出其中一个subReactor线程对在channel中的数据进行读取,如果是业务数据则新建一个线程来进行业务上面的操作,这样就保证了线程的不会阻塞,同时也实现了一个subReactor可以处理多个channel来的业务数据的要求,这个就是大概的Reactor线程模型的含义。我们接着看下EventLoopGroup的创建过程,在创建bossGroup的时候我们传入的参数是1,这个可以理解为1个服务器只有1个入口,通过这个入口在将消息分发给其他workGroup,而workGroup创建的时候我们是没有传入参数的,我们主要看下这个的创建过程,整理了一个如下图所示的图片
通过构造函数我们可以进入到MultitreadEvnetLoopGroup类
protected MultithreadEventLoopGroup(int nThreads, Executor executor, Object... args) {
super(nThreads == 0 ? DEFAULT_EVENT_LOOP_THREADS : nThreads, executor, args);
}
在这个类的构造函数中判断了我们传入的线程数量,如果传入的线程数量为0,那么就去取默认值,这里有2种默认值的实现,一种是通过系统参数io.netty.eventLoopThreads进行指定,另外一种是在没有系统参数指定的情况下,默认获取系统处理器数量*2的值
private static final int DEFAULT_EVENT_LOOP_THREADS;
static {
DEFAULT_EVENT_LOOP_THREADS = Math.max(1, SystemPropertyUtil.getInt(
"io.netty.eventLoopThreads", NettyRuntime.availableProcessors() * 2));
......
}
然后继续通过构造函数进入到MultithreadEventExecutorGroup类中
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());
}
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;
}
}
}
}
}
......
在该构造函数中,如果在Executor没有初始化的情况下,创建了一个默认工厂线程执行类,然后根据线程个数创建一个线程数组children,循环该children,通过newChild()方法创建一个NioEventLoop对象,接下来我们看下NioEventLoop的实现
NioEventLoop(NioEventLoopGroup parent, Executor executor, SelectorProvider selectorProvider,
SelectStrategy strategy, RejectedExecutionHandler rejectedExecutionHandler) {
super(parent, executor, false, DEFAULT_MAX_PENDING_TASKS, rejectedExecutionHandler);
if (selectorProvider == null) {
throw new NullPointerException("selectorProvider");
}
if (strategy == null) {
throw new NullPointerException("selectStrategy");
}
provider = selectorProvider;
final SelectorTuple selectorTuple = openSelector();
selector = selectorTuple.selector;
unwrappedSelector = selectorTuple.unwrappedSelector;
selectStrategy = strategy;
}
在NioEventLoop构造函数中调用了super的实现,以及新建了一个selectorTuple变量,这个变量对java.nio.channels.Selector进行了封装,也就是说这里还是一个对Java原生的Selector的实现,再次进入到super()方法,分别依次调用了这个两个super
protected SingleThreadEventLoop(EventLoopGroup parent, Executor executor,
boolean addTaskWakesUp, int maxPendingTasks,
RejectedExecutionHandler rejectedExecutionHandler) {
super(parent, executor, addTaskWakesUp, maxPendingTasks, rejectedExecutionHandler);
tailTasks = newTaskQueue(maxPendingTasks);
}
protected SingleThreadEventExecutor(EventExecutorGroup parent, Executor executor,
boolean addTaskWakesUp, int maxPendingTasks,
RejectedExecutionHandler rejectedHandler) {
super(parent);
this.addTaskWakesUp = addTaskWakesUp;
this.maxPendingTasks = Math.max(16, maxPendingTasks);
this.executor = ObjectUtil.checkNotNull(executor, "executor");
taskQueue = newTaskQueue(this.maxPendingTasks);
rejectedExecutionHandler = ObjectUtil.checkNotNull(rejectedHandler, "rejectedHandler");
}
在这2个构造方法中,分别实现了2个queue队列,通过这两个queue的实现,都可以理解为工作线程队列。分析完children数组的创建,我们再次回到MultithreadEventExecutorGroup的构造函数中
protected MultithreadEventExecutorGroup(int nThreads, Executor executor,
EventExecutorChooserFactory chooserFactory, Object... args) {
......
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);
}
接下来我们创建一个了chooser,在这个chooser中,是根据2的n次方进行进行初始化的,看下代码
public EventExecutorChooser newChooser(EventExecutor[] executors) {
if (isPowerOfTwo(executors.length)) {
return new PowerOfTwoEventExecutorChooser(executors);
} else {
return new GenericEventExecutorChooser(executors);
}
}
private static boolean isPowerOfTwo(int val) {
return (val & -val) == val;
}
chooser的选择初始化完成后,在对children中的NioEventLoop对象进行了销毁时的监听,最后创建了一个不可修改的readonlyChildren的set集合,至此就完成了所有的NioEvent对象的创建,在下篇文章中我们分析端口的bind及启动过程。