2.2.x から 3.0.x への移行
このガイドでは、Ktorアプリケーションを2.2.xバージョンから3.0.xへ移行する方法について説明します。
Ktorサーバー
ApplicationEngine、ApplicationEnvironment、および Application
ApplicationEngine、ApplicationEnvironment、およびApplicationインスタンス間の設定可能性を向上させ、分離をより明確にするために、いくつかの設計変更が導入されました。
v3.0.0より前では、ApplicationEngineがApplicationEnvironmentを管理し、それがさらにApplicationを管理していました。
しかし、現在の設計では、ApplicationはApplicationEngineとApplicationEnvironmentの両方を作成、所有、初期化する責任を負います。
この再構築には、以下の破壊的変更が伴います。
ApplicationEngineEnvironmentBuilderおよびapplicationEngineEnvironmentクラスの名称変更。ApplicationEngineEnvironmentからstart()およびstop()メソッドの削除。commandLineEnvironment()の削除。ServerConfigBuilderの導入。embeddedServer()がApplicationEngineではなくEmbeddedServerを返すように変更。
これらの変更は、以前のモデルに依存する既存のコードに影響を与えます。
クラス名の変更
| パッケージ | 2.x.x | 3.0.x |
|---|---|---|
io.ktor:ktor-server-core | ApplicationEngineEnvironmentBuilder | ApplicationEnvironmentBuilder |
io.ktor:ktor-server-core | applicationEngineEnvironment | applicationEnvironment |
ApplicationEngineEnvironmentからstart()およびstop()メソッドが削除されました
ApplicationEngineEnvironmentがApplicationEnvironmentに統合されたため、start()およびstop()メソッドはApplicationEngineを介してのみアクセスできるようになりました。
| 2.x.x | 3.0.x |
|---|---|
ApplicationEngineEnvironment.start() | ApplicationEngine.start() |
ApplicationEngineEnvironment.stop() | ApplicationEngine.stop() |
さらに、以下の表で削除されたプロパティと、それに対応する現在の所有権のリストを確認できます。
| 2.x.x | 3.0.x |
|---|---|
ApplicationEngineEnvironment.connectors | ApplicationEngine.Configuration.connectors |
ApplicationEnvironment.developmentMode | Application.developmentMode |
ApplicationEnvironment.monitor | Application.monitor |
ApplicationEnvironment.parentCoroutineContext | Application.parentCoroutineContext |
ApplicationEnvironment.rootPath | Application.rootPath |
所有権の変更は、以下の例で示すことができます。
commandLineEnvironment()が削除されました
コマンドライン引数からApplicationEngineEnvironmentインスタンスを作成するために使用されていたcommandLineEnvironment()関数は、Ktor 3.0.0で削除されました。代わりに、コマンドライン引数を設定オブジェクトに解析するためにCommandLineConfig関数を使用できます。
アプリケーションをcommandLineEnvironmentからCommandLineConfigに移行するには、commandLineEnvironment()を以下に示すようにconfigureブロックで置き換えてください。
embeddedServerでのコマンドライン設定の詳細については、コードでの設定トピックを参照してください。
ServerConfigBuilderの導入
新しいエンティティであるServerConfigBuilderがサーバープロパティを設定するために導入され、以前のApplicationPropertiesBuilderの設定メカニズムを置き換えます。ServerConfigBuilderは、以前ApplicationPropertiesによって管理されていたモジュール、パス、および環境の詳細を保持するServerConfigクラスのインスタンスを構築するために使用されます。
以下の表は、主な変更点をまとめたものです。
| パッケージ | 2.x.x | 3.0.x |
|---|---|---|
io.ktor:ktor-server-core | ApplicationProperties | ServerConfig |
io.ktor:ktor-server-core | ApplicationPropertiesBuilder | ServerConfigBuilder |
さらに、embeddedServer()関数では、この新しい設定アプローチを反映するためにapplicationProperties属性がrootConfigに名称変更されました。
embeddedServer()を使用する際は、applicationProperties属性をrootConfigに置き換えてください。 以下は、developmentModeを明示的にtrueに設定してサーバーを構成するためにserverConfigブロックを使用する例です。
fun main(args: Array<String>) {
embeddedServer(Netty,
serverConfig {
developmentMode = true
module(Application::module)
},
configure = {
connector { port = 12345 }
}
).start(wait = true)
}EmbeddedServerの導入
EmbeddedServerクラスが導入され、embeddedServer()関数の戻り値の型としてApplicationEngineの代わりに使われるようになりました。
モデル変更の詳細については、YouTrackのKTOR-3857の課題を参照してください。
テスト
withTestApplicationおよびwithApplicationが削除されました
2.0.0リリースで非推奨になったwithTestApplication関数とwithApplication関数は、ktor-server-test-hostパッケージから削除されました。
代わりに、既存のKtorクライアントインスタンスと共にtestApplication関数を使用し、サーバーにリクエストを送信して結果を検証してください。
以下のテストでは、handleRequest関数がclient.getリクエストに置き換えられています。
詳細については、Ktorサーバーでのテストを参照してください。
TestApplicationモジュールの読み込み
TestApplicationは、設定ファイル (例: application.conf) からモジュールを自動的に読み込まなくなりました。代わりに、testApplication関数内で明示的にモジュールを読み込むか、設定ファイルを手動で読み込む必要があります。
明示的なモジュールの読み込み
モジュールを明示的に読み込むには、testApplication内でapplication関数を使用します。このアプローチでは、読み込むモジュールを手動で指定でき、テスト設定をより細かく制御できます。
設定ファイルからモジュールを読み込む
設定ファイルからモジュールを読み込みたい場合は、environment関数を使用してテストの設定ファイルを指定します。
@Test
fun testHello() = testApplication {
environment {
config = ApplicationConfig("application-custom.conf")
}
}テストアプリケーションの設定の詳細については、Ktorサーバーでのテストセクションを参照してください。
CallLoggingプラグインパッケージが名称変更されました
CallLoggingプラグインパッケージは、タイプミスにより名称変更されました。
| 2.x.x | 3.0.x |
|---|---|
io.ktor.server.plugins.callloging | io.ktor.server.plugins.calllogging |
ktor-server-host-commonモジュールが削除されました
ApplicationがApplicationEngineの知識を必要とするため、ktor-server-host-commonモジュールの内容はktor-server-core、具体的にはio.ktor.server.engineパッケージに統合されました。
それに応じて依存関係が更新されていることを確認してください。ほとんどの場合、ktor-server-host-commonの依存関係を削除するだけで済みます。
Locationsプラグインが削除されました
Ktorサーバー用のLocationsプラグインは削除されました。タイプセーフなルーティングを作成するには、代わりにResourcesプラグインを使用してください。これには以下の変更が必要です。
io.ktor:ktor-server-locationsアーティファクトをio.ktor:ktor-server-resourcesに置き換えます。ResourcesプラグインはKotlin serializationプラグインに依存します。serializationプラグインを追加するには、kotlinx.serializationのセットアップを参照してください。プラグインのインポートを
io.ktor.server.locations.*からio.ktor.server.resources.*に更新します。さらに、
io.ktor.resourcesからResourceモジュールをインポートします。
以下の例は、これらの変更を実装する方法を示しています。
Resourcesの操作の詳細については、タイプセーフなルーティングを参照してください。
WebSockets設定におけるjava.timeの置き換え
WebSocketsプラグインの設定は、pingPeriodおよびtimeoutプロパティにKotlinのDurationを使用するように更新されました。これにより、以前のjava.time.Durationの使用が、よりKotlinらしい体験のために置き換えられます。
既存のコードを新しい形式に移行するには、kotlin.time.Durationクラスの拡張関数とプロパティを使用して期間を構築します。以下の例では、Duration.ofSeconds()がKotlinのseconds拡張に置き換えられています。
他の期間設定にも、必要に応じて同様のKotlin期間拡張(minutes、hoursなど)を使用できます。詳細については、Durationのドキュメントを参照してください。
サーバーソケットの.bind()がsuspend関数になりました
JSおよびWasmJS環境での非同期操作をサポートするため、TCPSocketBuilderとUDPSocketBuilderの両方で、サーバーソケットの.bind()関数がsuspend関数に更新されました。これは、.bind()へのすべての呼び出しがコルーチン内で行われる必要があることを意味します。
移行するには、.bind()がコルーチンまたはsuspend関数内でのみ呼び出されるようにしてください。以下はrunBlockingを使用する例です。
runBlocking {
val selectorManager = SelectorManager(Dispatchers.IO)
val serverSocket = aSocket(selectorManager).tcp().bind("127.0.0.1", 9002)
//...
}ソケットの操作の詳細については、ソケットのドキュメントを参照してください。
マルチパートフォームデータ
バイナリおよびファイルアイテムの新しいデフォルト制限
Ktor 3.0.0では、ApplicationCall.receiveMultipart()を使用してバイナリおよびファイルアイテムを受信するためのデフォルトの制限が50MBに導入されました。受信したファイルまたはバイナリアイテムが50MBの制限を超えると、IOExceptionがスローされます。
デフォルト制限のオーバーライド
アプリケーションが以前、明示的な設定なしに50MBを超えるファイルの処理に依存していた場合、予期しない動作を避けるためにコードを更新する必要があります。
デフォルト制限をオーバーライドするには、.receiveMultipart()を呼び出すときにformFieldLimitパラメーターを渡します。
val multipartData = call.receiveMultipart(formFieldLimit = 1024 * 1024 * 100)PartData.FileItem.streamProvider()が非推奨になりました
以前のバージョンのKtorでは、PartData.FileItemの.streamProvider()関数を使用して、ファイルアイテムのコンテンツにInputStreamとしてアクセスしていました。Ktor 3.0.0以降、この関数は非推奨になりました。
アプリケーションを移行するには、.streamProvider()を.provider()関数に置き換えてください。.provider()関数はByteReadChannelを返します。これは、バイトのストリームを増分的に読み取るための、コルーチンフレンドリーな非ブロック抽象化です。 その後、ByteReadChannelによって提供される.copyTo()または.copyAndClose()メソッドを使用して、チャネルからファイル出力に直接データをストリームできます。
この例では、.copyAndClose()メソッドがByteReadChannelからファイルのWritableByteChannelにデータを転送します。
完全な例とマルチパートフォームデータの操作に関する詳細については、マルチパートフォームデータの要求処理を参照してください。
セッション暗号化メソッドの更新
Sessionsプラグインによって提供される暗号化メソッドがセキュリティを強化するために更新されました。
具体的には、以前は復号化されたセッション値からMACを導出していたSessionTransportTransformerEncryptメソッドが、暗号化された値からMACを計算するようになりました。
既存のセッションとの互換性を確保するため、KtorはbackwardCompatibleReadプロパティを導入しました。現在の設定では、SessionTransportTransformerEncryptのコンストラクタにこのプロパティを含めます。
install(Sessions) {
cookie<UserSession>("user_session") {
// ...
transform(
SessionTransportTransformerEncrypt(
secretEncryptKey, // ここに暗号化キー
secretSignKey, // ここに署名キー
backwardCompatibleRead = true
)
)
}
}Ktorのセッション暗号化の詳細については、セッションデータの署名と暗号化を参照してください。
Ktorクライアント
HttpResponseのcontentプロパティの名称変更
Ktor 3.0.0より前では、HttpResponseのcontentプロパティは、ネットワークから読み取られた応答コンテンツへの生のByteReadChannelを提供していました。Ktor 3.0.0以降、contentプロパティは、その目的をよりよく反映するためにrawContentに名称変更されました。
SocketTimeoutExceptionがタイプエイリアスになりました
io.ktor.client.network.socketsパッケージのSocketTimeoutExceptionは、KotlinクラスからJavaクラスのエイリアスに変換されました。この変更により、特定のケースでNoClassDefFoundErrorが発生する可能性があり、既存のコードの更新が必要になる場合があります。
アプリケーションを移行するには、コードが古いクラスを参照しておらず、最新のKtorバージョンでコンパイルされていることを確認してください。例外チェックを更新する方法は次のとおりです。
共有モジュール
kotlinx-ioへの移行
3.0.0リリースで、Ktorはkotlinx-ioライブラリの使用に移行しました。これは、Kotlinライブラリ全体で標準化された効率的なI/O APIを提供します。この変更により、パフォーマンスが向上し、メモリ割り当てが削減され、I/O処理が簡素化されます。プロジェクトがKtorの低レベルI/O APIとやり取りしている場合は、互換性を確保するためにコードを更新する必要がある場合があります。
これは、ByteReadChannelやByteWriteChannelなど、多くのクラスに影響を与えます。さらに、以下のKtorクラスは現在kotlinx-ioを基盤としており、以前の実装は非推奨になりました。
| Ktor 2.x | Ktor 3.x |
|---|---|
io.ktor.utils.io.core.Buffer | kotlinx.io.Buffer |
io.ktor.utils.io.core.BytePacketBuilder | kotlinx.io.Sink |
io.ktor.utils.io.core.ByteReadPacket | kotlinx.io.Source |
io.ktor.utils.io.core.Input | kotlinx.io.Source |
io.ktor.utils.io.core.Output | kotlinx.io.Sink |
io.ktor.utils.io.core.Sink | kotlinx.io.Buffer |
io.ktor.utils.io.errors.EOFException | kotlinx.io.EOFException |
io.ktor.utils.io.errors.IOException | kotlinx.io.IOException |
非推奨のAPIはKtor 4.0までサポートされますが、できるだけ早く移行することをお勧めします。アプリケーションを移行するには、kotlinx-ioから対応するメソッドを使用するようにコードを更新してください。
例:ストリーミングI/O
大規模なファイルダウンロードを処理し、効率的なストリーミングソリューションが必要な場合は、手動のバイト配列処理をkotlinx-ioの最適化されたストリーミングAPIに置き換えることができます。
Ktor 2.xでは、大規模なファイルダウンロードの処理は、通常、ByteReadChannel.readRemaining()を使用して利用可能なバイトを手動で読み取り、File.appendBytes()を使用してファイルに書き込むことでした。
val client = HttpClient(CIO)
val file = File.createTempFile("files", "index")
runBlocking {
client.prepareGet("https://ktor.io/").execute { httpResponse ->
val channel: ByteReadChannel = httpResponse.body()
while (!channel.isClosedForRead) {
val packet = channel.readRemaining(DEFAULT_BUFFER_SIZE.toLong())
while (!packet.isEmpty) {
val bytes = packet.readBytes()
file.appendBytes(bytes)
println("Received ${file.length()} bytes from ${httpResponse.contentLength()}")
}
}
println("A file saved to ${file.path}")
}
}このアプローチでは、複数のメモリ割り当てと冗長なデータコピーが発生しました。
Ktor 3.xでは、ByteReadChannel.readRemaining()がSourceを返すようになり、Source.transferTo()を使用してデータをストリーミングできるようになりました。
val client = HttpClient(CIO)
val file = File.createTempFile("files", "index")
val stream = file.outputStream().asSink()
val fileSize = 100 * 1024 * 1024
val bufferSize = 1024 * 1024
runBlocking {
client.prepareGet("https://httpbin.org/bytes/$fileSize").execute { httpResponse ->
val channel: ByteReadChannel = httpResponse.body()
var count = 0L
stream.use {
while (!channel.exhausted()) {
val chunk = channel.readRemaining(bufferSize)
count += chunk.remaining
chunk.transferTo(stream)
println("Received $count bytes from ${httpResponse.contentLength()}")
}
}
}
println("A file saved to ${file.path}")
}このアプローチでは、チャネルからファイルのシンクにデータが直接転送され、メモリ割り当てが最小限に抑えられ、パフォーマンスが向上します。
完全な例については、client-download-streamingを参照してください。
APIの置き換えの詳細については、
kotlinx-ioドキュメントを参照してください。
Attributeキーが厳密な型の一致を要求するようになりました
Ktor 3.0.0では、AttributeKeyインスタンスはIDによって比較され、値を格納および取得する際に厳密な型の一致を要求するようになりました。これにより、型安全性が確保され、型不一致によって引き起こされる意図しない動作が防止されます。
以前は、getOrNull<Any>()を使用してAttributeKey<Boolean>をフェッチするなど、格納された型とは異なるジェネリック型で属性を取得することが可能でした。
アプリケーションを移行するには、取得型が格納型と厳密に一致することを確認してください。
val attrs = Attributes()
attrs.put(AttributeKey<Boolean>("key"), true)
attrs.getOrNull<Boolean>("key")空のアーティファクトの削除
Ktor 1.0.0以降、空のアーティファクトio.ktor:ktorが誤ってMavenに公開されていました。このアーティファクトはKtor 3.0.0以降削除されました。
プロジェクトにこのアーティファクトが依存関係として含まれている場合、安全に削除できます。
