在 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 应用程序的信息。