1.mina将内核和一些特性的联系过于紧密,使得用户在不需要这些特性的时候无法脱离,相比下性能会有所下降;netty解决了这个设计问题;


2.netty的文档更清晰,很多mina的特性在netty里都有;


3.netty更新周期更短,新版本的发布比较快;


4.它们的架构差别不大,mina靠apache生存,而netty靠jboss,和jboss的结合度非常高,netty有对google protocal buf的支持,有更完整的ioc容器支持(spring,guice,jbossmc和osgi);


5.netty比mina使用起来更简单,netty里你可以自定义的处理upstream events 或/和 downstream events,可以使用decoder和encoder来解码和编码发送内容;


6.netty和mina在处理UDP时有一些不同,netty将UDP无连接的特性暴露出来;而mina对UDP进行了高级层次的抽象,可以把UDP当成"面向连接"的协议,而要netty做到这一点比较困难。



运用spring注解实现netty服务器端udp应用程序



netty是JBOSS针对网络开发的一套应用框架,它也是在NIO的基础上发展起来的。netty基于异步的事件驱动,具有高性能、高扩展性等特性,它提供了统一的底层协议接口,使得开发者从底层的网络协议(比如 TCP/IP、UDP)中解脱出来。就使用来说,开发者只要参考 Netty提供的若干例子和它的指南文档,就可以放手开发基于Netty的服务端程序了。

netty有几个比较重要的概念,在此,仅做介绍,详细可以参考netty文档或源码。

1). channelBuffer: Bootstrap 是一个设置服务的帮助类。你甚至可以在这个服务中直接设置一个 Channel 通道。

现在以实现一个UDP协议下的服务器应用程序为例,演示netty通过spring注解开发服务器端。(在此以maven工具管理项目开发)

首先,是导入关联jar的POM文件:


+ expand sourceview plaincopy to clipboardprint? 

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 

 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 

 <modelVersion>4.0.0</modelVersion> 

 <groupId>com.byd.example</groupId> 

 <artifactId>nettyTest</artifactId> 

 <version>0.0.1-SNAPSHOT</version> 

 <packaging>jar</packaging> 

 <name>nettyTest</name> 

 <url>http://maven.apache.org</url> 

 <properties> 

 <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> 

 </properties> 

 <dependencies> 

 <dependency> 

 <groupId>junit</groupId> 

 <artifactId>junit</artifactId> 

 <version>3.8.1</version> 

 <scope>test</scope> 

 </dependency> 

 <dependency> 

 <groupId>slf4j</groupId> 

 <artifactId>slf4j-jdk14</artifactId> 

 <version>1.6.1</version> 

 </dependency> 

 <dependency> 

 <groupId>log4j</groupId> 

 <artifactId>log4j</artifactId> 

 <version>1.2.9</version> 

 </dependency> 

 <dependency> 

 <groupId>org.jboss.netty</groupId> 

 <artifactId>netty</artifactId> 

 <version>3.2.0.BETA1</version> 

 </dependency> 

 <dependency> 

 <groupId>org.springframework</groupId> 

 <artifactId>spring-context</artifactId> 

 <version>3.0.2.RELEASE</version> 

 </dependency> 

 <dependency> 

 <groupId>org.springframework</groupId> 

 <artifactId>spring-expression</artifactId> 

 <version>3.0.2.RELEASE</version> 

 </dependency> 

 <dependency> 

 <groupId>org.springframework</groupId> 

 <artifactId>spring-tx</artifactId> 

 <version>3.0.2.RELEASE</version> 

 </dependency> 

 <dependency> 

 <groupId>org.springframework</groupId> 

 <artifactId>spring-context</artifactId> 

 <version>3.0.2.RELEASE</version> 

 </dependency> 

 </dependencies> 

 <repositories> 

 <repository> 

 <id>repository.jboss.org</id> 

 <url>http://repository.jboss.org/nexus/content/groups/public/</url> 

 <snapshots> 

 <enabled>false</enabled> 

 </snapshots> 

 </repository> 

 </repositories> 

 <build> 


 </build> 

</project> 


接下来是应用程序代码,在本人机器上可以运行并正常工作,如有需要可以试试。 


I、Server接口: 



view plaincopy to clipboardprint? 

package com.byd.example.netty; 

public interface IServer 

{ 

 /** 

 * 启动服务器 

 */ 

 public void start(); 

