使用Spring+Maven配置Netty4
原文:http://nerdronix.blogspot.com/2013/06/netty-4-configuration-using-spring-maven.html (需要翻墙)
本文介绍如何使用Spring3.2和Maven配置Netty 4. 源码在github. Spring的配置使用的是纯Java配置没有涉及xml文件. 在本文的最后, 也会有相应的xml文件的配置.
![](http://write.blog.csdn.net/139464_files/113357_IM3U_592601.png)
Netty
为了创建一个netty服务端, 通常我们需要以下几个步骤:
- 创建ServerBootstrap对象
- 设置参数像bossGroup, workerGroup, childHandler以及设置ChannelOption就像keep_alive针对bootstrap.
- 使用bootstrap创建channel.
- 确保可以退出程序, 你调用shutDownGracefully方法或者相似的方法.
现在假设你已经在Spring中创建了bootstrap, 下面这几行代码足够启动服务端以及关闭.
2 | public void start() throws Exception { |
3 | serverChannel = b.bind(tcpPort).sync().channel().closeFuture().sync().channel() |
其中的"b"就是bootstrap通过Spring注入得到. 你可以查看完整代码TCPServer.
Spring
涉及到一点针对Netty的Spring配置. 必须配置ServerBootstrap, ChannelInitializer和ChannelOption以及一些解码器和编码器, 这个例子更加的深入. 这几行代码是Spring配置的说明. 完整代码在SpringConfig
注解
2 | @ComponentScan ( "org.nerdronix" ) |
3 | @PropertySource ( "classpath:netty-server.properties" ) |
4 | public class SpringConfig { ... |
@Configuration注解确保java文件可以像近似于Spring的application-context.xml文件一样的方式处理. 组件扫描特性被用来设置通过Spring将被扫描到的一个或多个包自动装配. 注意任何需要被Spring管理的POJO都应该带上@Component注意或者子注解. 稍后会有更多关于@PropertySource注解.
现在我们往下到第2步, 即真实的bean发生在SpringConfig中的初始化过程.
Bean的创建
下面的代码展示如何创建一个bean.
1 | @Bean (name = "bossGroup" , destroyMethod = "shutdownGracefully" ) |
2 | public NioEventLoopGroup bossGroup() { |
3 | return new NioEventLoopGroup(bossCount); |
@Bean注解被用来表示这个方法将会返回一个bean, 注解的destroyMethod参数意味着Spring退出时将被调用. 这是个可选参数, 连"name"都是可选的. 因此bossCount来自哪里? 我们到第3步, 去解释下.
PropertySource的配置.
Spring3.1引入了一种方法, 即使用下面这两个注解, @PropertySource和@Value, 可以用很简单的方式注意一个bean的属性.
1 | @PropertySource ( "classpath:netty-server.properties" ) |
4 | @Value ( "${boss.thread.count}" ) |
另外对于纯java的配置方案, 你还需要在SpringConfig类中设置接下来的bean, 否则这些不会被@Value注解正确的评估.
2 | * Necessary to make the @Value annotations work. |
6 | public static PropertySourcesPlaceholderConfigurer propertyPlaceholderConfigurer() { |
7 | return new PropertySourcesPlaceholderConfigurer(); |
在netty-server.properties文件中相应的条目是boss.thread.count=2. 注意Spring将自动转换由string到integer, 这种做法针对所有常见数据类型, 所以你不需要调用Integer.valueOf(string).
设置Netty Bootstrap
下面的代码片断展示netty bootstrap如何设置.
01 | @Bean (name = "serverBootstrap" ) |
02 | public ServerBootstrap bootstrap() { |
03 | ServerBootstrap b = new ServerBootstrap(); |
04 | b.group(bossGroup(), workerGroup()) |
05 | .channel(NioServerSocketChannel. class ) |
06 | .childHandler(protocolInitalizer); |
07 | Map, Object> tcpChannelOptions = tcpChannelOptions(); |
08 | Set> keySet = tcpChannelOptions.keySet(); |
09 | for ( @SuppressWarnings ( "rawtypes" ) |
10 | ChannelOption option : keySet) { |
11 | b.option(option, tcpChannelOptions.get(option)); |
protocolInitalizer你可以找到真实的POJO,位于另一个包的 这里. 那么我们如何在SpringConfig类中得到这个bean? 答案是SpringConfig的@Configuration注解也继承了@Component注解意味着SpringConfig也是一个 Spring类, 而且我们可以自动装配其他bean到这个bean, 就像任何其他的普通Spring bean.
下面几行SpringConfig文件中的代码可以做好这件事
2 | @Qualifier ( "springProtocolInitializer" ) |
3 | private StringProtocolInitalizer protocolInitalizer; |
控制反转的好处是所有的bean被默认是单例你不需要花费任何精力, spring的组件扫描功能会负责自动写程序并且使用@PropertySource和@Value注解属性被轻松的注入. 依照接口编程的示例你可以让你的代码成为真正的模块.
Maven
pom相当的清晰; 你需要添加针对Spring, netty和logging的依赖库让他工作. 主要的依赖库会在下面提供, 父级的pom包括所有的版本和常用依赖库.
02 | <groupId>io.netty</groupId> |
03 | <artifactId>netty-all</artifactId> |
04 | <version>${netty.version}</version> |
08 | <groupId>org.springframework</groupId> |
09 | <artifactId>spring-context</artifactId> |
10 | <version>${org.springframework.version}</version> |
最后, 运行!
找到Main类执行他, Netty服务端应该启动并监听在netty-server.properties文件中设置的端口, 即localhost:8090.
我想要XML!
好吧, 你还是在2009年噢! 实际上, 我仍然热爱针对bean的关系图的XML文件并且使用工具构建, 虽然纯Java的选项肯定赢我. 不管怎么样, 在这: 虽然不是完整的例子但是他展示的是最有意义的bean.
02 | <groupId>io.netty</groupId> |
03 | <artifactId>netty-all</artifactId> |
04 | <vers<bean id= "bossGroup" class = "io.netty.channel.nio.NioEventLoopGroup" > |
05 | <constructor-arg type= "int" index= "0" value= "${boss.thread.count}" /> |
06 | <constructor-arg index= "1" ref= "bossThreadFactory" /> |
09 | <bean id= "workerGroup" class = "io.netty.channel.nio.NioEventLoopGroup" > |
10 | <constructor-arg type= "int" index= "0" value= "${worker.thread.count}" /> |
11 | <constructor-arg index= "1" ref= "workerThreadFactory" /> |
14 | <bean id= "bossThreadFactory" class = "org.nerdronix.NamedThreadFactory" > |
15 | <constructor-arg type= "String" value= "Server-Boss" /> |
18 | <bean id= "workerThreadFactory" class = "org.nerdronix.NamedThreadFactory" > |
19 | <constructor-arg type= "String" index= "0" value= "Server-Worker" /> |
23 | <!-- Netty options for server bootstrap --> |
24 | <util:map id= "tcpChannelOptions" map- class = "java.util.HashMap" > |
26 | <key><util:constant static -field= "io.netty.channel.ChannelOption.SO_KEEPALIVE" /></key> |
27 | <value type= "java.lang.Boolean" >${so.keepalive}</value> |
30 | <key><util:constant static -field= "io.netty.channel.ChannelOption.SO_BACKLOG" /></key> |
31 | <value type= "java.lang.Integer" >${so.backlog}</value> |