在 Ktor 应用程序模块而不是 Main 中获取命令行参数?

Posted

技术标签:

【中文标题】在 Ktor 应用程序模块而不是 Main 中获取命令行参数?【英文标题】:Get command line arguments in Ktor Application module instead of Main? 【发布时间】:2019-12-06 07:50:05 【问题描述】:

我正在尝试从 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
            )
        
    

【问题讨论】:

【参考方案1】:

您可以将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)

详情

函数embeddedServermodule 作为最后一个参数。参数类型为Application类型的函数,不带任何参数,以Unit为返回值:

fun embeddedServer(..., module: Application.() -> Unit) : TEngine

这就是您可以提供Application::mainModule a 作为函数参考的原因。它与参数的类型定义完全匹配。但是你也可以提供一个尾随 lambda 而不是这个函数引用:

val server = embeddedServer(Netty, port = 8080)  
    // this is Application
    routing 
        get("/status") 
            //...
        
    

在此 lambda 中,this 的类型为 Application,与您的函数 Application.mainModule 完全相同。这意味着在这个 lambda 中,您可以轻松调用 Application 类型的其他函数。在我的回答中,我使用 args 作为参数创建了 Application.mainModule,并在尾随 lambda 中调用此函数。

【讨论】:

这很好用!!!谢谢你勒内。我现在正在努力理解这实际上是如何工作的......如果你能给我一些关于为什么 lambda 在这里提供帮助的指导,那就太棒了。但这已经很棒了! 谢谢!! 在保持io.ktor.server.netty.EngineMain.main(args)的功能的同时有什么办法吗? @daka 请查看我的答案,它应该会有所帮助。【参考方案2】:

要传递新的配置参数,您可以在其前面加上-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 应用程序的更多信息。

【讨论】:

谢谢,你觉得你能回答这个问题吗? ***.com/q/66279393/812919

以上是关于在 Ktor 应用程序模块而不是 Main 中获取命令行参数?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Ktor 中调用内部端点?

如何使用 ktor 获取客户端 IP

Ktor App 部署到 AppEngine 时未调用 Main 方法

如何在 Ktor 内部检查 Netty 是不是实际启动?

如何在 package.json 中选择“模块”而不是“主”文件

Kotlin / Ktor,不能使用 withtTestApplication 因为我的 main 是一个挂起函数