 /** 

 * 重启程序 

 */ 

 public void restart(); 


 /** 

 * 停止程序运行 

 */ 

 public void stop(); 

} 


 II、ChannelHandler扩张类(继承SimpleChannelHandler): 





view plaincopy to clipboardprint? 

package com.byd.example.netty; 

import java.util.Random; 

import org.apache.log4j.Logger; 

import org.jboss.netty.buffer.ChannelBuffer; 

import org.jboss.netty.buffer.DynamicChannelBuffer; 

import org.jboss.netty.channel.ChannelFutureListener; 

import org.jboss.netty.channel.ChannelHandlerContext; 

import org.jboss.netty.channel.ExceptionEvent; 

import org.jboss.netty.channel.MessageEvent; 

import org.jboss.netty.channel.SimpleChannelHandler; 

import org.springframework.stereotype.Component; 

@Component("receiverHandler") 

public class ReceiverHandler extends SimpleChannelHandler 

{ 

 private static final Logger logger=Logger.getLogger(ReceiverHandler.class.getName()); 


 @Override 

 public void messageReceived(ChannelHandlerContext ctx,MessageEvent e) throws Exception 

 { 

 ChannelBuffer buffer=(ChannelBuffer)e.getMessage(); 

 byte[] recByte=buffer.copy().toByteBuffer().array(); 

 String recMsg=new String(recByte); 

 logger.info("server received:"+recMsg.trim()); 

 Random random=new Random(); 

 int backWord=random.nextInt(10000); 

 ChannelBuffer responseBuffer=new DynamicChannelBuffer(4); 

 responseBuffer.readBytes(backWord); 

 e.getChannel().write(responseBuffer); 

 } 


 @Override 

 public void exceptionCaught(ChannelHandlerContext ctx,ExceptionEvent e) 

 { 

 logger.error(e.getCause()); 

 if(e.getChannel() !=null) 

 { 

 e.getChannel().close().addListener(ChannelFutureListener.CLOSE); 

 } 

 } 

} 


III、ChannelPipelineFactory实现类,包装ChannelHandler,处理I/O事件。 



view plaincopy to clipboardprint? 

package com.byd.example.netty; 

import org.jboss.netty.channel.ChannelPipeline; 

import org.jboss.netty.channel.ChannelPipelineFactory; 

import org.jboss.netty.channel.Channels; 

import org.springframework.beans.factory.annotation.Autowired; 

import org.springframework.beans.factory.annotation.Qualifier; 

import org.springframework.stereotype.Component; 

@Component("serverChannelPipelineFactory") 

public class ServerChannelPipelineFactory implements ChannelPipelineFactory 

{ 

 @Autowired 

 @Qualifier("receiverHandler") 

 private ReceiverHandler handler; 

 @Override 

 public ChannelPipeline getPipeline() throws Exception 

 { 

 ChannelPipeline pipeline=Channels.pipeline(); 

 pipeline.addLast("handler", this.handler); 

 return pipeline; 

 } 

 public void setHandler(ReceiverHandler handler) { 

 this.handler = handler; 

 } 

} 


IV、Iserver接口的实现类。 



+ expand sourceview plaincopy to clipboardprint? 

package com.byd.example.netty; 

import java.net.InetSocketAddress; 

import java.net.SocketAddress; 

import java.util.concurrent.Executors; 

import org.apache.log4j.Logger; 

import org.jboss.netty.bootstrap.ConnectionlessBootstrap; 

import org.jboss.netty.channel.Channel; 

import org.jboss.netty.channel.ChannelFutureListener; 

import org.jboss.netty.channel.socket.DatagramChannelFactory; 

import org.jboss.netty.channel.socket.nio.NioDatagramChannelFactory; 

import org.springframework.beans.factory.annotation.Autowired; 

import org.springframework.beans.factory.annotation.Qualifier; 

import org.springframework.stereotype.Component; 

@Component("serverNettyImpl") 

public class ServerNettyImpl implements IServer { 

 @Autowired 

 @Qualifier("serverChannelPipelineFactory") 

 private ServerChannelPipelineFactory pipelineFactory; 

 private Channel channel; 

 private static final Logger logger = Logger.getLogger(ServerNettyImpl.class 

 .getName()); 

 @Override 

