在阅读IoBuffer源码之前,我们先看Mina对IoBuffer的描述:A byte buffer used by MINA applications. This is a replacement for ByteBuffer. 这是一个对ByteBuffer的replacement,同样是用作缓冲区,做内容的切换和承载的容器,为什么要用重新封装ByteBuffer,MINA是这么给出解释的Two Reasons:

l  It doesn't provide useful getters and putters

l  It is difficult to write variable-length data due to its fixed capacity

用过ByteBuffer的人可能经常会遇到BufferOverflowException这样的异常,原因是buffer在初始化allocate之后就不能再自动的改变大小了,如果项目很规整,约定的很好,那可能不太会出意外,怕就怕项目一大,好多东西就乱套了。所以在阅读IoBuffer源码的时候,我们会着重看它和ByteBuffer之间的差异。另外一点,就是IoBuffer作为一个应用框架的工具,必然会提供比原生Buffer更便捷的方法,比如IoBuffer中可以直接put和get String,可以直接将内容转成十六进制等等。

用法很简单,我倒是想从如何将一个已有的类进行封装和扩展的角度来看IoBuffer的源码。在看MINA的源码之前,我们有必要稍稍回顾一下ByteBuffer的构成:

ByteBuffer继承了Buffer类,这个继承关系约定了Buffer系列中特定的操作形式(有点儿像指针),limit/position/mark/capacity,以及在遍历中使用的hasRemaining。然后通过两个静态方法来构建出ByteBuffer:

使用Heap空间,堆空间的构造采用申请byte数组:

public static ByteBuffer allocate(int capacity) {
if (capacity < 0)
throw new IllegalArgumentException();
return new HeapByteBuffer(capacity, capacity);
}

使用direct memory,这块内存的开辟就比较麻烦了,好多都是采用了Bit和native的方法:

public static ByteBuffer allocateDirect(int capacity) {
return new DirectByteBuffer(capacity);
}

除了构造之外,剩下的主要是对数据的操作方法,wrap、get和put,下面的图没有截全,还有好多方法:

IoBuffer及其相关的类均在org.apache.mina.core.buffer下,IoBuffer定义了buffer使用的规则,AbseractIoBuffer提供了具体的实现:

IoBuffer没有继承任何类,只是实现了comparable接口,我们注意到IoBuffer类修饰符用的是abstract,跟ByteBuffer也是用abstract修饰,至于为什么要用abstract,我觉得也容易理解,毕竟这是一个要对外直接使用的类,同时需要对实现进行规则和扩展:

public abstract class IoBuffer implements Comparable<IoBuffer>

在IoBuffer的一系列代码阅读中,你可以看到抽象类之间的继承,内部类的使用情况等等,后面,我会通过一个删减版的例子来盘点这中间的关系,所以大片的源码就不贴了。

UML工具不会用,关键是怕用错了,还是用PPT画了。囧一个,大家有好那种可以一键生成的工具推荐一下,我之前用的是JUDE和Visio。上图画出了IoBuffer中几个重要类之间的关系,两个内部类均继承了AbstractIoBuffer,AbstractIoBuffer和IoBufferWrapper均实现了IoBuffer中的具体操作部分。IoBufferAllocator接口主要定义了为缓冲区开辟空间的方法,所以IoBuffer中需要引用来自IoBufferAllocator的对象。

在IoBuffer中,我们熟知的allocate和wrap方法被声明成了static,通过引用IoBufferAllocator接口中的对象来实现,而其他诸如get、put等操作的方法都定义为abstract了,让其子类得以实现。IoBuffer中我们还值得关注的主要见我之前写过的一篇文章《IoBuffer和ByteBuffer》

下面是这些中产生buffer的接口IoBufferAllocator和其实现类:

接口很简单,就定义了几个在IoBuffer中已经被static修饰的方法。有两个类都实现了IoBufferAllocator,但是在IoBuffer中使用的是SimpleBufferAllocator:

/** The allocator used to create new buffers */
private static IoBufferAllocator allocator = new SimpleBufferAllocator(); /** A flag indicating which type of buffer we are using : heap or direct */
private static boolean useDirectBuffer = false;

所以我们主要关注SimpleBufferAllocator:

public IoBuffer allocate(int capacity, boolean direct) {
return wrap(allocateNioBuffer(capacity, direct));
} public ByteBuffer allocateNioBuffer(int capacity, boolean direct) {
ByteBuffer nioBuffer;
if (direct) {
nioBuffer = ByteBuffer.allocateDirect(capacity);
} else {
nioBuffer = ByteBuffer.allocate(capacity);
}
return nioBuffer;
} public IoBuffer wrap(ByteBuffer nioBuffer) {
return new SimpleBuffer(nioBuffer);
} public void dispose() {
// Do nothing
}

