Apache MINA 2.x提供了一个全新的API,其抛弃向后兼容1.x。2.x简化了先前API中过于复杂的部分,在牺牲某种程度的向后兼容性后变得更直观。请注意,本节仅仅解释不兼容的改变,因为API的大部分还是向后兼容的。
包与命名
l 所有的类和方法严格遵循驼峰命名法则
例如SSLFilter被更名为SslFilter,其它很多类也是如此。
l 所有NIO传输类增加‘Nio’前缀
由于NIO并非socket/datagram传输的唯一实现,因此‘Nio’前缀加在了所有的NIO传输类上。
改变之前:
SocketAcceptor acceptor = new SocketAcceptor();
改变之后:
SocketAcceptor acceptor = new NioSocketAcceptor();
l Filter类被重新整理到多个子包中
随着开箱即用的filter实现数量的增加,所有的filter都被移到相应的子包中(例如,StreamWriteFilter移至org.apache.mina.filter.stream)。
l *.support中的所有类被移到了其父包(或者其它包)中
为了避免循环依赖,*.support包中的所有类被移到其父包或其它包中。你可以在IDE(例如Eclipse)中简单地修改这些包的导入来解决编译错误。
Buffers
l MINA ByteBuffer重命名为IoBuffer
因为MINA ByteBuffer与JDK中NIO ByteBuffer同名,很多用户发现与其组员沟通时存在很多困难。根据用户的反馈,我们将MINA ByteBuffer重命名为IoBuffer,这样类名就更加简化和明确。
l Buffer池被移除,IoBuffer.allocate(int) 默认分配一个堆(heap) buffer
1. 不再有易犯错的acquire()与release()方法,如果你愿意,你可以调用free()方法,但这是可选的。请自己承担使用这个方法的风险。
2. 在大多数JVM中更好的开箱即用的性能和稳定性。
Direct buffer池是MINA早期版本所标榜的众多特性之一。然而根据当今基准,在主流的JVM中direct buffers的表现要比heap buffers差。此外,当direct buffer 内存的最大值没有被正确设定时,突如其来的OutOfMemoryError经常出现。
为了提供更好的开箱即用的性能和稳定性,Apache MINA项目组决定将默认的buffer类型由direct改为heap。因为heap buffers并不需要池化,PooledByteBufferAllocator也被移除了。由于没有了池的概念,ByteBuffer.acquire() 和 ByteBuffer.release()也就被移除了。
然而,如果分配发生的太快,分配heap buffers也会成为瓶颈。这是因为任何字节数组的分配都要填充其元素内容为0,而这会消耗大量的内存带宽。CachedBufferAllocator可以用来解决这个问题,但是在大多数情况下,你还是应该使用默认的SimpleBufferAllocator。
启动和配置
IoService的配置被简化
在1.x中,有很多种方式来配置IoService和它的子接口(如IoAcceptor和IoConnector)。基本上,有两种配置方式:
1. 调用bind()或connect()时,具体指定一个IoServiceConfig
SocketAcceptor acceptor = new SocketAcceptor();
SocketAcceptorConfig myServiceConfig = new SocketAcceptorConfig();
myServiceConfig.setReuseAddress(true);
acceptor.bind(myHandler, myServiceConfig);
2. 使用IoService.defaultConfig属性,不需要指定一个IoServiceConfig
SocketAcceptor acceptor = new SocketAcceptor();
acceptor.getDefaultConfig().setReuseAddress(true);
acceptor.bind(new InetSocketAddress(8080), myHandler);
配置IoFilterChain带来另一个令人头痛的问题,因为除了IoServiceConfig内部的IoFilterChainBuilder外,还有一个全局的IoFilterChainBuilder,这就意味着使用两个IoFilterChainBuilders来配置一个IoFilterChain。大多数用户仅使用全局的IoFilterChainBuilder来配置IoFilterChain,而这就足够了。
IoAcceptor acceptor = new SocketAcceptor(); acceptor.getFilterChain().addLast("myFilter1", new MyFisrtFilter()); acceptor.getDefaultConfig().getFilterChain().addLast("myFilter2", new MySecondFilter()); acceptor.bind(new InetSocketAddress(8080), myHandler); // Which filter will be the first? |
为了解决这一复杂问题,MINA 2.0简化了网络应用程序的启动,请比较下面的代码与前面代码的不同。
SocketAcceptor acceptor = new SocketAcceptor(); acceptor.setReuseAddress(true); acceptor.getFilterChain().addLast("myFilter1", new MyFirstFilter()); acceptor.getFilterChain().addLast("myFilter2", new MySecondFilter()); acceptor.getSessionConfig().setTcpNoDelay(true);
// You can specify more than one addresses to bind to multiple addresses or interface cards. acceptor.setLocalAddress(new InetSocketAddress(8080)); acceptor.setHandler(myHandler);
acceptor.bind();
// New API restricts one bind per acceptor, and you can't bind more than once. // The following statement will raise an exception. acceptor.bind(); |
你可能已经注意与Spring框架的集成也将变得更加简单。
线程
l ThreadModel被移除
最初引入ThreadModel概念是为了简化IoService使用预定义线程模型的过程。然而,配置线程模型变得越来越简单以至于不用引入新的组件。与其易用性相比,线程模型带了更多的混乱。在2.x中,当且仅当你需要时,你才需要明确地添加一个ExecutorFilter。
l ExecutorFilter使用一个特定的Executor实现来维系事件顺序
在1.x中,可以使用任意指定的Executor来维系事件顺序,但2.x提供了两个新的ThreadPoolExecutor实现,OrderedThreadPoolExecutor和UnorderedThreadPoolExecutor。ExecutorFilter维系事件顺序,在以下两种情况:
1. 当使用默认构造方法时,ExecutorFilter创建一个OrderedThreadPoolExecutor,或者
2. 明确指明使用OrderedThreadPoolExecutor时
OrderedThreadPoolExecutor和UnorderedThreadPoolExecutor具有防止发生OutOfMemoryError的机制,所以你应该尽量使用这两个类而不是其它Executor的实现。
协议编解码
DemuxingProtocolCodecFactory被重写
新增了DemuxingProtocolEncoder和DemuxingProtocolDecoder两个类,DemuxingProtocolCodecFactory只是这两个类的门面。register() 方法重命名为addMessageEncoder() 和addMessageDecoder(),这个变化给编解码器的实现者以更多的自由混合使用不同的encoders和decoders。
MessageEncoder接口也发生了改变,MessageEncoder.getMessageTypes()被移除了,当调用addMessageEncoder()时,你需要指明encoder可编码的信息类型。
集成
l JMX集成被重写
大部分旧有代码被抛弃,JMX集成完全重写。现在的JMX集成模块基于MBean模型并使用OGNL管理属性。
请参考“Image Server”例子了解JMX集成的细节。
l Spring集成简化了
Spring集成也大为重写和简化,下面给出变化的摘要:
1. 包org\apache\mina\integration\spring\ssl被移除。
2. org.apache.mina.integration.spring包更名为org.apache.mina.integration.xbean,目的是与Spring脱钩从而也支持其它的DI框架。
3. 新的集成构建于集成Bean包,如上所述。
请参考“Chat example”例子了解最新的Spring集成的细节。
其它的改变
l TransportType更名为TransportMetadata
TransportType改名是因为它的角色是元数据而不仅仅是一个枚举。
l IoSessionLogger被重写
目前,IoSessionLogger实现了SLF4J Logger接口,所以你可以像声明SLF4J logger实例一样声明它,这个变化使你不必向其它不必要的部分暴露IoSessionLogger对象。另外,在使用MDC(Mapped Diagnostic Context)时,请考虑使用简单的 MdcInjectionFilter,这时IoSessionLogger是没有必要的。
改变之前:
IoSessionLogger.debug(session, ...);
改变之后:
Logger logger = IoSessionLogger.getLogger(session);
logger.debug(...);
l BroadcastIoSession被合并到IoSession中
ReadThrottleFilterBuilder被ReadThrottleFilter替代并最终被移除。