在mina的源码,整个框架最核心的几个包是 :

  • org.apache.mina.core.service :IoService、IoProcessor、IoHandler、IoAcceptor、IoConnector
  • org.apache.mina.core.session
  • org.apache.mina.core.polling
  • org.apache.mina.transport.socket

IoService Base interface for all IoAcceptors and IoConnectors that provide I/O service and manage IoSessions.
      它是所有 IoAcceptor 和 IoConnector 的基接口,对于一个 IoService,有哪些信息需要我们关注呢?

  1. 底层的元数据信息 TransportMetadata,比如底层的网络服务提供者(NIO,ARP,RXTX等)。(除此方法之外,其它方法在 AbstractIoService 得以实现。)
  2. 通过这个服务创建一个新会话时,新会话的默认配置 IoSessionConfig。
  3. 此服务所管理的所有会话。
  4. 与这个服务相关所产生的事件所对应的监听者(IoServiceListener)。
  5. 处理这个服务所管理的所有连接的处理器(IoHandler)。
  6. 每个会话都有一个过滤器链(IoFilterChain),每个过滤器链通过其对应的 IoFilterChainBuilder来负责构建。
  7. 由于此服务管理了一系列会话,因此可以通过广播的方式向所有会话发送消息,返回结果是一个WriteFuture集,后者是一种表示未来预期结果的数据结构。
  8. 服务创建的会话(IoSession)相关的数据通过 IoSessionDataStructureFactory来提供。
  9. 发送消息时有一个写缓冲队列。
  10. 服务的闲置状态有三种:读端空闲,写端空闲,双端空闲。
  11. 还提供服务的一些统计信息,比如时间,数据量等。

IoProcessor<S extends IoSession> :An internal interface to represent an 'I/O processor' that performs actual I/O operations for IoSessions. It abstracts existing reactor frameworks such as Java NIO once again to simplify transport implementations.
一个内部接口代表一个I/O处理器,它为 IoSession 执行实际的I/O操作。它抽象现有反应器框架,如 Java NIO 再一次简化传输实现。

1、IoAcceptor :服务器端接口,接受客户端访问的请求。

2、AbstractIoService :设定处理函数、Filter、IoServiceListener,实现了 IoService 所有方法,除了 getTransportMetadata() 。

3、IoServiceListener :可以用于打印日志,主要有Service启动、停止、空闲等监听方法。

4、处理函数是一个Executor或者是Executor的包装。

5、AbstractIoAcceptor完成绑定监听端口。

6、AbstractPollingIoAcceptor执行具体的监听连接以及监听I/O事件,但真正实现的是NioSocketAcceptor open() 方法。

7、NioSocketAcceptor用JAVA NIO的方式实现了具体的连接方法ServerSocketChannel,例如open,accept等

 

以下代码的流程:

    IoAcceptor acceptor = new NioSocketAcceptor();
acceptor.setHandler(new IoHandlerAdapter());
acceptor.bind(new InetSocketAddress(6969));

1)NioSocketAcceptor 构造函数:

    public NioSocketAcceptor() {
super(new DefaultSocketSessionConfig(), NioProcessor.class);
((DefaultSocketSessionConfig) getSessionConfig()).init(this);
}

定义了SessionConfig,并把this传递到SessionConfig当中,指定NioProcessor。

