在阅读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数组:
1 |
public static ByteBuffer
allocate( int capacity)
{ |
3 |
throw new IllegalArgumentException(); |
4 |
return new HeapByteBuffer(capacity,
capacity); |
使用direct memory,这块内存的开辟就比较麻烦了,好多都是采用了Bit和native的方法:
1 |
public static ByteBuffer
allocateDirect( int capacity)
{ |
2 |
return new DirectByteBuffer(capacity); |
除了构造之外,剩下的主要是对数据的操作方法,wrap、get和put,下面的图没有截全,还有好多方法:
![](http://static.oschina.net/uploads/space/2012/1120/200133_nbwW_589742.jpg)
IoBuffer及其相关的类均在org.apache.mina.core.buffer下,IoBuffer定义了buffer使用的规则,AbseractIoBuffer提供了具体的实现:
![](http://static.oschina.net/uploads/space/2012/1120/200208_aeUV_589742.jpg)
IoBuffer没有继承任何类,只是实现了comparable接口,我们注意到IoBuffer类修饰符用的是abstract,跟ByteBuffer也是用abstract修饰,至于为什么要用abstract,我觉得也容易理解,毕竟这是一个要对外直接使用的类,同时需要对实现进行规则和扩展:
1 |
public abstract class IoBuffer implements Comparable<IoBuffer> |
在IoBuffer的一系列代码阅读中,你可以看到抽象类之间的继承,内部类的使用情况等等,后面,我会通过一个删减版的例子来盘点这中间的关系,所以大片的源码就不贴了。
![](http://static.oschina.net/uploads/space/2012/1120/200313_77wA_589742.jpg)
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和其实现类:
![](http://static.oschina.net/uploads/space/2012/1120/200406_8tCI_589742.jpg)
接口很简单,就定义了几个在IoBuffer中已经被static修饰的方法。有两个类都实现了IoBufferAllocator,但是在IoBuffer中使用的是SimpleBufferAllocator:
1 |
/**
The allocator used to create new buffers */ |
2 |
private static IoBufferAllocator
allocator = new SimpleBufferAllocator(); |
4 |
/**
A flag indicating which type of buffer we are using : heap or direct */ |
5 |
private static boolean useDirectBuffer
= false ; |
所以我们主要关注SimpleBufferAllocator:
01 |
public IoBuffer
allocate( int capacity, boolean direct)
{ |
02 |
return wrap(allocateNioBuffer(capacity,
direct)); |
05 |
public ByteBuffer
allocateNioBuffer( int capacity, boolean direct)
{ |
08 |
nioBuffer
= ByteBuffer.allocateDirect(capacity); |
10 |
nioBuffer
= ByteBuffer.allocate(capacity); |
15 |
public IoBuffer
wrap(ByteBuffer nioBuffer) { |
16 |
return new SimpleBuffer(nioBuffer); |
19 |
public void dispose()
{ |
这是接口中定义的几个方法,这里调用内部类SimpleBuffer来生成相应的buffer,又由于SimpleBuffer继承了AbstractIoBuffer,所以真正实现的代码在AbstractIoBuffer中(这里有点儿绕,大家结合上面的图和源码一起读)。而且注意构造方法的protected关键字的使用:
01 |
private ByteBuffer
buf; |
03 |
protected SimpleBuffer(ByteBuffer
buf) { |
04 |
super (SimpleBufferAllocator. this ,
buf.capacity()); |
06 |
buf.order(ByteOrder.BIG_ENDIAN); |
09 |
protected SimpleBuffer(SimpleBuffer
parent, ByteBuffer 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:
01 |
package org.apache.mina.core.rewrite.buffer; |
09 |
public abstract class IoBuffer
{ |
11 |
private static IoBufferAllocator
allocator= new SimpleBufferAllocator(); |
12 |
private static boolean direct; |
14 |
protected IoBuffer()
{ |
18 |
public static IoBuffer
allocate( int capacity)
{ |
19 |
return allocator.allocate(capacity,
direct); |
22 |
public static IoBuffer
wrap( byte []
byteArray, int offset, int length){ |
27 |
public abstract IoBuffer
get(); |
29 |
public abstract IoBuffer
put( byte b); |
31 |
public abstract boolean other(); |
然后是他的继承:
01 |
package org.apache.mina.core.rewrite.buffer; |
03 |
import java.nio.ByteBuffer; |
10 |
public abstract class AbstractIoBuffer extends IoBuffer{ |
12 |
protected AbstractIoBuffer(ByteBuffer
buffer){ |
17 |
public IoBuffer
get() { |
18 |
//
TODO Auto-generated method stub |
23 |
public IoBuffer
put( byte b)
{ |
24 |
//
TODO Auto-generated method stub |
allocator:
01 |
package org.apache.mina.core.rewrite.buffer; |
03 |
import java.nio.ByteBuffer; |
10 |
public interface IoBufferAllocator
{ |
12 |
IoBuffer
allocate( int capacity, boolean direct); |
14 |
IoBuffer
wrap(ByteBuffer nioBuffer); |
16 |
ByteBuffer
allocateNioBuffer( int capacity, boolean direct); |
allocator的实现:
01 |
package org.apache.mina.core.rewrite.buffer; |
03 |
import java.nio.ByteBuffer; |
09 |
public class SimpleBufferAllocator implements IoBufferAllocator{ |
12 |
public IoBuffer
allocate( int capacity, boolean direct)
{ |
13 |
return wrap(allocateNioBuffer(capacity,
direct)); |
17 |
public IoBuffer
wrap(ByteBuffer nioBuffer) { |
19 |
return new SimpleBuffer(nioBuffer); |
23 |
public ByteBuffer
allocateNioBuffer( int capacity, boolean direct)
{ |
26 |
nioBuffer
= ByteBuffer.allocateDirect(capacity); |
28 |
nioBuffer
= ByteBuffer.allocate(capacity); |
34 |
public void dispose()
{ |
35 |
//
TODO Auto-generated method stub |
39 |
private class SimpleBuffer extends AbstractIoBuffer{ |
40 |
@SuppressWarnings ( "unused" ) |
42 |
protected SimpleBuffer(ByteBuffer
buffer){ |
48 |
public boolean other()
{ |
49 |
//
TODO Auto-generated method stub |
55 |
public String
toString() { |
56 |
System.out.println(buffer); |
57 |
return super .toString(); |
最后是测试类和测试结果:
1 |
package org.apache.mina.core.rewrite.buffer; |
4 |
public static void main(String[]
args) { |
5 |
IoBuffer
buffer=IoBuffer.allocate( 1024 ); |
6 |
System.out.println(buffer); |
控制台输出:
1 |
java.nio.HeapByteBuffer[pos= 0 lim= 1024 cap= 1024 ] |
2 |
org.apache.mina.core.rewrite.buffer.SimpleBufferAllocator$SimpleBuffer @1da12fc0 |
-------------------------------------------------------------------
后面一篇应该会将service,就是mina中实现连接的部分,后面的更新速度可能会慢点儿,到后面越来越复杂了,我得想想怎么写才能写的号。最近在弄kafka,其实我还想写点儿kafka的东西,可是真的没有时间,kafka部分等我把分布式的弄完了再发点儿心得上来。大家将就着看吧。谢谢。
- Mina源码阅读笔记(四)—Mina的连接IoConnector2
接着Mina源码阅读笔记(四)-Mina的连接IoConnector1,,我们继续: AbstractIoAcceptor: 001 package org.apache.mina.core.rewr ...
- Mina源码阅读笔记(一)-整体解读
今天的这一节,将从整体上对mina的源代码进行把握,网上已经有好多关于mina源码的阅读笔记,但好多都是列举了一下每个接口或者类的方法.我倒是想从mina源码的结构和功能上对这个框架进行剖析.源码的阅 ...
- Mina源码阅读笔记(七)—Mina的拦截器FilterChain
Filter我们很熟悉,在Mina中,filter chain的用法也类似于Servlet的filters,这种拦截器的设计思想能够狠轻松的帮助我们实现对资源的统一处理.我们先大致连接下mina中的f ...
- Mina源码阅读笔记(六)—Mina异步IO的实现IoFuture
IoFuture是和IoSession紧密相连的一个类,在官网上并没有对它的描述,因为它一般不会显示的拿出来用,权当是一个工具类被session所使用.当然在作用上,这个系列可并不简单,我们先看源码的 ...
- Mina源码阅读笔记(五)—Mina对连接的操作IoSession
IoSession是Mina管理两端的一个重要部分,也是Mina的核心,Session具有了生命周期的概念,它的生命周期和连接时紧密相关的,这点在后面的介绍中会涉及.另外,好像hibernate中也有 ...
- Mina源码阅读笔记(四)—Mina的连接IoConnector1
上一篇写的是IoAcceptor是服务器端的接收代码,今天要写的是IoConnector,是客户端的连接器.在昨天,我们还留下一些问题没有解决,这些问题今天同样会产生,但是都要等到讲到session的 ...
- Mina源码阅读笔记(三)-Mina的连接IoAccpetor
其实在mina的源码中,IoService可以总结成五部分service责任.Processor线程处理.handler处理器.接收器和连接器,分别对应着IoService.IoProcessor.I ...
- werkzeug源码阅读笔记(二) 下
wsgi.py----第二部分 pop_path_info()函数 先测试一下这个函数的作用: >>> from werkzeug.wsgi import pop_path_info ...
- werkzeug源码阅读笔记(二) 上
因为第一部分是关于初始化的部分的,我就没有发布出来~ wsgi.py----第一部分 在分析这个模块之前, 需要了解一下WSGI, 大致了解了之后再继续~ get_current_url()函数 很明 ...
随机推荐
- 分布式内存文件系统Tachyon
UCBerkeley研发的Tachyon(超光子['tækiːˌɒn],名字要不要这么太嚣张啊:)是一款为各种集群并发计算框架提供内存数据管理的平台,也可以说是一种内存式的文件系统吧.如下图,它就处于 ...
- 从嵌入式linux到android应用开发
时间过得很快,转眼之间已经到新公司一个月了.虽然学到了一些移动开发的知识,但是觉得离我的目标还很远,完全没能达到我想要的水平.以前产品都是自己主导的,需要完成什么,计划什么也是自己主导,现在得从头 ...
- java中hashCode()与equals()详解
首先之所以会将hashCode()与equals()放到一起是因为它们具备一个相同的作用:用来比较某个东西.其中hashCode()主要是用在hash表中提高 查找效率,而equals()则相对而言使 ...
- Java-IO之CharArrayWriter(字符数组输出流)
CharArrayWriter用于写数据,数据单位是字符. (1) 通过CharArrayWriter()创建的CharArrayWriter对应的字符数组大小是32. (2) 通过CharArray ...
- JavaI/O体系详解
Java中IO操作主要是指使用Java进行输入,输出操作,Java中所有的IO操作类都存放在Java.io包中,在使用时需要导入此包. 在整个Java.io包中最重要的就是5个类和一个接口.5个类指的 ...
- Android进阶(二十四)Android UI---界面开发推荐颜色
Android UI---界面开发推荐颜色 在Android开发过程中,总要给app添加一些背景,个人认为使用纯色调便可以达到优雅的视觉效果. 补充一些常用的颜色值:colors.xml < ...
- Dynamics CRM2013 sub grid中数据翻页问题
CRM2013中一个很低级很令人无语的BUG,见下图subgrid中的明细条目超过当前页设置的条目后会有翻页,在底下有个paging bar会显示条数.页数.当前所处页数 但sp1版本的CRM打上ur ...
- Linux 句柄是什么 ?
1.句柄就是一个标识符,只要获得对象的句柄,我们就可以对对象进行任意的操作. 2.句柄不是指针,操作系统用句柄可以找到一块内存,这个句柄可能是标识符,map的key,也可能是指针,看操作系统怎么处理的 ...
- java的hashmap与hashtable说明,简单易理解
1. HashMap 1) hashmap的数据结构 Hashmap是一个数组和链表的结合体(在数据结构称"链表散列"),如下图示: 当我们往hashmap中put元素的时候,先根 ...
- android加载大图,防止oom
高效加载大图片 我们在编写Android程序的时候经常要用到许多图片,不同图片总是会有不同的形状.不同的大小,但在大多数情况下,这些图片都会大于我们程序所需要的大小.比如说系统图片库里展示的图片大都是 ...