MINA源码笔记(二)IoBuffer的封装

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

在阅读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数组:

?
1
2
3
4
5
public static ByteBuffer allocate( int capacity) {
     if (capacity < 0 )
         throw new IllegalArgumentException();
     return new HeapByteBuffer(capacity, capacity);
     }

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

?
1
2
3
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,我觉得也容易理解,毕竟这是一个要对外直接使用的类,同时需要对实现进行规则和扩展:

?
1
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

?
1
2
3
4
5
/** 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:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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关键字的使用:

?
1
2
3
4
5
6
7
8
9
10
11
12
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:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
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();
}
然后是他的继承:
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
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:
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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的实现:
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
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();
         }      
     }
}
最后是测试类和测试结果:
?
1
2
3
4
5
6
7
8
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);
     }
}
控制台输出:
?
1
2
java.nio.HeapByteBuffer[pos= 0 lim= 1024 cap= 1024 ]
org.apache.mina.core.rewrite.buffer.SimpleBufferAllocator$SimpleBuffer @1da12fc0
-------------------------------------------------------------------

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

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

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Apache Mina是一个用于开发高性能、高可扩展性网络应用程序的Java框架。它提供了一种简单和灵活的方式来构建基于TCP/IP和UDP/IP协议的客户端和服务器端应用。 在学习Apache Mina时,首先需要了解它的基本概念和架构。Mina采用了NIO(非阻塞IO)的方式来实现网络通信。它的核心组件是IoService,它负责接收客户端的连接请求,并将请求分发给对应的I/O处理器进行处理。而I/O处理器则负责实际的数据读写和业务逻辑的处理。 在使用Mina进行开发时,我们首先需要创建一个IoAcceptor对象来监听指定的端口,并设置相应的处理器。当有客户端发起连接请求时,IoAcceptor会接收并处理这些请求。同时,我们还需要编写相应的I/O处理器来对接收到的数据进行处理和响应。 Mina还提供了一些便捷的工具类和接口,以简化开发过程。例如,可以使用IoBuffer来处理数据的读写,它类似于Java NIO中的ByteBuffer。同时,Mina还提供了一些过滤器,可以在数据传输的过程中进行一些常用的操作,比如加密、压缩、编解码等。 值得一提的是,Mina支持多种编解码协议,包括自定义的协议。它可以根据指定的编解码规则将数据进行解析和组装。这在实际应用中非常实用,因为经常会遇到需要对传输的数据进行编码和解码的情况。 总的来说,学习Apache Mina需要了解其基本概念、架构和核心组件,并掌握基本的开发流程和常用的工具类和接口。通过学习Mina,我们可以更加方便地开发出高性能、高可扩展性的网络应用程序。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值