简化的关闭
releaseExternalResources() |
有两个方法来配置Netty的Channel的
socket参数。第一个是明确地调用ChannelConfig的setter,例如
SocketChannelConfig.setTcpNoDelay(true)。这是最为类型安全的方法。另外一个是调用
ChannelConfig.setOption()方法。有时候你不得不决定在运行时的时候socket要配置什么选项,同时这个方法在这种情况下有点
不切实际。然而,在3.x里它是容易出错的,因为一个用户必需用一对字符串和对象来指定
选项。如果用户调用了错误的选项名或者值,他或她将会赵宇到一个ClassCastException或指定的选项甚至可能会默默地忽略了。
4.0引入了名为ChannelOption的新的类型,它提供了类型安全地访问socket选项。
ChannelConfig cfg = ...;
// Before:
cfg.setOption("tcpNoDelay", true);
cfg.setOption("tcpNoDelay", 0); // Runtime ClassCastException
cfg.setOption("tcpNoDelays", true); // Typo in the option name - ignored silently
// After:
cfg.setOption(ChannelOption.TCP_NODELAY, true);
cfg.setOption(ChannelOption.TCP_NODELAY, 0); // Compile error
在回应用户指令里,你可以附加任意的对象到
Channel和ChannelHandlerContext。一个名为AttributeMap的新接口被加入了,它被Channel和
ChannelHandlerContext继承。作为替代,ChannelLocal和
Channel.attachment被移除。这些属性会在他们关联的Channel被垃圾回收的同时回收。
public class MyHandler extends ChannelInboundMessageHandlerAdapter<MyMessage> {
private static final AttributeKey<MyState> STATE =
new AttributeKey<MyState>("MyHandler.state");
@Override
public void channelRegistered(ChannelHandlerContext ctx) {
ctx.attr(STATE).set(new MyState());
ctx.fireChannelRegistered();
}
@Override
public void messageReceived(ChannelHandlerContext ctx, MyMessage msg) {
MyState state = ctx.attr(STATE).get();
}
...
}
bootstrap API已经重头重写,尽管它的目的还是一样;它执行需要使服务器或客户端运行的典型步骤,通常能在样板代码里找到。新的bootstrap同样采取了流畅的接口。
public static void main(String[] args) throws Exception {
// Configure the server.
ServerBootstrap b = new ServerBootstrap();
try {
b.group(new NioEventLoopGroup(), new NioEventLoopGroup())
.channel(new NioServerSocketChannel())
.option(ChannelOption.SO_BACKLOG, 100)
.localAddress(8080)
.childOption(ChannelOption.TCP_NODELAY, true)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(handler1, handler2, ...);
}
});
// Start the server.
ChannelFuture f = b.bind().sync();
// Wait until the server socket is closed.
f.channel().closeFuture().sync();
} finally {
// Shut down all event loops to terminate all threads.
b.shutdown();
}
}
ChannelPipelineFactory → ChannelInitializer和你在上面的例子注意到的一样,ChannelPipelineFactory不再存在了。而是由ChannelInitializer来替换,它给予了在Channel和ChannelPipeline的配置的更多控制。 请注意,你不能自己创建一个新的ChannelPipeline。通过观察目前为止的用例报告,Netty项目队伍总结到让用户去创建自己的管道实现或者是继承默认的实现是没有好处的。 因此,ChannelPipeline不再让用户创建。ChannelPipeline由Channel自动创建。 |
ChannelFuture拆分为ChannelFuture和ChannelPromiseChannelFuture已经被拆分为ChannelFuture和ChannelPromise了。这不仅仅是让异步操作里的生产者和消费者间的约定更明显,同样也是得在使用从链中返回的ChannelFuture更加安全,因为 ChannelFuture的状态是不能改变的。 由于这个编号,一些方法现在都采用ChannelPromiser而不是ChannelFuture来改变它的状态。 |
良好定义的线程模型在3.x里并没有良好设计的线程模型,尽管曾经要修复线程模型在3.5的不一致性。4.0定义的一个严格的线程模型来帮助用户编写ChannelHandler而不必担心太多关于线程安全的东西。
|
不再有ExecutionHandler ——它包含到核心里在你加入一个ChannelHandler到一个ChannelPipeline来告诉管道总是通过指定的EventExecutor调用加入的ChannelHander处理器的方法的时候,你可以指定一个 EventExecutor。 Channel ch = ...; EventExecutor是EventLoop的超类,同时也继承了ScheduledExecutorService。 fixme 编码解码器框架变化在编码解码器框架里有实质性的内部改变,因为4.0需要一个处理器来创建和管理它的缓存(看这篇文章的每个处理器缓存部分。)然而,从用户角度来看这些变化都不是很大的。
|
编码解码器嵌入器→ EmbeddedChannel编码解码器嵌入器已经被 io.netty.channel.embedded.EmbeddedByteChannel和EmbeddedMessageChannel替换了。EmbeddedChannel允许用户对任何包含编码解码器的管道进行单元测试。 HTTP编码解码器HTTP解码器现在在每个HTTP消息中总生成多个消息对象: 1 * HttpRequest / HttpResponse 要看更多的细节,请到转到已更新了的HttpSnoopServer例子。如果你希望为一个单一的HTTP消息处理多个消息,你可以把HttpObjectAggregator放入管道里。 HttpObjectAggregator会把多个消息转换为 一个单一的FullHttpRequest或是FullHttpResponse。 传输实现的变化下面是传输协议新加入的东西:
|
用例学习:移植示例Factorial这部分粗略地展示把示例Factorial从3.0移植到4.0的步骤。示例Factorial已经移植到4.0了,它放在io.netty.example.factorial包里。请浏览示例的源代码来看下每一处的变化。 移植服务端
|
大部分和移植服务端差不多,但你要在你编写一个潜在的大数据流时要多注意下。
private void sendNumbers() {
// Do not send more than 4096 numbers.
boolean finished = false;
MessageBuf<Object> out = ctx.nextOutboundMessageBuffer();
while (out.size() < 4096) {
if (i <= count) {
out.add(Integer.valueOf(i));
i ++;
} else {
finished = true;
break;
}
}
ChannelFuture f = ctx.flush();
if (!finished) {
f.addListener(numberSender);
}
}
private final ChannelFutureListener numberSender = new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future) throws Exception {
if (future.isSuccess()) {
sendNumbers();
}
}
};