AbstractPollingIoAcceptor 构造函数:

    protected AbstractPollingIoAcceptor(IoSessionConfig sessionConfig, Class<? extends IoProcessor<S>> processorClass) {
this(sessionConfig, null, new SimpleIoProcessorPool<S>(processorClass), true);
}
    private AbstractPollingIoAcceptor(IoSessionConfig sessionConfig, Executor executor, IoProcessor<S> processor,
boolean createdProcessor) {
super(sessionConfig, executor); if (processor == null) {
throw new IllegalArgumentException("processor");
} this.processor = processor;
this.createdProcessor = createdProcessor; try {
// Initialize the selector
init(); // 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);
}
}
}
}
    public SimpleIoProcessorPool(Class<? extends IoProcessor<S>> processorType, Executor executor) {
this(processorType, executor, DEFAULT_SIZE); // int DEFAULT_SIZE = Runtime.getRuntime().availableProcessors() + 1;
}
    public SimpleIoProcessorPool(Class<? extends IoProcessor<S>> processorType, Executor executor, int size) {
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 {
processorConstructor = processorType.getConstructor(Executor.class);
pool[0] = processorConstructor.newInstance(this.executor);
} 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) {
pool[i] = processorConstructor.newInstance(this.executor);
} else {
pool[i] = processorConstructor.newInstance();
}
} catch (Exception e) {
// Won't happen because it has been done previously
}
} success = true;
} finally {
if (!success) {
dispose();
}
}
}
    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);
}
}

new SimpleIoProcessorPool<S>(processorClass) :是把NioProcessor包装成了pool.看类图IoProcessor就很好理解了,这是一个组成模式。

init()的调用实际上是NioSocketAcceptor的,init() 源码:selector = Selector.open(); 值得注意的是,服务端在创建NioSocketAcceptor实现时,会生成一个线程池(AbstractIoService.executor),此线程池用来执行一个接受请求的任务,这个任务是AbstractPollingIoAcceptor的Acceptor,Acceptor会开一个Selector,用来监听NIO中的ACCEPT事件。任务初始化时并没有执行,而在调用NioSocketAcceptor实例的bind方法时,则会启动对指定端口的ACCEPT事件的监听。

SimpleIoProcessorPool是在NioSocketAcceptor实例化时创建的,其上有N+1(N=CPU的个数)个NIOProcessor(IoProcessor<S>[] pool)来处理实际IO的读写事件,每个pool都是从NioSocketAcceptor构造函数传过去的NioProcessor实例,并在NioProcessor构造函数传入一个线程池。

每个NIOProcessor都会对应一个Selector和 NioSocketAcceptor.init() 中的Selector 一起构成了Mina独有的双Selector模型,这种设计的优点是不会导致阻塞),来监听Socket中的读写事件。实际对读写的操作也是在一个SimpleIoProcessorPool实例化好的一个线程池中以任务的形式执行,这个任务叫Processor(可以在AbstractPollingIoProcessor类中找到其实现)

AbstractIoAcceptor 构造函数:

    protected AbstractIoAcceptor(IoSessionConfig sessionConfig, Executor executor) {
super(sessionConfig, executor);
defaultLocalAddresses.add(null);
}

AbstractIoAcceptor主要用来绑定监听端口。这个构造函数没有干其他的事情。

    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();
}

这个构造函数还有一个监听器,或者叫监听池(可以包含多个监听器)。用来监听service创建、连接、断开等动作,当上述动作发生地时候,会调用listener。里面可以写自己的一些方法。

一次请求的过程如下 :

Client通过Socket连接服务器,先是由Acceptor接收到请求连接的事件(即ACCEPT事件)。此事件由Acceptor进行处理,会创建一条Socket连接,并将此连接和一个NIOProcessor关联,这个过程通过图中的连接分配器进行,连接分配器会均衡的将Socket和不同的NIOProcessor绑定(轮流分配),绑定完成后,会在NIOProcessor上进行读写事件的监听,而读写的实际处理则分配给Processor任务完成。当有读写事件发生时,就会通知到对应的Processor进行数据处理。

