Mina源码阅读笔记(二)- IoBuffer的封装 – A2 Studio – 开源中国社区

【说明】 本文转载自:http://my.oschina.net/ielts0909/blog/90584

http://blog.weirong.li/wp-content/uploads/2016/09/8369f17f-aa33-436d-9a88-f326b968730f Mina源码阅读笔记(二)- IoBuffer 的封装

59人收藏此文章, 我要收藏 发表于11个月前(2012-11-20 20:12) , 已有6267次阅读 ,共11个评论

上一篇《整体解读》 的延续

在阅读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) {

2 if (capacity < 0)

3 throw new IllegalArgumentException();

4 return new HeapByteBuffer(capacity, capacity);

5 }

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

1 public static ByteBuffer allocateDirect(int capacity) {

2 return new DirectByteBuffer(capacity);

3 }

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

http://blog.weirong.li/wp-content/uploads/2016/09/b6205d08-91a9-481a-9bbc-60f910ce7422

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

http://blog.weirong.li/wp-content/uploads/2016/09/6e6ce085-68c0-4150-bae7-6ea2640a7d6b

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

1 public abstract class IoBuffer implements Comparable<IoBuffer>

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

http://blog.weirong.li/wp-content/uploads/2016/09/2c834d9b-9de7-4da9-94ae-5af346001a05

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

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

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

http://blog.weirong.li/wp-content/uploads/2016/09/fb285226-2052-4c77-b2ea-8176354dba8c

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

1 /** The allocator used to create new buffers */

2 private static IoBufferAllocator allocator = new SimpleBufferAllocator();

3

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

03 }

04

05 public ByteBuffer allocateNioBuffer(int capacity, boolean direct) {

06 ByteBuffer nioBuffer;

07 if (direct) {

08 nioBuffer = ByteBuffer.allocateDirect(capacity);

09 } else {

10 nioBuffer = ByteBuffer.allocate(capacity);

11 }

12 return nioBuffer;

13 }

14

15 public IoBuffer wrap(ByteBuffer nioBuffer) {

16 return new SimpleBuffer(nioBuffer);

17 }

18

19 public void dispose() {

20 // Do nothing

21 }

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

01 private ByteBuffer buf;

02

03 protected SimpleBuffer(ByteBuffer buf) {

04 super(SimpleBufferAllocator.this, buf.capacity());

05 this.buf = buf;

06 buf.order(ByteOrder.BIG_ENDIAN);

07 }

08

09 protected SimpleBuffer(SimpleBuffer parent, ByteBuffer buf) {

10 super(parent);

11 this.buf = buf;

12 }

看到了吧,底层还是用的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;

02

03 /**

04 * IoBuffer

05 *

06 * @author ChenHui

07 *

08 */

09 public abstract class IoBuffer {

10

11 private static IoBufferAllocator allocator=new SimpleBufferAllocator();

12 private static boolean direct;

13

14 protected IoBuffer() {

15 // do nothing

16 }

17

18 public static IoBuffer allocate(int capacity) {

19 return allocator.allocate(capacity, direct);

20 }

21

22 public static IoBuffer wrap(byte[] byteArray, int offset, int length){

23 //TODO

24 return null;

25 }

26

27 public abstract IoBuffer get();

28

29 public abstract IoBuffer put(byte b);

30

31 public abstract boolean other();

32 }

然后是他的继承:

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

02

03 import java.nio.ByteBuffer;

04

05 /**

06 *

07 * @author ChenHui

08 *

09 */

10 public abstract class AbstractIoBuffer extends IoBuffer{

11

12 protected AbstractIoBuffer(ByteBuffer buffer){

13 //TODO

14 }

15

16 @Override

17 public IoBuffer get() {

18 // TODO Auto-generated method stub

19 return null;

20 }

21

22 @Override

23 public IoBuffer put(byte b) {

24 // TODO Auto-generated method stub

25 return null;

26 }

27

28

29 }

allocator:

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

02