这是接口中定义的几个方法,这里调用内部类SimpleBuffer来生成相应的buffer,又由于SimpleBuffer继承了AbstractIoBuffer,所以真正实现的代码在AbstractIoBuffer中(这里有点儿绕,大家结合上面的图和源码一起读)。而且注意构造方法的protected关键字的使用:

private ByteBuffer buf;

        protected SimpleBuffer(ByteBuffer buf) {
super(SimpleBufferAllocator.this, buf.capacity());
this.buf = buf;
buf.order(ByteOrder.BIG_ENDIAN);
} protected SimpleBuffer(SimpleBuffer parent, ByteBuffer buf) {
super(parent);
this.buf = buf;
}

看到了吧,底层还是用的NIO中的ByteBuffer。至于怎么实现AutoExpand这样的方法,我觉得不是源码的重点,这些都是算法上的事情,如果你不关注算法,可以稍稍看看即可,而且好多都是native的实现,也看不到。而我这边主要关注的还是他们之间的结构。

上图左边的路走通了,我们来走右边的路,右边主要看AbstractIoBuffer,他是IoBuffer的具体实现,但是它也是一个抽象类,也要被其他类继承,用于扩展。AbstractIoBuffer中,大多类都是final的。而且这里面主要的实现都是在处理limit/position/mark/capacity这之间的关系。而CachedBufferAllocator主要用于实现IoBuffer中自动扩展AutoExpand和收缩: that caches the buffers which are likely to be reused during auto-expansion of the buffers.

----------------------------------------------------------

最后,我们将上面的叙述用一个删减版的代码来模拟一下,这样有助于理解代码的结构,以后遇到类似的情况就可以类似的处理,我更希望,能在分析完所有源码之后,就能呈现一个类似的框架出来,不过这个真的只是想想,毕竟没那么多时间,如果你有时间,可以试着去阉割一下mina。

首先是IoBuffer:

package org.apache.mina.core.rewrite.buffer;

/**
* IoBuffer
*
* @author ChenHui
*
*/
public abstract class IoBuffer { private static IoBufferAllocator allocator=new SimpleBufferAllocator();
private static boolean direct; protected IoBuffer() {
// do nothing
} public static IoBuffer allocate(int capacity) {
return allocator.allocate(capacity, direct);
} public static IoBuffer wrap(byte[] byteArray, int offset, int length){
//TODO
return null;
} public abstract IoBuffer get(); public abstract IoBuffer put(byte b); public abstract boolean other();
}

然后是他的继承:

package org.apache.mina.core.rewrite.buffer;

import java.nio.ByteBuffer;

/**
*
* @author ChenHui
*
*/
public abstract class AbstractIoBuffer extends IoBuffer{ protected AbstractIoBuffer(ByteBuffer buffer){
//TODO
} @Override
public IoBuffer get() {
// TODO Auto-generated method stub
return null;
} @Override
public IoBuffer put(byte b) {
// TODO Auto-generated method stub
return null;
} }

allocator:

package org.apache.mina.core.rewrite.buffer;

import java.nio.ByteBuffer;

/**
*
* @author ChenHui
*
*/
public interface IoBufferAllocator { IoBuffer allocate(int capacity, boolean direct); IoBuffer wrap(ByteBuffer nioBuffer); ByteBuffer allocateNioBuffer(int capacity, boolean direct); void dispose(); }

allocator的实现:

package org.apache.mina.core.rewrite.buffer;

import java.nio.ByteBuffer;
/**
*
* @author ChenHui
*
*/
public class SimpleBufferAllocator implements IoBufferAllocator{ @Override
public IoBuffer allocate(int capacity, boolean direct) {
return wrap(allocateNioBuffer(capacity, direct));
} @Override
public IoBuffer wrap(ByteBuffer nioBuffer) { return new SimpleBuffer(nioBuffer);
} @Override
public ByteBuffer allocateNioBuffer(int capacity, boolean direct) {
ByteBuffer nioBuffer;
if (direct) {
nioBuffer = ByteBuffer.allocateDirect(capacity);
} else {
nioBuffer = ByteBuffer.allocate(capacity);
}
return nioBuffer;
} @Override
public void dispose() {
// TODO Auto-generated method stub } private class SimpleBuffer extends AbstractIoBuffer{
@SuppressWarnings("unused")
ByteBuffer buffer;
protected SimpleBuffer(ByteBuffer buffer){
super(buffer);
this.buffer=buffer;
} @Override
public boolean other() {
// TODO Auto-generated method stub
return false;
} /**这里重写是为了打印方便*/
@Override
public String toString() {
System.out.println(buffer);
return super.toString();
}
}
}

最后是测试类和测试结果:

package org.apache.mina.core.rewrite.buffer;

public class Test {
public static void main(String[] args) {
IoBuffer buffer=IoBuffer.allocate(1024);
System.out.println(buffer);
}
}

控制台输出:

