上一篇我们通过实例学习了MINA框架的用法,发现用起来还是挺方便的,就那么几步就可以了,本着学东西必知其原理的观念,决定看看MINA的源码实现,好了,我们开始吧!
MINA源码对于客户端和服务端来说基本上差别不是很大的,所以我计划主要还是分析服务端的源码,在正式分析之前,我们需要对MINA有一个整体的了解;
MINA中涉及到了这么几个对象:
IoService:用于提供连接,他是IoAcceptor和IoConnector的父接口;
IoBuffer:消息缓存区;
IoSession:在每一次连接建立成功之后都会创建一个IoSession对象出来,并且在创建该对象的时候创建一个IoFilter对象出来,通过IoSession的session id来为当前IoSession设置处理他的IoProcessor;
IoProcessor:用于检查是否有数据在通道上面进行读写,在我们创建Acceptor或者Connector的时候,默认会创建一个线程池,里面存储的就是IoProcessor线程,该线程里面是拥有自己的Selector的,这个是MINA为我们做的一点优化,我们通常使用NIO的话是只有一个Selector的,而MINA中的
IoFilter:用于定义拦截器,这些拦截器可以包括日志输出、数据编解码等等,只要用于二进制数据和对象之间的转换;
IoHandler:处于IoFilter的尾部,用于真正的业务逻辑处理,所以我们在使用MINA的时候是必须要提供IoHandler对象的,因为是靠他来进行真正业务处理的;
接下来我们看看上篇博客中我们用到的MINA中涉及到的这几个对象的类结构图:
NioSocketAcceptor类结构图:
NioSocketConnector类结构图:
NioSocketSession类结构图:
NioProcessor类结构图:
好了,开始我们真正的源码分析了(服务端);
首先我们通过NioSocketAcceptor acceptor = new NioSocketAcceptor();创建了一个NioSocketAcceptor对象出来,那我们就得看看NioSocketAcceptor的构造函数里面做了些什么事了;
NioSocketAcceptor$NioSocketAcceptor()
- public NioSocketAcceptor() {
- super(new DefaultSocketSessionConfig(), NioProcessor.class);
- ((DefaultSocketSessionConfig) getSessionConfig()).init(this);
- }
AbstractPollingIoAcceptor$AbstractPollingIoAcceptor()
- protected AbstractPollingIoAcceptor(IoSessionConfig sessionConfig, Class<? extends IoProcessor<S>> processorClass) {
- this(sessionConfig, null, new SimpleIoProcessorPool<S>(processorClass), true, null);
- }
SimpleIoProcessorPool$SimpleIoProcessorPool()
- public SimpleIoProcessorPool(Class<? extends IoProcessor<S>> processorType) {
- this(processorType, null, DEFAULT_SIZE, null);
- }
- public SimpleIoProcessorPool(Class<? extends IoProcessor<S>> processorType, Executor executor, int size,
- SelectorProvider selectorProvider) {
- if (processorType == null) {
- throw new IllegalArgumentException("processorType");
- }
- if (size <= 0) {
- throw new IllegalArgumentException("size: " + size + " (expected: positive integer)");
- }
- // Create the executor if none is provided
- createdExecutor = (executor == null);
- if (createdExecutor) {
- this.executor = Executors.newCachedThreadPool();
- // Set a default reject handler
- ((ThreadPoolExecutor) this.executor).setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
- } else {
- this.executor = executor;
- }
- pool = new IoProcessor[size];
- boolean success = false;
- Constructor<? extends IoProcessor<S>> processorConstructor = null;
- boolean usesExecutorArg = true;
- try {
- // We create at least one processor
- try {
- try {
- processorConstructor = processorType.getConstructor(ExecutorService.class);
- pool[0] = processorConstructor.newInstance(this.executor);
- } catch (NoSuchMethodException e1) {
- // To the next step...
- try {
- if(selectorProvider==null) {
- processorConstructor = processorType.getConstructor(Executor.class);
- pool[0] = processorConstructor.newInstance(this.executor);
- } else {
- processorConstructor = processorType.getConstructor(Executor.class, SelectorProvider.class);
- pool[0] = processorConstructor.newInstance(this.executor,selectorProvider);
- }
- } catch (NoSuchMethodException e2) {
- // To the next step...
- try {
- processorConstructor = processorType.getConstructor();
- usesExecutorArg = false;
- pool[0] = processorConstructor.newInstance();
- } catch (NoSuchMethodException e3) {
- // To the next step...
- }
- }
- }
- } catch (RuntimeException re) {
- LOGGER.error("Cannot create an IoProcessor :{}", re.getMessage());
- throw re;
- } catch (Exception e) {
- String msg = "Failed to create a new instance of " + processorType.getName() + ":" + e.getMessage();
- LOGGER.error(msg, e);
- throw new RuntimeIoException(msg, e);
- }
- if (processorConstructor == null) {
- // Raise an exception if no proper constructor is found.
- String msg = String.valueOf(processorType) + " must have a public constructor with one "
- + ExecutorService.class.getSimpleName() + " parameter, a public constructor with one "
- + Executor.class.getSimpleName() + " parameter or a public default constructor.";
- LOGGER.error(msg);
- throw new IllegalArgumentException(msg);
- }
- // Constructor found now use it for all subsequent instantiations
- for (int i = 1; i < pool.length; i++) {
- try {
- if (usesExecutorArg) {
- if(selectorProvider==null) {
- pool[i] = processorConstructor.newInstance(this.executor);
- } else {
- pool[i] = processorConstructor.newInstance(this.executor, selectorProvider);
- }
- } else {
- pool[i] = processorConstructor.newInstance();
- }
- } catch (Exception e) {
- // Won't happen because it has been done previously
- }
- }
- success = true;
- } finally {
- if (!success) {
- dispose();
- }
- }
- }
这段代码相对来说比较长,可以看到在第14行判断传入SimpleIoProcessorPool的executor是否为null,为null的话执行第15行,创建一个CachedThreadPool类型的线程池,随后在第32行通过反射获取到processorType参数为ExecutorService的构造函数,我们这里的processType实际上就是NioProcessor,随后33行通过反射创建一个NioProcessor对象出来,调用的是他的下面这个构造函数:
- public NioProcessor(Executor executor) {
- super(executor);
- try {
- // Open a new selector
- selector = Selector.open();
- } catch (IOException e) {
- throw new RuntimeIoException("Failed to open a selector.", e);
- }
- }
到此,我们创建出来了CPU个数+1个NioProcessor,每个NioProcessor里面都会有一个Selector对象;
我们回到AbstractPollingIoAcceptor的构造函数
- private AbstractPollingIoAcceptor(IoSessionConfig sessionConfig, Executor executor, IoProcessor<S> processor,
- boolean createdProcessor, SelectorProvider selectorProvider) {
- super(sessionConfig, executor);
- if (processor == null) {
- throw new IllegalArgumentException("processor");
- }
- this.processor = processor;
- this.createdProcessor = createdProcessor;
- try {
- // Initialize the selector
- init(selectorProvider);
- // The selector is now ready, we can switch the
- // flag to true so that incoming connection can be accepted
- selectable = true;
- } catch (RuntimeException e) {
- throw e;
- } catch (Exception e) {
- throw new RuntimeIoException("Failed to initialize.", e);
- } finally {
- if (!selectable) {
- try {
- destroy();
- } catch (Exception e) {
- ExceptionMonitor.getInstance().exceptionCaught(e);
- }
- }
- }
- }
- protected AbstractIoService(IoSessionConfig sessionConfig, Executor executor) {
- if (sessionConfig == null) {
- throw new IllegalArgumentException("sessionConfig");
- }
- if (getTransportMetadata() == null) {
- throw new IllegalArgumentException("TransportMetadata");
- }
- if (!getTransportMetadata().getSessionConfigType().isAssignableFrom(sessionConfig.getClass())) {
- throw new IllegalArgumentException("sessionConfig type: " + sessionConfig.getClass() + " (expected: "
- + getTransportMetadata().getSessionConfigType() + ")");
- }
- // Create the listeners, and add a first listener : a activation listener
- // for this service, which will give information on the service state.
- listeners = new IoServiceListenerSupport(this);
- listeners.add(serviceActivationListener);
- // Stores the given session configuration
- this.sessionConfig = sessionConfig;
- // Make JVM load the exception monitor before some transports
- // change the thread context class loader.
- ExceptionMonitor.getInstance();
- if (executor == null) {
- this.executor = Executors.newCachedThreadPool();
- createdExecutor = true;
- } else {
- this.executor = executor;
- createdExecutor = false;
- }
- threadName = getClass().getSimpleName() + '-' + id.incrementAndGet();
- }
这个构造函数会判断我们的executor是否为null,为null的话会创建一个CachedThreadPool出来,这里我们传入给AbstractPollingIoAcceptor的参数值为null,因此会创建一个Executor出来;
可以看到第14行执行了init方法,传入的参数是SelectorProvider类型对象,这个方法在AbstractPollingIoAcceptor里面并没有实现,因此查看AbstractPollingIoAcceptor的子类NioSocketAcceptor的init(SelectorProvider)方法
- protected void init(SelectorProvider selectorProvider) throws Exception {
- this.selectorProvider = selectorProvider;
- if (selectorProvider == null) {
- selector = Selector.open();
- } else {
- selector = selectorProvider.openSelector();
- }
- }
这个方法所做的事还是比较简单的,就是创建根据SelectorProvider是否为空创建Selector对象而已,注意这个Selector对象是属于NioSocketAcceptor的;
在init执行结束之后,AbstractPollingIoAcceptor构造函数第18行会将selectable设置为true,表示我们NioSocketAcceptor里面的Selector对象已经创建结束了,我们可以处理随后客户端到来的连接请求了;
至此,NioSocketAcceptor的构造方法执行结束了,在这个构造方法中为我们创建出了CPU个数+1个NioProcess对象,每个对象里面都包含一个Selector对象,同时也为NioSocketAcceptor创建了一个Selector对象,同时从上面可以发现我们的NioSocketAcceptor和SimpleIoProcessorPool里的线程池可以是同一个也可以不是同一个,具体就在你创建NioSocketAcceptor和SimpleIoProcessorPool是否传入同一个Executor就可以啦;
有了NioSocketAcceptor对象之后,我们通过有了NioSocketAcceptor的bind方法将他和某一个端口绑定起来,因此查看NioSocketAcceptor的bind方法,你会发现根本不存在,那么根据前面NioSocketAcceptor的类结构图,去他的父类AbstractPollingIoAcceptor查找,还是没有,那只能继续向上找,找到AbstractIoAcceptor里面,终于找到了;
AbstractIoAcceptor$bind()
- public final void bind(Iterable<? extends SocketAddress> localAddresses) throws IOException {
- if (isDisposing()) {
- throw new IllegalStateException("The Accpetor disposed is being disposed.");
- }
- if (localAddresses == null) {
- throw new IllegalArgumentException("localAddresses");
- }
- List<SocketAddress> localAddressesCopy = new ArrayList<SocketAddress>();
- for (SocketAddress a : localAddresses) {
- checkAddressType(a);
- localAddressesCopy.add(a);
- }
- if (localAddressesCopy.isEmpty()) {
- throw new IllegalArgumentException("localAddresses is empty.");
- }
- boolean activate = false;
- synchronized (bindLock) {
- synchronized (boundAddresses) {
- if (boundAddresses.isEmpty()) {
- activate = true;
- }
- }
- if (getHandler() == null) {
- throw new IllegalStateException("handler is not set.");
- }
- try {
- Set<SocketAddress> addresses = bindInternal(localAddressesCopy);
- synchronized (boundAddresses) {
- boundAddresses.addAll(addresses);
- }
- } catch (IOException e) {
- throw e;
- } catch (RuntimeException e) {
- throw e;
- } catch (Exception e) {
- throw new RuntimeIoException("Failed to bind to: " + getLocalAddresses(), e);
- }
- }
- if (activate) {
- getListeners().fireServiceActivated();
- }
- }
AbstractPollingIoAcceptor$bindInternal
- protected final Set<SocketAddress> bindInternal(List<? extends SocketAddress> localAddresses) throws Exception {
- // Create a bind request as a Future operation. When the selector
- // have handled the registration, it will signal this future.
- AcceptorOperationFuture request = new AcceptorOperationFuture(localAddresses);
- // adds the Registration request to the queue for the Workers
- // to handle
- registerQueue.add(request);
- // creates the Acceptor instance and has the local
- // executor kick it off.
- startupAcceptor();
- // As we just started the acceptor, we have to unblock the select()
- // in order to process the bind request we just have added to the
- // registerQueue.
- try {
- lock.acquire();
- // Wait a bit to give a chance to the Acceptor thread to do the select()
- Thread.sleep(10);
- wakeup();
- } finally {
- lock.release();
- }
- // Now, we wait until this request is completed.
- request.awaitUninterruptibly();
- if (request.getException() != null) {
- throw request.getException();
- }
- // Update the local addresses.
- // setLocalAddresses() shouldn't be called from the worker thread
- // because of deadlock.
- Set<SocketAddress> newLocalAddresses = new HashSet<SocketAddress>();
- for (H handle : boundHandles.values()) {
- newLocalAddresses.add(localAddress(handle));
- }
- return newLocalAddresses;
- }
首先创建了一个AcceptorOperationFuture类型的对象,当NioSocketAcceptor里面的Selector已经处理了该注册请求后,就会给AcceptorOperationFuture对象发送一个信号,至于什么地方会发送信号后面会讲到,接着会将创建的AcceptorOperationFuture对象添加到registerQueue中,他是一个AcceptorOperationFuture类型的队列,保存着我们所有注册到NioSocketAcceptor上面的服务端address组成的AcceptorOperationFuture,也就是说上面的requestQueue实际上存储的是服务端需要注册到NioSocketAcceptor里面的Selector的集合;接着第12行执行了startupAcceptor方法,我们来看看这个方法做了些什么;
- private void startupAcceptor() throws InterruptedException {
- // If the acceptor is not ready, clear the queues
- // TODO : they should already be clean : do we have to do that ?
- if (!selectable) {
- registerQueue.clear();
- cancelQueue.clear();
- }
- // start the acceptor if not already started
- Acceptor acceptor = acceptorRef.get();
- if (acceptor == null) {
- lock.acquire();
- acceptor = new Acceptor();
- if (acceptorRef.compareAndSet(null, acceptor)) {
- executeWorker(acceptor);
- } else {
- lock.release();
- }
- }
- }
AbstractIoService$executeWorker
- protected final void executeWorker(Runnable worker) {
- executeWorker(worker, null);
- }
- protected final void executeWorker(Runnable worker, String suffix) {
- String actualThreadName = threadName;
- if (suffix != null) {
- actualThreadName = actualThreadName + '-' + suffix;
- }
- executor.execute(new NamePreservingRunnable(worker, actualThreadName));
- }
AbstractPollingIoAcceptor$Acceptor$run()
- public void run() {
- assert (acceptorRef.get() == this);
- int nHandles = 0;
- // Release the lock
- lock.release();
- while (selectable) {
- try {
- // Detect if we have some keys ready to be processed
- // The select() will be woke up if some new connection
- // have occurred, or if the selector has been explicitly
- // woke up
- int selected = select();
- // this actually sets the selector to OP_ACCEPT,
- // and binds to the port on which this class will
- // listen on
- nHandles += registerHandles();
- // Now, if the number of registred handles is 0, we can
- // quit the loop: we don't have any socket listening
- // for incoming connection.
- if (nHandles == 0) {
- acceptorRef.set(null);
- if (registerQueue.isEmpty() && cancelQueue.isEmpty()) {
- assert (acceptorRef.get() != this);
- break;
- }
- if (!acceptorRef.compareAndSet(null, this)) {
- assert (acceptorRef.get() != this);
- break;
- }
- assert (acceptorRef.get() == this);
- }
- if (selected > 0) {
- // We have some connection request, let's process
- // them here.
- processHandles(selectedHandles());
- }
- // check to see if any cancellation request has been made.
- nHandles -= unregisterHandles();
- } catch (ClosedSelectorException cse) {
- // If the selector has been closed, we can exit the loop
- ExceptionMonitor.getInstance().exceptionCaught(cse);
- break;
- } catch (Exception e) {
- ExceptionMonitor.getInstance().exceptionCaught(e);
- try {
- Thread.sleep(1000);
- } catch (InterruptedException e1) {
- ExceptionMonitor.getInstance().exceptionCaught(e1);
- }
- }
- }
- // Cleanup all the processors, and shutdown the acceptor.
- if (selectable && isDisposing()) {
- selectable = false;
- try {
- if (createdProcessor) {
- processor.dispose();
- }
- } finally {
- try {
- synchronized (disposalLock) {
- if (isDisposing()) {
- destroy();
- }
- }
- } catch (Exception e) {
- ExceptionMonitor.getInstance().exceptionCaught(e);
- } finally {
- disposalFuture.setDone();
- }
- }
- }
- }
AbstractPollingIoAcceptor$registerHandles
- private int registerHandles() {
- for (;;) {
- // The register queue contains the list of services to manage
- // in this acceptor.
- AcceptorOperationFuture future = registerQueue.poll();
- if (future == null) {
- return 0;
- }
- // We create a temporary map to store the bound handles,
- // as we may have to remove them all if there is an exception
- // during the sockets opening.
- Map<SocketAddress, H> newHandles = new ConcurrentHashMap<SocketAddress, H>();
- List<SocketAddress> localAddresses = future.getLocalAddresses();
- try {
- // Process all the addresses
- for (SocketAddress a : localAddresses) {
- H handle = open(a);
- newHandles.put(localAddress(handle), handle);
- }
- // Everything went ok, we can now update the map storing
- // all the bound sockets.
- boundHandles.putAll(newHandles);
- // and notify.
- future.setDone();
- return newHandles.size();
- } catch (Exception e) {
- // We store the exception in the future
- future.setException(e);
- } finally {
- // Roll back if failed to bind all addresses.
- if (future.getException() != null) {
- for (H handle : newHandles.values()) {
- try {
- close(handle);
- } catch (Exception e) {
- ExceptionMonitor.getInstance().exceptionCaught(e);
- }
- }
- // TODO : add some comment : what is the wakeup() waking up ?
- wakeup();
- }
- }
- }
- }
首先第5行从我们的registerQueue服务端请求注册队队列中取出队首元素,第14行创建了一个临时的Map来存储我们已经绑定的请求地址对应的SocketAddress,为什么要这个临时的Map呢?原因就在于如果我们在Socket开启的状态下发生异常的话,我们需要移出掉这些已经绑定的请求地址,有点类似于数据库中的事务操作,如果有一个失败,那么就需要全部回滚,具体我们可以看到发生异常之后执行的是第33行代码,为future设置了异常,随后finally中进行了回滚操作;紧接着第15行获得可该AcceptorOperationFuture里面对应的SocketAddress列表,接着执行了第20行的open方法,为我们的每个SocketAddress创建一个ServerSocketChannel及其对应的ServerSocket,同时将通道注册到Selector上面,并且为当前通道注册OP_ACCEPT事件;我们来看看open方法,这个方法是在AbstractPollingIoAcceptor的子类NioSocketAcceptor中实现的;
NioSocketAcceptor$open()
- protected ServerSocketChannel open(SocketAddress localAddress) throws Exception {
- // Creates the listening ServerSocket
- ServerSocketChannel channel = null;
- if (selectorProvider != null) {
- channel = selectorProvider.openServerSocketChannel();
- } else {
- channel = ServerSocketChannel.open();
- }
- boolean success = false;
- try {
- // This is a non blocking socket channel
- channel.configureBlocking(false);
- // Configure the server socket,
- ServerSocket socket = channel.socket();
- // Set the reuseAddress flag accordingly with the setting
- socket.setReuseAddress(isReuseAddress());
- // and bind.
- try {
- socket.bind(localAddress, getBacklog());
- } catch (IOException ioe) {
- // Add some info regarding the address we try to bind to the
- // message
- String newMessage = "Error while binding on " + localAddress + "\n" + "original message : "
- + ioe.getMessage();
- Exception e = new IOException(newMessage);
- e.initCause(ioe.getCause());
- // And close the channel
- channel.close();
- throw e;
- }
- // Register the channel within the selector for ACCEPT event
- channel.register(selector, SelectionKey.OP_ACCEPT);
- success = true;
- } finally {
- if (!success) {
- close(channel);
- }
- }
- return channel;
- }
open方法执行结束之后,registerHandles也算结束了,registerHandles中其他部分代码可以略过,至此,我们将服务端需要创建的ServerSocketChannel及其对应绑定了指定SocketAddress的ServerSocket注册到了Selector选择器中,同时注册了OP_ACCEPT事件;
回到我们Acceptor里面的run方法,注意registerHandles方法的返回值实际上就是我们已经创建ServerSocketChannel的个数,接着就是执行第25行,如果我们创建的ServerSocketChannel个数为0的话,就会退出这个while死循环,因为我们没有任何ServerSocket来监听客户端连接的到来,避免资源的浪费;随后就是第41行,当有通道被选择的时候,selected的值将会是大于0的,那么就会执行第44行的processHandles方法,这个方法的参数是由selectedHandles获得的,他的实现是在NioSocketAcceptor里面的
NioSocketAcceptor$selectedHandles
- protected Iterator<ServerSocketChannel> selectedHandles() {
- return new ServerSocketChannelIterator(selector.selectedKeys());
- }
接下来我们看看processHandles做了些什么
AbstractPollingIoAcceptor$processHandles
- private void processHandles(Iterator<H> handles) throws Exception {
- while (handles.hasNext()) {
- H handle = handles.next();
- handles.remove();
- // Associates a new created connection to a processor,
- // and get back a session
- S session = accept(processor, handle);
- if (session == null) {
- continue;
- }
- initSession(session, null, null);
- // add the session to the SocketIoProcessor
- session.getProcessor().add(session);
- }
- }
- }
NioSocketAcceptor$accept()
- protected NioSession accept(IoProcessor<NioSession> processor, ServerSocketChannel handle) throws Exception {
- SelectionKey key = null;
- if (handle != null) {
- key = handle.keyFor(selector);
- }
- if ((key == null) || (!key.isValid()) || (!key.isAcceptable())) {
- return null;
- }
- // accept the connection from the client
- SocketChannel ch = handle.accept();
- if (ch == null) {
- return null;
- }
- return new NioSocketSession(this, processor, ch);
- }
这个方法里首先获得被选中ServerSocketChannel的key,接着对该key进行一系列的判断,接着第14行获取到和当前ServerSocketChannel有关联的SocketChannel,这里需要补充一点的就是ServerSocketChannel和Selector是通过SelectionKey来发生关联的,SelectionKey标志了我们当前ServerSocketChannel的状态,而如果说某一客户端想要和服务器某一端口服务发生关联的话,那么它实际上是和与该端口绑定的ServerSocketChannel发生联系的,因此我们就可以通过ServerSocketChannel获取与他有关联了客户端SocketChannel啦;最后执行第20行创建一个NioSocketSession对象,我们来看看他的构造函数;
NioSocketSession$NioSocketSession()
- public NioSocketSession(IoService service, IoProcessor<NioSession> processor, SocketChannel channel) {
- super(processor, service, channel);
- config = new SessionConfigImpl();
- this.config.setAll(service.getSessionConfig());
- }
- protected NioSession(IoProcessor<NioSession> processor, IoService service, Channel channel) {
- super(service);
- this.channel = channel;
- this.processor = processor;
- filterChain = new DefaultIoFilterChain(this);
- }
DefaultIoFilterChain$DefaultIoFilterChain()
- public DefaultIoFilterChain(AbstractIoSession session) {
- if (session == null) {
- throw new IllegalArgumentException("session");
- }
- this.session = session;
- head = new EntryImpl(null, null, "head", new HeadFilter());
- tail = new EntryImpl(head, null, "tail", new TailFilter());
- head.nextEntry = tail;
- }
到此呢,我们的NioSocketSession就创建成功啦,创建NioSocketSession其实主要就是在它里面创建一个IoFilter责任链出来,用于处理当前Session的一些编解码工作,这样我们的NioSocketAcceptor的accept方法就执行结束了,返回了一个NioSocketSession对象,继续回到AbstractPollingIoAcceptor里面的processHandles方法,在第8行创建完NioSocketSession之后,执行第17行,将我们的NioSocketSession对象放到NioProcessor中,具体实现过程见下:
首先执行的是session的getProcessor方法,这里的session类型是NioSocketSession,所以我们去NioSocketSession里面查看getProcessor,你会发现它里面不存在这个方法,那就要去他的父类NioSession里面找了,果然我们找到了:
- public IoProcessor<NioSession> getProcessor() {
- return processor;
- }
getProcessor里面的方法体非常简单,就是返回processor而已了,那么这个processor是在哪里赋值的呢?就是在创建NioSession的构造函数里面,我们在创建NioSocketSession的时候是会调用super来调用NioSession的构造函数的,也就是我们这里的processor就是我们在创建NioSocketAcceptor的时候创建的SimpleIoProcessorPool对象,接下来调用的就是它里面的add方法啦:
- public final void add(S session) {
- getProcessor(session).add(session);
- }
- private IoProcessor<S> getProcessor(S session) {
- IoProcessor<S> processor = (IoProcessor<S>) session.getAttribute(PROCESSOR);
- if (processor == null) {
- if (disposed || disposing) {
- throw new IllegalStateException("A disposed processor cannot be accessed.");
- }
- processor = pool[Math.abs((int) session.getId()) % pool.length];
- if (processor == null) {
- throw new IllegalStateException("A disposed processor cannot be accessed.");
- }
- session.setAttributeIfAbsent(PROCESSOR, processor);
- }
- return processor;
- }
那么到这里,实际上add操作执行的就是NioProcessor的add操作啦,我们查看NioProcessor里面会发现不存在这个方法,那么需要去他的父类AbstractPollingIoProcessor查看,代码见下:
AbstractPollingIoProcessor$add()
- public final void add(S session) {
- if (disposed || disposing) {
- throw new IllegalStateException("Already disposed.");
- }
- // Adds the session to the newSession queue and starts the worker
- newSessions.add(session);
- startupProcessor();
- }
紧接着执行了startupProcessor方法,如果你还记得上面的源码分析过程的话,会发现上面有调用过startupAcceptor方法,这两个方法不同之处在于一个是用于开启Processor线程执行它里面NioSocketSession请求的,一个是用于开启Acceptor来进行ServerSocketChannel的事件注册的,并且startupAcceptor只会执行一次,而startupProcessor会执行多次,默认情况下最多执行CPU个数+1次;
我们来看看startupProcessor方法:
AbstractPollingIoProcessor$startupProcessor
- private void startupProcessor() {
- Processor processor = processorRef.get();
- if (processor == null) {
- processor = new Processor();
- if (processorRef.compareAndSet(null, processor)) {
- executor.execute(new NamePreservingRunnable(processor, threadName));
- }
- }
- // Just stop the select() and start it again, so that the processor
- // can be activated immediately.
- wakeup();
- }
- public void run() {
- assert (processorRef.get() == this);
- int nSessions = 0;
- lastIdleCheckTime = System.currentTimeMillis();
- for (;;) {
- try {
- // This select has a timeout so that we can manage
- // idle session when we get out of the select every
- // second. (note : this is a hack to avoid creating
- // a dedicated thread).
- long t0 = System.currentTimeMillis();
- int selected = select(SELECT_TIMEOUT);
- long t1 = System.currentTimeMillis();
- long delta = (t1 - t0);
- if (!wakeupCalled.getAndSet(false) && (selected == 0) && (delta < 100)) {
- // Last chance : the select() may have been
- // interrupted because we have had an closed channel.
- if (isBrokenConnection()) {
- LOG.warn("Broken connection");
- } else {
- LOG.warn("Create a new selector. Selected is 0, delta = " + (t1 - t0));
- // Ok, we are hit by the nasty epoll
- // spinning.
- // Basically, there is a race condition
- // which causes a closing file descriptor not to be
- // considered as available as a selected channel,
- // but
- // it stopped the select. The next time we will
- // call select(), it will exit immediately for the
- // same
- // reason, and do so forever, consuming 100%
- // CPU.
- // We have to destroy the selector, and
- // register all the socket on a new one.
- registerNewSelector();
- }
- }
- // Manage newly created session first
- nSessions += handleNewSessions();
- updateTrafficMask();
- // Now, if we have had some incoming or outgoing events,
- // deal with them
- if (selected > 0) {
- // LOG.debug("Processing ..."); // This log hurts one of
- // the MDCFilter test...
- process();
- }
- // Write the pending requests
- long currentTime = System.currentTimeMillis();
- flush(currentTime);
- // And manage removed sessions
- nSessions -= removeSessions();
- // Last, not least, send Idle events to the idle sessions
- notifyIdleSessions(currentTime);
- // Get a chance to exit the infinite loop if there are no
- // more sessions on this Processor
- if (nSessions == 0) {
- processorRef.set(null);
- if (newSessions.isEmpty() && isSelectorEmpty()) {
- // newSessions.add() precedes startupProcessor
- assert (processorRef.get() != this);
- break;
- }
- assert (processorRef.get() != this);
- if (!processorRef.compareAndSet(null, this)) {
- // startupProcessor won race, so must exit processor
- assert (processorRef.get() != this);
- break;
- }
- assert (processorRef.get() == this);
- }
- // Disconnect all sessions immediately if disposal has been
- // requested so that we exit this loop eventually.
- if (isDisposing()) {
- boolean hasKeys = false;
- for (Iterator<S> i = allSessions(); i.hasNext();) {
- IoSession session = i.next();
- if (session.isActive()) {
- scheduleRemove((S)session);
- hasKeys = true;
- }
- }
- if (hasKeys) {
- wakeup();
- }
- }
- } catch (ClosedSelectorException cse) {
- // If the selector has been closed, we can exit the loop
- // But first, dump a stack trace
- ExceptionMonitor.getInstance().exceptionCaught(cse);
- break;
- } catch (Exception e) {
- ExceptionMonitor.getInstance().exceptionCaught(e);
- try {
- Thread.sleep(1000);
- } catch (InterruptedException e1) {
- ExceptionMonitor.getInstance().exceptionCaught(e1);
- }
- }
- }
- try {
- synchronized (disposalLock) {
- if (disposing) {
- doDispose();
- }
- }
- } catch (Exception e) {
- ExceptionMonitor.getInstance().exceptionCaught(e);
- } finally {
- disposalFuture.setValue(true);
- }
- }
- }
- private int handleNewSessions() {
- int addedSessions = 0;
- for (S session = newSessions.poll(); session != null; session = newSessions.poll()) {
- if (addNow(session)) {
- // A new session has been created
- addedSessions++;
- }
- }
- return addedSessions;
- }
AbstractPollingIoProcessor$addNow()
- private boolean addNow(S session) {
- boolean registered = false;
- try {
- init(session);
- registered = true;
- // Build the filter chain of this session.
- IoFilterChainBuilder chainBuilder = session.getService().getFilterChainBuilder();
- chainBuilder.buildFilterChain(session.getFilterChain());
- // DefaultIoFilterChain.CONNECT_FUTURE is cleared inside here
- // in AbstractIoFilterChain.fireSessionOpened().
- // Propagate the SESSION_CREATED event up to the chain
- IoServiceListenerSupport listeners = ((AbstractIoService) session.getService()).getListeners();
- listeners.fireSessionCreated(session);
- } catch (Exception e) {
- ExceptionMonitor.getInstance().exceptionCaught(e);
- try {
- destroy(session);
- } catch (Exception e1) {
- ExceptionMonitor.getInstance().exceptionCaught(e1);
- } finally {
- registered = false;
- }
- }
- return registered;
- }
NioProcessor$init()
- @Override
- protected void init(NioSession session) throws Exception {
- SelectableChannel ch = (SelectableChannel) session.getChannel();
- ch.configureBlocking(false);
- session.setSelectionKey(ch.register(selector, SelectionKey.OP_READ, session));
- }
这样的话,addNow方法执行结束了,由于这篇篇幅已经比较长了,所以决定在下一篇继续分析,未完,请继续查看下一篇