03 import java.nio.ByteBuffer;

04

05 /**

06 *

07 * @author ChenHui

08 *

09 */

10 public interface IoBufferAllocator {

11

12 IoBuffer allocate(int capacity, boolean direct);

13

14 IoBuffer wrap(ByteBuffer nioBuffer);

15

16 ByteBuffer allocateNioBuffer(int capacity, boolean direct);

17

18 void dispose();

19

20 }

allocator的实现:

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

02

03 import java.nio.ByteBuffer;

04 /**

05 *

06 * @author ChenHui

07 *

08 */

09 public class SimpleBufferAllocator implements IoBufferAllocator{

10

11 @Override

12 public IoBuffer allocate(int capacity, boolean direct) {

13 return wrap(allocateNioBuffer(capacity, direct));

14 }

15

16 @Override

17 public IoBuffer wrap(ByteBuffer nioBuffer) {

18

19 return new SimpleBuffer(nioBuffer);

20 }

21

22 @Override

23 public ByteBuffer allocateNioBuffer(int capacity, boolean direct) {

24 ByteBuffer nioBuffer;

25 if (direct) {

26 nioBuffer = ByteBuffer.allocateDirect(capacity);

27 } else {

28 nioBuffer = ByteBuffer.allocate(capacity);

29 }

30 return nioBuffer;

31 }

32

33 @Override

34 public void dispose() {

35 // TODO Auto-generated method stub

36

37 }

38

39 private class SimpleBuffer extends AbstractIoBuffer{

40 @SuppressWarnings("unused")

41 ByteBuffer buffer;

42 protected SimpleBuffer(ByteBuffer buffer){

43 super(buffer);

44 this.buffer=buffer;

45 }

46

47 @Override

48 public boolean other() {

49 // TODO Auto-generated method stub

50 return false;

51 }

52

53 /**这里重写是为了打印方便*/

54 @Override

55 public String toString() {

56 System.out.println(buffer);

57 return super.toString();

58 }

59 }

60 }

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

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

2

3 public class Test {

4 public static void main(String[] args) {

5 IoBuffer buffer=IoBuffer.allocate(1024);

6 System.out.println(buffer);

7 }

8 }

控制台输出:

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部分等我把分布式的弄完了再发点儿心得上来大家将就着看吧。谢谢。

——————————————————————–

转个面试题,北京一家做视频公司的算法题:《一道面试题》 , @ppdep 已经有答案了这题的第二问还是很有挑战的,大家可以去看看。

声明:OSCHINA 博客文章版权属于作者,受法律保护未经作者同意不得转载。

page 2

上一篇《整体解读》 的延续

在阅读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);    }

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

http://blog.weirong.li/wp-content/uploads/2016/09/b6205d08-91a9-481a-9bbc-60f910ce7422

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

http://blog.weirong.li/wp-content/uploads/2016/09/6e6ce085-68c0-4150-bae7-6ea2640a7d6b

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

public abstract class IoBuffer implements Comparable<IoBuffer>

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

http://blog.weirong.li/wp-content/uploads/2016/09/2c834d9b-9de7-4da9-94ae-5af346001a05

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

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

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

http://blog.weirong.li/wp-content/uploads/2016/09/fb285226-2052-4c77-b2ea-8176354dba8c

接口很简单,就定义了几个在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

——————————————————————-

后面一篇应该会将service,就是mina中实现连接的部分,后面的更新速度可能会慢点儿,到后面越来越复杂了,我得想想怎么写才能写的号最近在弄kafka,其实我还想写点儿kafka的东西,可是真的没有时间,kafka部分等我把分布式的弄完了再发点儿心得上来大家将就着看吧。谢谢。

——————————————————————–

转个面试题,北京一家做视频公司的算法题:《一道面试题》 , @ppdep 已经有答案了这题的第二问还是很有挑战的,大家可以去看看。

此条目发表在Uncategorized分类目录,贴了标签。将固定链接加入收藏夹。