java.nio.HeapByteBuffer[pos=0 lim=1024 cap=1024]
org.apache.mina.core.rewrite.buffer.SimpleBufferAllocator$SimpleBuffer@1da12fc0

-------------------------------------------------------------------

文章引自---https://my.oschina.net/ielts0909/blog/90584

MINA系列学习-IoBuffer的更多相关文章

  1. Mina的IoBuffer改造成Netty的ByteBuff

    背景:部标GPS通讯底层全部改造成基于Netty服务器实现的,现将Mina的依赖移除,修改过程中有用到缓冲区的读写.现做了如下修改: 原有基于Mina的IoBuffer对字节读写封装代码如下: pac ...

  2. MINA系列学习-mina整体介绍

    今天的这一节,将从整体上对mina的源代码进行把握,网上已经有好多关于mina源码的阅读笔记,但好多都是列举了一下每个接口或者类的方法.我倒是想从mina源码的结构和功能上对这个框架进行剖析.源码的阅 ...

  3. MINA系列学习-IoAccpetor

    其实在mina的源码中,IoService可以总结成五部分service责任.Processor线程处理.handler处理器.接收器和连接器,分别对应着IoService.IoProcessor.I ...

  4. 【MINA】缓存区ByteBuffer和IOBuffer你要了解的常用知识

    mina中IOBuffer是Nio中ByteBuffer的衍生类,主要是解决Bytebuffer的两个不足 1.没有提供足够灵活的get/putXXX方法 2.它容量固定,难以写入可变长度的数据 特点 ...

  5. Mina源码阅读笔记(二)- IoBuffer的封装

    在阅读IoBuffer源码之前,我们先看Mina对IoBuffer的描述:A byte buffer used by MINA applications. This is a replacement ...

  6. Mina、Netty、Twisted一起学(四):定制自己的协议

    在前面的博文中,介绍一些消息分割的方案,以及MINA.Netty.Twisted针对这些方案提供的相关API.例如MINA的TextLineCodecFactory.PrefixedStringCod ...

  7. mina2

      远程通信 Mina2 学习笔记 作者:李少华 邮箱:xiaosanshaoli@126.com QQ:305409913 2010-12-23   初稿 引言... 1 一.       Mina ...

  8. mina IoBuffer

    mina IoBuffer 常用方法   Limit(int) 如果position>limit, position = limit,如果mark>limit, 重置mark Mark() ...

  9. mina IoBuffer 常用方法

    Limit(int) 如果position>limit, position = limit,如果mark>limit, 重置mark Mark() 取当前的position的快照标记mar ...

随机推荐

  1. HTML 浏览器显示控制

    //强制浏览器以最高版本运行页面 <meta http-equiv="X-UA-Compatible" content="IE=edge,Chrome=1" ...

  2. java面试题个人总结

    1.重载和重写的区别重写:发生在父子类中,方法名.参数列表必须相同,返回值小于等于父类,抛出的异常小于等于父类,访问修饰符大于等于父类:如果父类方法访问修饰符为private则子类中就不是重写.2.j ...

  3. sqlserver如何关闭死锁进程.

    1.首先我们需要判断是哪个用户锁住了哪张表. --查询被锁表 select request_session_id spid,OBJECT_NAME(resource_associated_entity ...

  4. POI 设置

    FileOutputStream fos = new FileOutputStream("D:\\15.xls"); HSSFWorkbook wb = new HSSFWorkb ...

  5. rabbitMQ+yii2 使用

    安装rabbitMQ 见此文章 http://www.cnblogs.com/zxxyx/p/6229613.html 安装好之后 出现此目录: 然后需要yii里面进行载入: 这个目录下面: 加上这个 ...

  6. 关于JDK 安装,以及Java环境的设置

    关于JDK 安装,以及Java环境的设置 1.下载JDK1.6,选择对应的安装路径 2.配置相应的Java 环境变量 A.属性名称:JAVA_HOME 属性值:C:\Program Files\Jav ...

  7. IPv6测试环境

    1.准备机器 三台PC机器,通过1个hub连接,1台windows,安装成双网卡,1个网卡连接外网,1个网卡连接IPv6环网.系统版本:xp sp3 for japan 2台linux机器.操作系统版 ...

  8. 为了解决mysqlbing翻译表字段问题而分析frm文件(持续更新)

    出处:kelvin19840813 的博客 http://www.cnblogs.com/kelvin19840813/ 您的支持是对博主最大的鼓励,感谢您的认真阅读.本文版权归作者所有,欢迎转载,但 ...

  9. cocos2d-js callFunc传参

    1.传递一个参数: pg.TestScene.prototype.init = function () { if (cc.Scene.prototype.init.call(this)) { var ...

  10. Spring AOP /代理模式/事务管理/读写分离/多数据源管理

    参考文章: http://www.cnblogs.com/MOBIN/p/5597215.html http://www.cnblogs.com/fenglie/articles/4097759.ht ...