Netty 源码分析(一)
来源:互联网 发布:patch软件资源下载 编辑:程序博客网 时间:2024/05/19 23:52
1.创建两个NIO线程组,一个专门用于网络事件处理(接受客户端的连接),另一个则进行网络通信读写。
2.创建一个ServerBootstrap对象,配置Netty的一系列参数,例如接受传出数据的缓存大小等。
3.创建一个实际处理数据的类Channellnitalizer,进行初始化的准备工作,比如设置接受传出数据的字符 格式 以及实际处理数据的接口
4.绑定接口,执行同步阻塞方法等待服务器启动即可。
如此简单的四个步骤,我们的服务器端就编写完成了,几十行代码 就可以把之前NIO的代码代替。
public class Server { public static void main(String[] args) throws Exception { //1 第一个线程组 是用于接收Client端连接的 EventLoopGroup bossGroup = new NioEventLoopGroup(); //2 第二个线程组 是用于实际的业务处理操作的 EventLoopGroup workerGroup = new NioEventLoopGroup(); //3 创建一个辅助类Bootstrap,就是对我们的Server进行一系列的配置 ServerBootstrap b = new ServerBootstrap(); //把俩个工作线程组加入进来 b.group(bossGroup, workerGroup) //我要指定使用NioServerSocketChannel这种类型的通道 .channel(NioServerSocketChannel.class) .option(ChannelOption.SO_BACKLOG, 1024) //设置tcp列队缓冲区 .option(ChannelOption.SO_SNDBUF, 32*1024) //设置发送缓冲大小 .option(ChannelOption.SO_RCVBUF, 32*1024) //这是接收缓冲大小 .option(ChannelOption.SO_KEEPALIVE, true) //保持连接 //一定要使用 childHandler 去绑定具体的 事件处理器 .childHandler(new ChannelInitializer<SocketChannel>() { @Override protected void initChannel(SocketChannel sc) throws Exception { sc.pipeline().addLast(new ServerHandler()); } }); //绑定指定的端口 进行监听 ChannelFuture f = b.bind(8765).sync(); //Thread.sleep(1000000); f.channel().closeFuture().sync(); bossGroup.shutdownGracefully(); workerGroup.shutdownGracefully(); } }
我们来看 EventLoopGroup接口 源码
EventLoopGroup继承了EventExecutorGroup 是一个特殊的EventExecutorGroup , 允许在 select 循环时间操作 期间 可以注册 channel通道
EventLoopGroup 是一个事件循环组, EventLoop 是 事件循环 其实就是不断的等待事件发生的死循环。
/** * Special {@link EventExecutorGroup} which allows registering {@link Channel}s that get * processed for later selection during the event loop. * */public interface EventLoopGroup extends EventExecutorGroup { /** * Return the next {@link EventLoop} to use 返回下一个事件循环 */ @Override EventLoop next(); /** * Register a {@link Channel} with this {@link EventLoop}. The returned {@link ChannelFuture} * will get notified once the registration was complete. 将一个通道也就是连接注册到 事件循环中,通过ChannelFuture 异步返回的方法来判断是否完成 */ ChannelFuture register(Channel channel); /** * Register a {@link Channel} with this {@link EventLoop} using a {@link ChannelFuture}. The passed * {@link ChannelFuture} will get notified once the registration was complete and also will get returned. */ ChannelFuture register(ChannelPromise promise); /** * Register a {@link Channel} with this {@link EventLoop}. The passed {@link ChannelFuture} * will get notified once the registration was complete and also will get returned. * * @deprecated Use {@link #register(ChannelPromise)} instead. */ @Deprecated ChannelFuture register(Channel channel, ChannelPromise promise);}
ChannelFuture 接口 是继承了Future 接口 ,ChannelPromise 接口 继承了ChannelFuture
我们可以看到 ChannelFuture register(Channel channel); 注册一个通道或者连接 到事件循环中,那么ChannelFuture register(ChannelPromise promise); 是并没有Channel 如何注册,可以看ChannelPromise 源码里面 包含了Channel 对象的引用 才能将通道注册到事件循环中。
NioEventLoopGroup源码:用于基于NIO Selector 选择的 channel,
我们有的时候初始化 使用NioEventLoopGroup(1)一个线程用于接收Client端连接,默认NioEventLoopGroup()根据源码可以看到 是使用我们系统内核*2的线程来处理的,从NioEventLoopGroup源码 中可以看出 就是进行一些初始化的赋值
/* * 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.channel.nio;import io.netty.channel.Channel;import io.netty.channel.EventLoop;import io.netty.channel.DefaultSelectStrategyFactory;import io.netty.channel.MultithreadEventLoopGroup;import io.netty.channel.SelectStrategyFactory;import io.netty.util.concurrent.EventExecutor;import io.netty.util.concurrent.EventExecutorChooserFactory;import io.netty.util.concurrent.RejectedExecutionHandler;import io.netty.util.concurrent.RejectedExecutionHandlers;import java.nio.channels.Selector;import java.nio.channels.spi.SelectorProvider;import java.util.concurrent.Executor;import java.util.concurrent.ThreadFactory;/** * {@link MultithreadEventLoopGroup} implementations which is used for NIO {@link Selector} based {@link Channel}s.用于基于NIO Selector 选择的 channel */public class NioEventLoopGroup extends MultithreadEventLoopGroup { /** * Create a new instance using the default number of threads, the default {@link ThreadFactory} and * the {@link SelectorProvider} which is returned by {@link SelectorProvider#provider()}. */ public NioEventLoopGroup() { this(0); 第一步 } /** * Create a new instance using the specified number of threads, {@link ThreadFactory} and the * {@link SelectorProvider} which is returned by {@link SelectorProvider#provider()}. */ public NioEventLoopGroup(int nThreads) { this(nThreads, (Executor) null); 第二步 } /** * Create a new instance using the specified number of threads, the given {@link ThreadFactory} and the * {@link SelectorProvider} which is returned by {@link SelectorProvider#provider()}. */ public NioEventLoopGroup(int nThreads, ThreadFactory threadFactory) { this(nThreads, threadFactory, SelectorProvider.provider()); 第三步 } public NioEventLoopGroup(int nThreads, Executor executor) { this(nThreads, executor, SelectorProvider.provider());第四步 } /** * Create a new instance using the specified number of threads, the given {@link ThreadFactory} and the given * {@link SelectorProvider}. */ public NioEventLoopGroup( int nThreads, ThreadFactory threadFactory, final SelectorProvider selectorProvider) { this(nThreads, threadFactory, selectorProvider, DefaultSelectStrategyFactory.INSTANCE);第五步 } public NioEventLoopGroup(int nThreads, ThreadFactory threadFactory, final SelectorProvider selectorProvider, final SelectStrategyFactory selectStrategyFactory) { super(nThreads, threadFactory, selectorProvider, selectStrategyFactory, RejectedExecutionHandlers.reject());第六步 这时调用了父类的方法 } 那么我们去看 父类构造方法 public NioEventLoopGroup( int nThreads, Executor executor, final SelectorProvider selectorProvider) { this(nThreads, executor, selectorProvider, DefaultSelectStrategyFactory.INSTANCE); } public NioEventLoopGroup(int nThreads, Executor executor, final SelectorProvider selectorProvider, final SelectStrategyFactory selectStrategyFactory) { super(nThreads, executor, selectorProvider, selectStrategyFactory, RejectedExecutionHandlers.reject()); } public NioEventLoopGroup(int nThreads, Executor executor, EventExecutorChooserFactory chooserFactory, final SelectorProvider selectorProvider, final SelectStrategyFactory selectStrategyFactory) { super(nThreads, executor, chooserFactory, selectorProvider, selectStrategyFactory, RejectedExecutionHandlers.reject()); } public NioEventLoopGroup(int nThreads, Executor executor, EventExecutorChooserFactory chooserFactory, final SelectorProvider selectorProvider, final SelectStrategyFactory selectStrategyFactory, final RejectedExecutionHandler rejectedExecutionHandler) { super(nThreads, executor, chooserFactory, selectorProvider, selectStrategyFactory, rejectedExecutionHandler); } /** * Sets the percentage of the desired amount of time spent for I/O in the child event loops. The default value is * {@code 50}, which means the event loop will try to spend the same amount of time for I/O as for non-I/O tasks. */ public void setIoRatio(int ioRatio) { for (EventExecutor e: this) { ((NioEventLoop) e).setIoRatio(ioRatio); } } /** * Replaces the current {@link Selector}s of the child event loops with newly created {@link Selector}s to work * around the infamous epoll 100% CPU bug. */ public void rebuildSelectors() { for (EventExecutor e: this) { ((NioEventLoop) e).rebuildSelector(); } } @Override protected EventLoop newChild(Executor executor, Object... args) throws Exception { return new NioEventLoop(this, executor, (SelectorProvider) args[0], ((SelectStrategyFactory) args[1]).newSelectStrategy(), (RejectedExecutionHandler) args[2]); }}
从静态初始化方法来看,先冲 配置项中 找io.netty.eventLoopThreads 未配置 按照系统内核*2的线程 赋值
/** * Abstract base class for {@link EventLoopGroup} implementations that handles their tasks with multiple threads at * the same time. */public abstract class MultithreadEventLoopGroup extends MultithreadEventExecutorGroup implements EventLoopGroup { private static final InternalLogger logger = InternalLoggerFactory.getInstance(MultithreadEventLoopGroup.class); private static final int DEFAULT_EVENT_LOOP_THREADS; static { DEFAULT_EVENT_LOOP_THREADS = Math.max(1, SystemPropertyUtil.getInt( "io.netty.eventLoopThreads", NettyRuntime.availableProcessors() * 2)); if (logger.isDebugEnabled()) { logger.debug("-Dio.netty.eventLoopThreads: {}", DEFAULT_EVENT_LOOP_THREADS); } } /** * @see MultithreadEventExecutorGroup#MultithreadEventExecutorGroup(int, Executor, Object...) */ protected MultithreadEventLoopGroup(int nThreads, Executor executor, Object... args) { super(nThreads == 0 ? DEFAULT_EVENT_LOOP_THREADS : nThreads, executor, args); 第七步 我们在看父类的构造方法 }MultithreadEventExecutorGroup 源码:
Eexecutor作为灵活且强大的异步执行框架,其支持多种不同类型的任务执行策略,提供了一种标准的方法将任务的提交过程和执行过程解耦开发,基于生产者-消费者模式,其提交任务的线程相当于生产者,执行任务的线程相当于消费者,并用Runnable来表示任务,Executor的实现还提供了对生命周期的支持,以及统计信息收集,应用程序管理机制和性能监视等机制。
/** * Abstract base class for {@link EventExecutorGroup} implementations that handles their tasks with multiple threads at * the same time. */public abstract class MultithreadEventExecutorGroup extends AbstractEventExecutorGroup { private final EventExecutor[] children; private final Set<EventExecutor> readonlyChildren; private final AtomicInteger terminatedChildren = new AtomicInteger(); private final Promise<?> terminationFuture = new DefaultPromise(GlobalEventExecutor.INSTANCE); private final EventExecutorChooserFactory.EventExecutorChooser chooser; /** * Create a new instance. * * @param nThreads the number of threads that will be used by this instance. * @param threadFactory the ThreadFactory to use, or {@code null} if the default should be used. * @param args arguments which will passed to each {@link #newChild(Executor, Object...)} call */ protected MultithreadEventExecutorGroup(int nThreads, ThreadFactory threadFactory, Object... args) { this(nThreads, threadFactory == null ? null : new ThreadPerTaskExecutor(threadFactory), args); } /** * Create a new instance. * * @param nThreads the number of threads that will be used by this instance. * @param executor the Executor to use, or {@code null} if the default should be used. * @param args arguments which will passed to each {@link #newChild(Executor, Object...)} call */ protected MultithreadEventExecutorGroup(int nThreads, Executor executor, Object... args) { this(nThreads, executor, DefaultEventExecutorChooserFactory.INSTANCE, args); } /** * Create a new instance. * * @param nThreads the number of threads that will be used by this instance. * @param executor the Executor to use, or {@code null} if the default should be used. * @param chooserFactory the {@link EventExecutorChooserFactory} to use. * @param args arguments which will passed to each {@link #newChild(Executor, Object...)} call */ 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; } } } } } 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); } protected ThreadFactory newDefaultThreadFactory() { return new DefaultThreadFactory(getClass()); } @Override public EventExecutor next() { return chooser.next(); } @Override public Iterator<EventExecutor> iterator() { return readonlyChildren.iterator(); } /** * Return the number of {@link EventExecutor} this implementation uses. This number is the maps * 1:1 to the threads it use. */ public final int executorCount() { return children.length; } /** * Create a new EventExecutor which will later then accessible via the {@link #next()} method. This method will be * called for each thread that will serve this {@link MultithreadEventExecutorGroup}. * */ protected abstract EventExecutor newChild(Executor executor, Object... args) throws Exception;
创建线程执行器
public final class ThreadPerTaskExecutor implements Executor { private final ThreadFactory threadFactory; public ThreadPerTaskExecutor(ThreadFactory threadFactory) { if (threadFactory == null) { throw new NullPointerException("threadFactory"); } this.threadFactory = threadFactory; } @Override public void execute(Runnable command) { threadFactory.newThread(command).start(); }}
创建线程工厂
/** * A {@link ThreadFactory} implementation with a simple naming rule. */public class DefaultThreadFactory implements ThreadFactory { private static final AtomicInteger poolId = new AtomicInteger(); private final AtomicInteger nextId = new AtomicInteger(); private final String prefix; private final boolean daemon; private final int priority; protected final ThreadGroup threadGroup; public DefaultThreadFactory(Class<?> poolType) { this(poolType, false, Thread.NORM_PRIORITY); } public DefaultThreadFactory(String poolName) { this(poolName, false, Thread.NORM_PRIORITY); } public DefaultThreadFactory(Class<?> poolType, boolean daemon) { this(poolType, daemon, Thread.NORM_PRIORITY); } public DefaultThreadFactory(String poolName, boolean daemon) { this(poolName, daemon, Thread.NORM_PRIORITY); } public DefaultThreadFactory(Class<?> poolType, int priority) { this(poolType, false, priority); } public DefaultThreadFactory(String poolName, int priority) { this(poolName, false, priority); } public DefaultThreadFactory(Class<?> poolType, boolean daemon, int priority) { this(toPoolName(poolType), daemon, priority); } public static String toPoolName(Class<?> poolType) { if (poolType == null) { throw new NullPointerException("poolType"); } String poolName = StringUtil.simpleClassName(poolType); switch (poolName.length()) { case 0: return "unknown"; case 1: return poolName.toLowerCase(Locale.US); default: if (Character.isUpperCase(poolName.charAt(0)) && Character.isLowerCase(poolName.charAt(1))) { return Character.toLowerCase(poolName.charAt(0)) + poolName.substring(1); } else { return poolName; } } } public DefaultThreadFactory(String poolName, boolean daemon, int priority, ThreadGroup threadGroup) { if (poolName == null) { throw new NullPointerException("poolName"); } if (priority < Thread.MIN_PRIORITY || priority > Thread.MAX_PRIORITY) { throw new IllegalArgumentException( "priority: " + priority + " (expected: Thread.MIN_PRIORITY <= priority <= Thread.MAX_PRIORITY)"); } prefix = poolName + '-' + poolId.incrementAndGet() + '-'; this.daemon = daemon; this.priority = priority; this.threadGroup = threadGroup; } public DefaultThreadFactory(String poolName, boolean daemon, int priority) { this(poolName, daemon, priority, System.getSecurityManager() == null ? Thread.currentThread().getThreadGroup() : System.getSecurityManager().getThreadGroup()); } @Override public Thread newThread(Runnable r) { Thread t = newThread(new DefaultRunnableDecorator(r), prefix + nextId.incrementAndGet()); try { if (t.isDaemon() != daemon) { t.setDaemon(daemon); } if (t.getPriority() != priority) { t.setPriority(priority); } } catch (Exception ignored) { // Doesn't matter even if failed to set. } return t; } protected Thread newThread(Runnable r, String name) { return new FastThreadLocalThread(threadGroup, r, name); } private static final class DefaultRunnableDecorator implements Runnable { private final Runnable r; DefaultRunnableDecorator(Runnable r) { this.r = r; } @Override public void run() { try { r.run(); } finally { FastThreadLocal.removeAll(); } } }}
EventExecutorGroup :提供next()方法 返回EventExecutor
/** * The {@link EventExecutorGroup} is responsible for providing the {@link EventExecutor}'s to use * via its {@link #next()} method. Besides this, it is also responsible for handling their * life-cycle and allows shutting them down in a global fashion. * */public interface EventExecutorGroup extends ScheduledExecutorService, Iterable<EventExecutor> { /** * Returns {@code true} if and only if all {@link EventExecutor}s managed by this {@link EventExecutorGroup} * are being {@linkplain #shutdownGracefully() shut down gracefully} or was {@linkplain #isShutdown() shut down}. */ boolean isShuttingDown(); /** * Shortcut method for {@link #shutdownGracefully(long, long, TimeUnit)} with sensible default values. * * @return the {@link #terminationFuture()} */ Future<?> shutdownGracefully(); /** * Signals this executor that the caller wants the executor to be shut down. Once this method is called, * {@link #isShuttingDown()} starts to return {@code true}, and the executor prepares to shut itself down. * Unlike {@link #shutdown()}, graceful shutdown ensures that no tasks are submitted for <i>'the quiet period'</i> * (usually a couple seconds) before it shuts itself down. If a task is submitted during the quiet period, * it is guaranteed to be accepted and the quiet period will start over. * * @param quietPeriod the quiet period as described in the documentation * @param timeout the maximum amount of time to wait until the executor is {@linkplain #shutdown()} * regardless if a task was submitted during the quiet period * @param unit the unit of {@code quietPeriod} and {@code timeout} * * @return the {@link #terminationFuture()} */ Future<?> shutdownGracefully(long quietPeriod, long timeout, TimeUnit unit); /** * Returns the {@link Future} which is notified when all {@link EventExecutor}s managed by this * {@link EventExecutorGroup} have been terminated. */ Future<?> terminationFuture(); /** * @deprecated {@link #shutdownGracefully(long, long, TimeUnit)} or {@link #shutdownGracefully()} instead. */ @Override @Deprecated void shutdown(); /** * @deprecated {@link #shutdownGracefully(long, long, TimeUnit)} or {@link #shutdownGracefully()} instead. */ @Override @Deprecated List<Runnable> shutdownNow(); /** * Returns one of the {@link EventExecutor}s managed by this {@link EventExecutorGroup}. */ EventExecutor next(); @Override Iterator<EventExecutor> iterator(); @Override Future<?> submit(Runnable task); @Override <T> Future<T> submit(Runnable task, T result); @Override <T> Future<T> submit(Callable<T> task); @Override ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit); @Override <V> ScheduledFuture<V> schedule(Callable<V> callable, long delay, TimeUnit unit); @Override ScheduledFuture<?> scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit); @Override ScheduledFuture<?> scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit);}
- Netty 源码分析(一)
- netty 源码分析一
- netty源码分析一
- netty源码分析(一)-启动
- netty源码分析(一)EventLoopGroup
- netty EventLoop 源码分析(一)
- [netty源码分析]--ChannelPipeline源码分析(一)
- Netty 源码分析之 一 客户端创建(Bootstrap )
- Netty 源码分析之 一 服务端创建(ServerBootstrap )
- Netty源码分析(一)—服务端初始化
- netty学习及源码分析(一)
- Netty 源码分析之 EventLoop(一)
- Netty 源码分析(二)
- Netty 源码分析(三)
- netty(一):数据流分析
- Netty 4.0 源码分析(四):ByteBuf
- netty(十)源码分析之ByteBuf
- netty(十三)源码分析之Channel
- Please make sure you have the correct access rights
- Android Studio Template
- HashMap源码解析
- 回归、分类与聚类:三大方向剖解机器学习算法的优缺点
- java resultSet获取总行数
- Netty 源码分析(一)
- Spring技术内幕:SpringIOC原理学习总结
- ImageLoader的使用
- 集合源码学习(六):TreeMap
- Js apply()使用详解
- Python 定时线程,延时线程
- JVM 垃圾回收器
- openssh-server (sshd)
- ListView的多条目加载