 public void start() { 

 DatagramChannelFactory udpChannelFactory = new NioDatagramChannelFactory( 

 Executors.newCachedThreadPool()); 

 ConnectionlessBootstrap bootstrap = new ConnectionlessBootstrap(udpChannelFactory); 

 bootstrap.setOption("reuseAddress", false); 

 bootstrap.setOption("child.reuseAddress", false); 

 bootstrap.setOption("readBufferSize", 1024); 

 bootstrap.setOption("writeBufferSize", 1024); 

 bootstrap.setPipelineFactory(this.pipelineFactory); 

 SocketAddress serverAddress = new InetSocketAddress(5000); 

 this.channel = bootstrap.bind(serverAddress); 

 logger.info("server start on " + serverAddress); 

 } 

 @Override 

 public void restart() { 

 this.stop(); 

 this.start(); 

 } 

 @Override 

 public void stop() { 

 if (this.channel != null) { 

 this.channel.close().addListener(ChannelFutureListener.CLOSE); 

 } 

 } 

} 


V、应用程序入口: 



+ expand sourceview plaincopy to clipboardprint? 

package com.byd.example; 

import org.springframework.context.ApplicationContext; 

import org.springframework.context.support.ClassPathXmlApplicationContext; 

import com.byd.example.netty.IServer; 

public class NettyTestRun 

{ 

 public static void main( String[] args ) 

 { 

 ApplicationContext context=new ClassPathXmlApplicationContext("classpath*:nettyTest-context.xml"); 

 IServer server=(IServer)context.getBean("serverNettyImpl"); 

 server.start(); 

 } 

} 


VI、context配置文件: 



+ expand sourceview plaincopy to clipboardprint? 

<?xml version="1.0" encoding="UTF-8" ?> 

<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 

 xmlns:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop" 

 xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context" 

 xsi:schemaLocation="http://www.springframework.org/schema/beans


http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd 

 http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd 

 http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> 

 <context:component-scan base-package="com.byd.example"/> 

 <context:annotation-config/> 

</beans> 


 VII、日志配置文件: 



+ expand sourceview plaincopy to clipboardprint? 

<?xml version="1.0" encoding="UTF-8"?> 

<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd" > 

<log4j:configuration xmlns:log4j='http://jakarta.apache.org/log4j/' > 

 <appender name="CONSOLE" class="org.apache.log4j.ConsoleAppender"> 

 <param name="target" value="System.out"/> 

 <layout class="org.apache.log4j.PatternLayout"> 

 <param name="ConversionPattern" value="%d{yyyy-MM-dd HH:mm:ss}-%m%n" /> 

 </layout> 

 <!--过滤器设置输出的级别--> 

 <filter class="org.apache.log4j.varia.LevelRangeFilter"> 

 <param name="levelMin" value="debug" /> 

 <param name="levelMax" value="warn" /> 

 <param name="AcceptOnMatch" value="true" /> 

 </filter> 

</appender> 

 <appender name="FILE" class="org.apache.log4j.RollingFileAppender"> 

 <!-- 设置日志输出文件名 --> 

 <param name="File" value="./target/output.log" /> 

 <!-- 设置是否在重新启动服务时,在原有日志的基础添加新日志 --> 

 <param name="Append" value="true" /> 

 <param name="MaxBackupIndex" value="10" /> 

 <param name="encoding" value="UTF-8"/> 

 <layout class="org.apache.log4j.PatternLayout"> 

 <param name="ConversionPattern" value="%d{yyyy-MM-dd HH:mm:ss}-%m%n" /> 

 </layout> 

 </appender> 

 <appender name="activexAppender" class="org.apache.log4j.DailyRollingFileAppender"> 

 <param name="File" value="./target/activex.log" /> 

 <param name="DatePattern" value="'.'yyyy-MM-dd'.log'" /> 

 <layout class="org.apache.log4j.PatternLayout"> 

 <param name="ConversionPattern" value="%d{yyyy-MM-dd HH:mm:ss}-%m%n" /> 

 </layout> 

 </appender> 


<!-- 

 <logger name="com.runway.bssp.activeXdemo" additivity="false"> 

 <priority value ="info"/> 

 <param name="Level" value="DEBUG"/> 

 <appender-ref ref="activexAppender" /> 

 </logger> --> 



 <!-- 根logger的设置--> 

 <root> 

 <priority value ="debug"/> 

 <appender-ref ref="CONSOLE"/> 

 <appender-ref ref="FILE"/> 

 </root> 

</log4j:configuration>