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, // your encrypt key here
secretSignKey, // your sign key here
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
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()
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以降削除されました。
プロジェクトにこのアーティファクトが依存関係として含まれている場合、安全に削除できます。