在 Ktor Application 模块而不是 Main 中获取命令行参数?
Get command line arguments in Ktor Application module instead of Main?
我正在尝试从 Ktor 构建一个最终应该通过 fatjar 执行的应用程序。
fatjar 允许使用如下参数:
java -jar myApp.jar XXXXX YYYYY
我知道如何在主模块中获取 XXXXX
(通过使用简单的 args[0]
),但我在应用程序模块中获取该值时遇到了麻烦。
我想做这样的事情:
fun main(args: Array<String>) {
val port = System.getenv("PORT")?.toInt() ?: 8080
val status = args[0]
embeddedServer(Netty, port = port, module = (Application::mainModule())).start(wait = true)
}
fun Application.mainModule() {
routing {
get("/status") {
call.respondText(
<status variable from main function>,
contentType = ContentType.Text.Html
)
}
}
}
您可以将 module
参数的方法引用替换为普通的 lambda。
在此 lambda 中,您可以使用所需参数调用模块函数:
fun Application.mainModule(args: Array<String>) {
routing {
get("/status") {
//...
}
}
}
fun main(args: Array<String>) {
val server = embeddedServer(Netty, port = 8080) {
mainModule(args)
}
server.start(wait = true)
}
详情
函数 embeddedServer
的最后一个参数是 module
。参数的类型是 Application
类型的函数,没有任何参数并且 Unit
作为 return 值:
fun embeddedServer(..., module: Application.() -> Unit) : TEngine
这就是您可以提供 Application::mainModule
作为函数参考的原因。它与参数的类型定义完全匹配。但是你也可以提供一个尾随的 lambda 而不是这个函数引用:
val server = embeddedServer(Netty, port = 8080) {
// this is Application
routing {
get("/status") {
//...
}
}
}
在此 lambda 中 this
的类型 Application
与您的函数 Application.mainModule
中的类型完全相同。这意味着在此 lambda 中,您可以轻松调用 Application
类型的其他函数。在我的回答中,我使用 args
作为参数创建了 Application.mainModule
并在尾随的 lambda 中调用了这个函数。
要传递新的配置参数,您可以在其前面添加 -P:propName=
。
因此,如果您想通过命令行传递一个名为 csv
的 属性,您可以执行以下操作:
fun main(args: Array<String>) {
val csvFileName = "-P:csv=${args[0]}"
EngineMain.main(arrayOf(csvFileName))
}
您也可以通过使用 -P:csv=myfile.csv
作为命令行参数来传递参数而无需修改 args
。
然后,在您的模块中,您可以通过 environment.config.property("csv").getString()
访问它。
fun Application.module() {
val csvFileName = environment.config.property("csv").getString()
println(csvFileName)
}
您可以在 the official Ktor documentation 阅读更多关于配置 Ktor 应用程序的信息。
我正在尝试从 Ktor 构建一个最终应该通过 fatjar 执行的应用程序。 fatjar 允许使用如下参数:
java -jar myApp.jar XXXXX YYYYY
我知道如何在主模块中获取 XXXXX
(通过使用简单的 args[0]
),但我在应用程序模块中获取该值时遇到了麻烦。
我想做这样的事情:
fun main(args: Array<String>) {
val port = System.getenv("PORT")?.toInt() ?: 8080
val status = args[0]
embeddedServer(Netty, port = port, module = (Application::mainModule())).start(wait = true)
}
fun Application.mainModule() {
routing {
get("/status") {
call.respondText(
<status variable from main function>,
contentType = ContentType.Text.Html
)
}
}
}
您可以将 module
参数的方法引用替换为普通的 lambda。
在此 lambda 中,您可以使用所需参数调用模块函数:
fun Application.mainModule(args: Array<String>) {
routing {
get("/status") {
//...
}
}
}
fun main(args: Array<String>) {
val server = embeddedServer(Netty, port = 8080) {
mainModule(args)
}
server.start(wait = true)
}
详情
函数 embeddedServer
的最后一个参数是 module
。参数的类型是 Application
类型的函数,没有任何参数并且 Unit
作为 return 值:
fun embeddedServer(..., module: Application.() -> Unit) : TEngine
这就是您可以提供 Application::mainModule
作为函数参考的原因。它与参数的类型定义完全匹配。但是你也可以提供一个尾随的 lambda 而不是这个函数引用:
val server = embeddedServer(Netty, port = 8080) {
// this is Application
routing {
get("/status") {
//...
}
}
}
在此 lambda 中 this
的类型 Application
与您的函数 Application.mainModule
中的类型完全相同。这意味着在此 lambda 中,您可以轻松调用 Application
类型的其他函数。在我的回答中,我使用 args
作为参数创建了 Application.mainModule
并在尾随的 lambda 中调用了这个函数。
要传递新的配置参数,您可以在其前面添加 -P:propName=
。
因此,如果您想通过命令行传递一个名为 csv
的 属性,您可以执行以下操作:
fun main(args: Array<String>) {
val csvFileName = "-P:csv=${args[0]}"
EngineMain.main(arrayOf(csvFileName))
}
您也可以通过使用 -P:csv=myfile.csv
作为命令行参数来传递参数而无需修改 args
。
然后,在您的模块中,您可以通过 environment.config.property("csv").getString()
访问它。
fun Application.module() {
val csvFileName = environment.config.property("csv").getString()
println(csvFileName)
}
您可以在 the official Ktor documentation 阅读更多关于配置 Ktor 应用程序的信息。