ナビゲーションをスキップ

Netty 5 移行ガイド

このページはGithub Wikiページから自動生成されていることをご存知ですか? こちらから自分で改善できます!

Netty 5 移行ガイド

パッケージ

Netty 5とNetty 4を同じクラスパス上に共存させるために、Netty 5クラスのパッケージ名をio.netty5.*に変更しました。

バッファ

Netty 5では、ByteBufよりもシンプルで安全な新しいバッファAPIが導入されました。

容量

Netty 4.1のByteBufは、書き込み時に必要に応じて、特定の最大容量に達するまで自動的に容量を拡張します。

新しいBuffer APIでは、この動作は行われなくなり、容量と最大容量の区別もなくなりました。代わりに、適切なサイズのバッファを割り当てる(サイズの引数は必須になりました)か、必要に応じてensureWritable()を呼び出す必要があります。ensureWritable()メソッドは、単一のメモリコピーでコンパクション(旧discardReadBytes()と同じ)と拡張を同時に実行できる引数も受け入れるようになりました。

アダプター

2つのAPI間の変換を行い、すべてのハンドルと関連コードの移行が完了するまで共存できるようにするアダプターセットが含まれています。

ByteBufBuffer.wrap()メソッドはByteBufインスタンスを受け取り、新しいAPIのバッファインスタンスであるBufferを返します。逆に、ByteBufAdaptor.intoByteBufメソッドはBufferを受け取り、ByteBufを返します。これらのメソッドはどちらも可能な限り効率的な方法で変換を行い、複数回の変換はアダプターのネストを避けるために互いに打ち消し合います。

異なるAPIに依存するハンドルの間にパイプラインに挿入できるBufferConversionHandlerも含まれています。BufferConversionHandlerは、ByteBufHolderまたはBufferHolderオブジェクトを変換できません。BufferまたはByteBufインスタンスを含むオブジェクトは、例えばカスタムMessageToMessageCodecを使用して変換する必要があります。

APIの変更

新しいBuffer APIの重要な違いは、エイリアシングが許可されなくなったことです。エイリアシングとは、2つ以上のバッファオブジェクトが同じ基となるメモリを参照することです。つまり、slice()duplicate()などのメソッドは使用できなくなりました。一方、ライフサイクルの処理が簡素化され、参照カウントをAPIから完全に削除できます。

slice()duplicate()、およびそれらのretain*バリアント、およびretain()メソッドファミリを使用していた場所では、代わりにsplit()readSplit()、およびcopy()を使用します。

splitメソッドファミリはslice()に似ていますが、バッファの端でのみスライスでき、返されたバッファスライスは元のバッファから削除されるため、エイリアシングを防ぎます。

retain()メソッドとrelease()メソッドはなくなりました。代わりにバッファにはclose()メソッドがあり、これはバッファのライフタイムの最後に呼び出されます。バッファは、バッファのスコープとライフタイムが完全にローカルである場合の便宜のためにAutoCloseableを実装しています。

retain()が使用されていたほとんどの場所は、事実上、スーパークラスまたはサブクラスの無条件のrelease()の効果をキャンセルするためでした。これらのケースでは、通常、バッファの読み取り可能なセクションの受け渡しに関与するため、split()を使用できます。split()は、それぞれ閉じなければならない2つのバッファになります。

バッファの「所有権」が場所間で移動することを型システムでエンコードするために使用できる新しいsend()メソッドがあります。たとえば、これはCompositeBufferファクトリメソッドによって、複合バッファがコンポーネントバッファへの排他的アクセスを取得することを保証するために使用されます。これにより、バッファ合成によるエイリアシングを防ぎます。

バッファは常にビッグエンディアンになり、*LEアクセサーメソッドはなくなりました。リトルエンディアンの読み取りまたは書き込みを実行するには、ビッグエンディアンの読み取りまたは書き込みと組み合わせて、IntegerまたはLongreverseBytesメソッドを使用します。

Future / Promise

ChannelFuture / ChannelPromiseの削除

APIと型階層を簡素化するために、ChannelFuture / ChannelPromise(およびそのすべてのサブタイプ/実装)を完全に削除することにしました。代替として、Future<Void>Promise<Void>を直接使用します。

ProgressiveFuture / ProgressivePromiseとChannelProgressiveFuture / ChannelProgressivePromiseの削除

Progressive*Future / Progressive*Promiseのサポートは、Netty 5で完全に削除されました。これは、場合によっては役立つ可能性がありますが、パイプライン内のすべてのハンドラが、Promiseをチェーンする場合に特別なアクションを実行する必要があるためです。実際にはそうではなく、実際に行うのは非常に面倒です。

