文档章节

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

Gaischen
 Gaischen
发布于 2012/11/20 20:12
字数 1952
阅读 16642
收藏 63

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

在阅读IoBuffer源码之前,我们先看MinaIoBuffer的描述:A byte buffer used by MINA applications. This is a replacement for ByteBuffer. 这是一个对ByteBufferreplacement,同样是用作缓冲区,做内容的切换和承载的容器,为什么要用重新封装ByteBufferMINA是这么给出解释的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中可以直接putget 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,这块内存的开辟就比较麻烦了,好多都是采用了Bitnative的方法:

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

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

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画了。囧一个,大家有好那种可以一键生成的工具推荐一下,我之前用的是JUDEVisio。上图画出了IoBuffer中几个重要类之间的关系,两个内部类均继承了AbstractIoBufferAbstractIoBufferIoBufferWrapper均实现了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
-------------------------------------------------------------------

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

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

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

© 著作权归作者所有

Gaischen

Gaischen

粉丝 827
博文 55
码字总数 73789
作品 1
杭州
架构师
私信 提问
加载中

评论(16)

xiaopeng187
xiaopeng187
通过这篇博文我可以学到mina是如何扩展一个类(IoBuffer)的功能的。
yak
yak
http://mina.apache.org/mina-project/userguide/ch8-iobuffer/ch8-iobuffer.html

This will change in MINA 3. The main reason why MINA has its own wrapper on top of nio ByteBuffer is to have extensible buffers. This was a very bad decision. Buffers are just buffers : a temporary place to store temporary data, before it is used. Many other solutions exist, like defining a wrapper which relies on a list of NIO ByteBuffers, instead of copying the existing buffer to a bigger one just because we want to extend the buffer capacity.
yak
yak
RECEIVED: HeapBuffer[pos=19 lim=19 cap=19

打印message 是这个
Gaischen
Gaischen 博主

引用来自“wulei163”的评论

一个50M的数据包,一次传 跟 分N多小包多次传 速度差别很大,求解释,filterChain是mina自带的ObjectSerializationCodecFactory

分多次传 网络的开销很内存的开销都会增加的
wulei163
wulei163
一个50M的数据包,一次传 跟 分N多小包多次传 速度差别很大,求解释,filterChain是mina自带的ObjectSerializationCodecFactory
溢晨
溢晨

引用来自“FrankHui”的评论

引用来自“eonezhang”的评论

intellij可以把类托到uml

嗯 intellij 我之前装过,还不错 我到时候 试试看..谢啦

intellij不大适合新手用 太智能了
Gaischen
Gaischen 博主

引用来自“soulsaunter”的评论

加油。

嗯 谢谢 刚写完第三篇 发上来了。。。
soulsaunter
soulsaunter
加油。
沙发迪
沙发迪

引用来自“FrankHui”的评论

引用来自“袁迪”的评论

一定要写完了,千万别太监了!

嗯 好的 呵呵

给力啊,整个网站几十万的兄弟都在看你写的东西。加油!没有别的事情,注意休息。
Gaischen
Gaischen 博主

引用来自“justin_cn”的评论

谢谢博主的无私分享,另外想请教博主一个问题,你打算以什么样的思路来介绍mina框架,从哪些方面来阐述?

在上篇文章 整体解读里 我写到过 我主要是按照 mina的模块来读 这种通信框架也没有实际的业务 所以按模块比较合适 我关注的主要是它整体的组成结构 NIO的封装 和 并发的处理
Mina源码阅读笔记(一)-整体解读

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

Gaischen
2012/11/19
21.7K
19
IoBuffer和ByteBuffer

最近在做通信和传输的项目,大量的使用NIO和Mina,虽然之前一直对这部分比较关注,但是还没有好好的总结一下这方面的内容。今天想写点儿NIO里最基本的一个类ByteBuffer。至于Mina中的IoBuffe...

Gaischen
2012/10/24
10.8K
14
MiNa 实现多人聊天室程序

开发环境: System:Windows JavaSDK:1.6 IDE:eclipse、MyEclipse 6.6 开发依赖库: Jdk1.4+、mina-core-2.0.4.jar、slf4j-api-1.5.11.jar、slf4j-log4j12-1.5.11.jar Email:hoojo_@126.......

ibm_hoojo
2012/08/01
0
0
Mina源码阅读笔记(三)-Mina的连接IoAccpetor

接着上篇《IoBuffer的封装》. 其实在mina的源码中,IoService可以总结成五部分service责任、Processor线程处理、handler处理器、接收器和连接器,分别对应着IoService、IoProcessor、IoHandl...

Gaischen
2012/11/21
10.2K
7
mina read方法出现BufferUnderflowException异常的解决办法

现象: 先连续发几十个很小很小的包(<10 byte) 再突然发一个大小64byte的包 这时你会发现mina就会出现以下错误 经过对mina的分析,这是由对包长度不对做成的(即,我们发的包长是大于64byte的...

JavaGG
2009/02/17
76.8K
1

没有更多内容

加载失败,请刷新页面

加载更多

Spring Boot + Mybatis-Plus 集成与使用(二)

前言: 本章节介绍MyBatis-Puls的CRUD使用。在开始之前,先简单讲解下上章节关于Spring Boot是如何自动配置MyBatis-Plus。 一、自动配置 当Spring Boot应用从主方法main()启动后,首先加载S...

伴学编程
昨天
7
0
用最通俗的方法讲spring [一] ──── AOP

@[TOC](用最通俗的方法讲spring [一] ──── AOP) 写这个系列的目的(可以跳过不看) 自己写这个系列的目的,是因为自己是个比较笨的人,我曾一度怀疑自己的智商不适合干编程这个行业.因为在我...

小贼贼子
昨天
7
0
Flutter系列之在 macOS 上安装和配置 Flutter 开发环境

本文为Flutter开发环境在macOS下安装全过程: 一、系统配置要求 想要安装并运行 Flutter,你的开发环境需要最低满足以下要求: 操作系统:macOS(64位) 磁盘空间:700 MB(不包含 IDE 或其余...

過愙
昨天
6
0
OSChina 周六乱弹 —— 早上儿子问我他是怎么来的

Osc乱弹歌单(2019)请戳(这里) 【今日歌曲】 @凉小生 :#今日歌曲推荐# 少点戾气,愿你和这个世界温柔以待。中岛美嘉的单曲《僕が死のうと思ったのは (曾经我也想过一了百了)》 《僕が死の...

小小编辑
昨天
2.7K
16
Excption与Error包结构,OOM 你遇到过哪些情况,SOF 你遇到过哪些情况

Throwable 是 Java 中所有错误与异常的超类,Throwable 包含两个子类,Error 与 Exception 。用于指示发生了异常情况。 Java 抛出的 Throwable 可以分成三种类型。 被检查异常(checked Exc...

Garphy
昨天
42
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部