在阅读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,下面的图没有截全,还有好多方法:
IoBuffer及其相关的类均在org.apache.mina.core.buffer下,IoBuffer定义了buffer使用的规则,AbseractIoBuffer提供了具体的实现:
IoBuffer没有继承任何类,只是实现了comparable接口,我们注意到IoBuffer类修饰符用的是abstract,跟ByteBuffer也是用abstract修饰,至于为什么要用abstract,我觉得也容易理解,毕竟这是一个要对外直接使用的类,同时需要对实现进行规则和扩展:
1 |
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:
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()函数 很明 ...
随机推荐
- JQuery之动画与特效
显示与隐藏 show(spped,[callback])与hide(spped,[callback]) speed可选填slow.normal.fast,对应的速度分别为600ms.400ms.200 ...
- 一个简单的安卓+Servlet图片上传例子
例子比较 简单,服务端为Java Web Servlet,doPost方法中接收图片并保存,然后将保存的图片名返回给客户端,关键代码: @SuppressWarnings("deprecat ...
- 2、Android构建本地单元测试
如果你的单元测试在Android中没有依赖或者只有简单的以来,你可以在你的本地开发环境中运行你的测试.这种测试比较高效因为它能让你避免将整个app安装到物理设备或虚拟机中执行单元测试.最后,执行单元测 ...
- 网页搜索之后的APP搜索
搜索技术是互联网最核心的技术之一.但是移动互联网迅猛发展的今天,互联网产生的数据已经不是简单的网页搜索所能涵盖的了.比如微信公众号,产生了许多优质的内容,如果这些公众号仅仅将这些内容发布到微信平台,那 ...
- 字符串的n位左旋
要求:将主串的某一段(n位)翻转到主串的最后,如:abcdef以2位翻转则结果为:cdefab.要求时间复杂度为O(n),空间复杂度为O(1) 思路一:可以重新定义一个与原串相同大小的字符数组resu ...
- ADFS部署过程中设置network service对证书的读取权限
今儿在部署客户正式环境的ADFS时候遇到一问题,在配置完基于声明的身份验证后通过url访问居然报错了,这干过N回的事怎么会出错了呢,百思不得其解 网页报错如下 系统日志报错如下, 回想过程中的每一步, ...
- PA模块报错-实际返回的行数超出请求的行数(分析标准FORM报错解决思路)
录入预算报错时报错: 分析:这个错误是select into 语句返回多行的结果,但具体在哪? 两种方法查找,trace 或者debug 1.trace 启用调试 获取trace文件 -bash-3. ...
- STL:vector容器用法详解
vector类称作向量类,它实现了动态数组,用于元素数量变化的对象数组.像数组一样,vector类也用从0开始的下标表示元素的位置:但和数组不同的是,当vector对象创建后,数组的元素个数会随着ve ...
- 海量数据挖掘MMDS week2: 频繁项集挖掘 Apriori算法的改进:非hash方法
http://blog.csdn.net/pipisorry/article/details/48914067 海量数据挖掘Mining Massive Datasets(MMDs) -Jure Le ...
- 使用百度地图开发一个导航定位demo-android学习之旅(77)
首先介绍如何导入百度地图 步骤(其实官方文档写的很清楚了)http://developer.baidu.com/map/index.php?title=androidsdk/guide/introdu ...