上記の理由から、この機能はあまり使用されていなかったため、この機能を完全に削除するのが最善であると判断しました。「時々」しか機能しないものよりも、全くサポートしない方が良いでしょう。これにより、維持するコードも少なくなります。

VoidChannelPromiseの削除

Netty 4.1.xでは、voidPromise()メソッドを使用して、さまざまなIO操作(writeなど)に使用できる特別なChannelPromise実装を取得し、作成されるオブジェクトの数を減らすことができました。この機能の動機は良かったのですが、この特別なChannelPromiseは実際には多くの問題を引き起こすことが判明しました。

PromiseとFutureへのAPI変更

  • Future.addListeners()Future.removeListeners()、およびFuture.removeListener()は削除されました。以前に追加されたリスナーを削除する機能を削除しました。この機能は実際には使用されていなかったため、複雑さを軽減し、APIサーフェースを削減することができました。
  • Futureが完了していて失敗しているかどうかを確認するFuture.isFailed()メソッドが追加されました。これは、Futureが完了していて成功しているかどうかを確認する既存のFuture.isSuccess()と同様です。
  • 既存のFutureに基づいて新しいFutureを簡単に構成および作成できるFuture.map()メソッドとFuture.flatMap()メソッドが追加されました。これらのメソッドは、伝播を通じてエラーとキャンセルを適切に処理します。
  • CompletionStageに変換するための新しいメソッドが追加され、他のAPIとの相互運用が容易になりました。
  • Futureインターフェースからすべてのブロッキングメソッドが削除されました。これは、人々が誤ってこれらを使用し、EventLoopをブロックすることが容易だったためです。EventLoopの外側からブロックする必要がある場合は、Future.asStage()を使用してFutureを変換する必要があります。返されたFutureCompletionStageはブロッキングメソッドを提供します。

チャネル

Channel.eventLoop()Channel.executor()に名前変更されました

Netty 5.xでは、ChannelOutboundInvokerexecutor()メソッドを追加しました。このメソッドはEventExecutorを返すため、ChannelからeventLoop()メソッドを削除し、Channelに対してEventLoopを返すようにexecutor()をオーバーライドすることにしました。

戻り値の型がChannelFutureからFuture<Void>に変更されました

ChannelFuture / ChannelPromiseを削除したため、メソッドの戻り値の型もFuture<Void>に変更しました。

ハーフクロージャ

Netty 5は、そのコアにハーフクロージャのサポートを組み込んでいます。そのため、ChannelHandler.shutdownChannelHandler.channelShutdownが導入されました。これに加えて、Channel.isShutdown(...)ChannelOutboundInvoker.shutdown(...)も追加されました。これは、完全に削除された古いDuplexChannel抽象化に取って代わります。詳細については、プルリクエスト#12468を参照してください。

ChannelHandlerContextAttributeMapを拡張しなくなりました

ChannelHandlerContextAttributeMapを拡張しなくなりました。属性を使用する場合は、AttributeMapを拡張するChannelを直接使用してください。

Channel.Unsafeの削除

Channel.Unsafeインターフェースは完全に削除されたため、エンドユーザーが内部を混乱させることはできなくなりました。

ChannelOutboundBufferChannel APIの一部ではなくなりました

ChannelOutboundBufferは、AbstractChannel実装の実装の詳細であるため、Channel自体から完全に削除されました。

Channel.beforeBeforeWritable()が削除され、Channel.bytesBeforeUnwritable()writableBytes()に名前変更されました。

全く使用されていなかったためChannel.beforeBeforeWritable()メソッドを削除し、Channel.bytesBeforeUnwritable()Channel.writableBytesに名前変更しました。

ChannelPipeline

ChannelPipeline.add*(EventExecutorGroup...)の削除

Netty 4.xでは、明示的なEventExecutorGroupを使用してChannelHandlerChannelPipelineに追加する機能を追加しました。これは良いアイデアのように思えましたが、ライフサイクルに関してかなりの問題があることが判明しました。

  • handlerRemoved(...)handlerAdded(...)が「間違ったタイミング」で呼び出される可能性があります。これは多くの問題を引き起こす可能性があります。最悪の場合、handlerRemoved(...)が呼び出され、ハンドラはハンドラがもう使用されないと予想してネイティブメモリを解放する可能性があります。ここで起こりうることは、それが呼び出された後にchannelRead(...)が呼び出され、以前解放されたメモリにアクセスしようとしてJVMがクラッシュすることです。
  • パイプラインの同時アクセス/変更に関して「可視性」を正しく実装することも非常に問題です。