Apache Mina(二)的更多相关文章

  1. Apache MiNa 实现多人聊天室

    Apache MiNa 实现多人聊天室 开发环境: System:Windows JavaSDK:1.6 IDE:eclipse.MyEclipse 6.6 开发依赖库: Jdk1.4+.mina-c ...

  2. Apache Mina开发手冊之四

    Apache Mina开发手冊之四 作者:chszs,转载需注明. 博客主页:http://blog.csdn.net/chszs 一.Mina开发的主要步骤 1.创建一个实现了IoService接口 ...

  3. Apache Mina入门实例

    一.mina是啥 ApacheMINA是一个网络应用程序框架,用来帮助用户简单地开发高性能和高可扩展性的网络应用程序.它提供了一个通过Java NIO在不同的传输例如TCP/IP和UDP/IP上抽象的 ...

  4. Apache Mina(一)

    原文链接:http://www.cnblogs.com/xuekyo/archive/2013/03/06/2945826.html Apache Mina是一个能够帮助用户开发高性能和高伸缩性网络应 ...

  5. Apache MINA(一)

    Apache MINA is a network application framework which helps users develop high performance and high s ...

  6. Apache Mina 入门实例

    这个教程是介绍使用Mina搭建基础示例.这个教程内容是以创建一个时间服务器. 以下是这个教程需要准备的东西: MINA 2.0.7 Core JDK 1.5 或更高 SLF4J 1.3.0 或更高 L ...

  7. Apache Mina原理及典型例子分析

    Apache Mina ,一个高性能 Java 异步并发网络通讯框架.利用 Mina 可以高效地完成以下任务: TCP/IP 和 UDP/IP 通讯 串口通讯 VM 间的管道通讯 SSL/TLS JX ...

  8. Apache Mina 2.x 框架+源码分析

    源码下载 http://www.apache.org/dyn/closer.cgi/mina/mina/2.0.9/apache-mina-2.0.9-src.tar.gz 整体架构 核心过程(IoA ...

  9. 网络通信框架Apache MINA

    Apache MINA(Multipurpose Infrastructure for Network Applications) 是 Apache 组织一个较新的项目,它为开发高性能和高可用性的网络 ...

随机推荐

  1. CentOS 下mysql 的安装

    1.安装mysql服务器 yum -y install mysql-server 2.装入service启动服务 /etc/rc.d/init.d/mysqld start 3.设置mysql服务开机 ...

  2. Git学习 -- 冲突解决

    当连个分支对统一文件提交了不同修改时,可能会出现冲突,例如: $ git merge feature1 Auto-merging readme.txt CONFLICT (content): Merg ...

  3. Linux学习 -- 用户和用户组管理

    1 用户配置文件 1.1 用户信息文件 /etc/passwd 查看帮助 man 5 passwd -- account:password:UID:GID:GECOS:directory:shell ...

  4. (转)Windows管道(Pipe)重定向stdout,stderr,stdin

    参考: http://qiusuoge.com/11496.html http://www.cnblogs.com/BoyXiao/archive/2011/01/01/1923828.html st ...

  5. Apache多端口配置

    修改http.conf监听多个端口 Listen 80 Listen 8001 Listen 8002 配置站点 <VirtualHost *:8001> ServerName *:800 ...

  6. 虚拟ip

    网卡上增加一个IP: ifconfig eth0:1 192.168.0.1 netmask 255.255.255.0 删除网卡的第二个IP地址: ip addr del 192.168.0.1 d ...

  7. 转 如何使用V7包中ActionBar(Eclipse版)

    http://blog.csdn.net/appte/article/details/11712591 以前3.0以前的版本要使用ActionBar,必须使用国外大牛写的ActionBarSherlo ...

  8. BAT54C 二极管是如何工作的?

    这是一个多电源供电的电路:Vcc是正常供电电源(如5V,由市电变换得到),电压大于(Vcc1-Vf),正常供电时二极管不导通:Vcc1是电池供电电源,当Vcc撤掉时,DD1(上边的二极管)导通,由Vc ...

  9. <a href="#" onclick="history.back();"></a>这样写为什么是对的? -(转)

    为什么不用这样写?<a href="#" onclick="javascript:history.back();"></a> 正解是: ...

  10. 如何查看和更改mysql数据库文件存放位置

    mysql数据库的数据文件默认是存放在:C:\Documents and Settings\All Users\Application Data\MySQL\MySQL Server 5.1\data ...