本文采用版本为Jboss Netty-3.2.4.Final,Jboss Netty示例example、几十页的user guide是快速学习的入门捷径,学习Netty的过程中个人觉其思路比Apache Mina清晰且简洁,API提供了UML类图,对于相互之间的关系容易了解。
言归正传,以示例EchoServer为切入点,eclipse下一步一步debug、阅读其源码并分析下Netty的执行过程,总结下运行机制。
/**Netty example*/ public class EchoServer { public static void main(String[] args) throws Exception { // 配置Server ServerBootstrap bootstrap = new ServerBootstrap(new NioServerSocketChannelFactory( Executors.newCachedThreadPool(), Executors.newCachedThreadPool())); // 设置pipeline factory. bootstrap.setPipelineFactory(new ChannelPipelineFactory() { public ChannelPipeline getPipeline() throws Exception { return Channels.pipeline(new EchoServerHandler()); } }); // 绑定,开始接受client连接 bootstrap.bind(new InetSocketAddress(8080)); } }
一、配置Server
Bootstrap是初始化Channel的辅助类,为子类提供了通用的数据结构,ServerBootstrap 继承自Bootstrap,辅助
Server端创建Channel,接受客户端的连接(connection)。ServerBootstrap 只能用作有链接的transports ,如:TCP IP,绝不能用于UDP。
/*对于示例可以分开写成如下形式*/ ChannelFactory channelFactory = new NioServerSocketChannelFactory( Executors.newCachedThreadPool(), Executors.newCachedThreadPool()); bootstrap = new ServerBootstrap(channelFactory);
ServerBootstrap构造函数
Constructor Summary
ServerBootstrap() Creates a new instance with no ChannelFactory set. 无参构造函数创建实例 |
ServerBootstrap(ChannelFactory channelFactory) Creates a new instance with the specified initial ChannelFactory .使用指定的ChannelFactory创建 |
ServerBootstrap(channelFactory)做如下工作:
public ServerBootstrap(ChannelFactory channelFactory) { /*调用父类构造函数*/ super(channelFactory); }
父类Bootstrap构造函数:
protected Bootstrap(ChannelFactory channelFactory) { /*父类构造函数调用set属性方法*/ setFactory(channelFactory); } public void setFactory(ChannelFactory factory) { /*判断null*/ if (factory == null) { throw new NullPointerException("factory"); } /*是否已经设置channelFactory*/ if (this.factory != null) { throw new IllegalStateException( "factory can't change once set."); } /*属性赋值*/ this.factory = factory; }
创建一个ServerBootstrap,仅做了将channelFactory赋值给父类factory属性的动作。Netty是如何构造ChannelFactory,NioServerSocketChannelFactory的源码我们分析下。
同样我们先看下其API的构造函数。
NioServerSocketChannelFactory创建服务端的ServerSocketChannel,采用多线程执行非阻塞IO,和Mina的设计
模式一样,都采用了Reactor模式。其中bossExecutor、workerExecutor是两个线程池,bossExecutor用来接收客户端连接,workerExecutor用来执行非阻塞的IO操作,主要是read,write。
Reactor模式:
图表2:反应器模式
NioServerSocketChannelFactory构造函数:
Constructor Summary
NioServerSocketChannelFactory(Executor bossExecutor, Executor workerExecutor) Creates a new instance. 默认采用创建CPU*2个工作者线程数 |
NioServerSocketChannelFactory(Executor bossExecutor, Executor workerExecutor, int workerCount) Creates a new instance. 通过workerCount指定工作者线程数 |
NioServerSocketChannelFactory
源码如下:
public NioServerSocketChannelFactory( Executor bossExecutor, Executor workerExecutor, int workerCount) { this.bossExecutor = bossExecutor; this.workerExecutor = workerExecutor; /*创建指定数量的工作者线程*/ sink = new NioServerSocketPipelineSink(workerExecutor, workerCount); }
未指定工作者线程数量的构造函数采用了默认值SelectorUtil.DEFAULT_IO_THREADS,CPU数量的2倍,Runtime.getRuntime().availableProcessors() * 2。下面是在NioServerSocketPipelineSink的构造上函数中创建工作者线程。
NioServerSocketPipelineSink构造函数:
NioServerSocketPipelineSink(Executor workerExecutor, int workerCount) { /* *类定义了一个工作者数组,NioWorker[] workers。 */ workers = new NioWorker[workerCount]; for (int i = 0; i < workers.length; i ++) { workers[i] = new NioWorker(id, i + 1, workerExecutor); } }
至此,通过一个NioServerSocketChannelFactory创建ServerBootstrap实例做了以上工作,下面我们用一个时序图展示下步骤。
描述:
1,EchoServer的Main构造一个NioServerSocketChannelFactory实例。
2,无参构造函数实例化一个NioServerSocketChannelFactory。
3,实例化一个NioServerSocketPipelineSink。
4,创建工作者线程,默认CPU2倍。
5,构造工作者线程。
6,初始化工作者线程属性等。
7,返回创建好的ChannelFactory。
8,根据ChannelFactory实例化ServerBootstrap。
9,设置父类的factory属性
10,创建完毕,返回该实例。
图标4:类的大致关系
2、设置pipeline factory
待续
Reactor参考:
http://www.cs.bgu.ac.il/~spl051/Personal_material/Practical_sessions/Ps_12/ps12.html
Scalable IO in Java