これを考慮して、ユーザーが主に望んでいるのは、着信メッセージを別のスレッドで処理してビジネスロジックを処理することであることに気付きました。これは、ユーザーがいつ何を破棄できるかをよりよく把握しているため、ユーザーが提供するカスタム実装で実行する方が適切です。

戻り値の型がChannelFutureからFuture<Void>に変更されました

ChannelFuture / ChannelPromiseを削除したため、メソッドの戻り値の型もFuture<Void>に変更しました。

ChannelHandler

Netty 5は、ChannelHandlerの型階層を大幅に簡素化しました。

簡素化されたハンドラ型階層

ChannelInboundHandlerChannelOutboundHandlerは[ChannelHandler]にマージされました。[ChannelHandler]には、インバウンドハンドラメソッドとアウトバウンドハンドラメソッドの両方があります。ChannelPromiseを受け取るすべてのアウトバウンドメソッドは、Future<Void>を返すように変更されました。この変更により、使用がエラーになりにくくなり、APIが簡素化されます。

ChannelInboundHandlerAdapterChannelOutboundHandlerAdapter、およびChannelDuplexHandlerAdapterは削除され、[ChannelHandlerAdapter] に置き換えられました。

ハンドラーが入力ハンドラーか出力ハンドラーかを判別できなくなったため、CombinedChannelDuplexHandlerは[ChannelHandlerAppender]に置き換えられました。

この変更に関する詳細については、プルリクエスト #1999 を参照してください。

channelRead0()messageReceived()

[SimpleChannelInboundHandler]を使用している場合は、channelRead0()messageReceived()に名前を変更する必要があります。

ユーザーイベント

パイプラインを通して双方向にユーザー/カスタムイベントを発生させることが可能になりました。入力イベントにはfireChannelInboundEvent(...)fireUserEventTriggered(...)の代替)、出力イベントにはsendOutboundEvent(...)を使用します。これらはどちらも、通常のChannelHandlerで定義されたメソッドによってインターセプトできます。

ChannelHandler.pendingOutboundBytes(...)メソッドの追加

ChannelPipeline内のChannelHandlerによって、Channelの書き込み可能性に影響を与えることが容易になりました。これにより、ChannelHandler自体が出力データをバッファリングする場合のバックプレッシャーに影響を与えることができます。

EventLoopGroup / EventLoop

Netty 4.xでは、さまざまなトランスポート(つまり、NioEventLoopGroupEpollEventLoopGroupなど)に対して異なるEventLoopGroup/EventLoopの実装がありましたが、Netty 5では、MultiThreadEventLoopGroupと呼ばれる単一EventLoopGroup実装に変更されました。このMultiThreadEventLoopGroupは、トランスポート固有のIoHandlerFactory(つまり、NioHandler.newFactory()EpollHandler.newFactory()など)を受け取ります。この変更により、多くの利点があります。たとえば、MultiThreadEventLoopGroupを容易に拡張して、機能を装飾したり、カスタムメトリクスを追加したりすることができます。この実装は、さまざまなトランスポートで再利用できます。これは、カスタマイズの可能性という点で、JDKがThreadPoolExecutorで提供するものと非常に似ています。

EventLoopGroup.isCompatible(...)メソッドの追加

使用する前に、ChannelサブタイプがEventLoopGroup/EventLoopと互換性があるかどうかを確認できるようになりました。これにより、適切なChannelサブタイプを選択できます。

EventLoop.registerForIo(...)およびEventLoop.deregisterForIoの追加

Channelの登録と登録解除を可能にするために、EventLoopインターフェースに新しいメソッドが追加されました。これらはユーザーが直接使用するのではなく、Channel実装自体によって使用されるべきです。

あまり使用されていないコーデックをNetty Contribに移行

コードベースのスリム化とメンテナンス負担の軽減のために、以下のコーデックとハンドラーがNetty Contribに移行されました。

  • netty-codec-xml
  • netty-codec-redis
  • netty-codec-memcache
  • netty-codec-stomp
  • netty-codec-haproxy
  • netty-codec-mqtt
  • netty-codec-socks
  • netty-handler-proxy
  • io.netty.handler.codec.json
  • io.netty.handler.codec.marshalling
  • io.netty.handler.codec.protobuf
  • io.netty.handler.codec.serialization
  • io.netty.handler.codec.xml
  • io.netty.handler.pcap
最終取得日: 2024年7月19日