【问题标题】:Gradle doesn't collect strings starting with -DGradle 不收集以 -D 开头的字符串
【发布时间】:2018-03-08 21:14:24
【问题描述】:

这是 Gradle 还是 Groovy 错误?

我想将 JVM 参数从 Gradle 传递到分叉的 JVM,不幸的是这不是自动完成的。这应该可以工作,build.gradle:

...
bootRun {
   jvmArgs = System.properties.iterator().findAll{it.key.startsWith('myapp')}.collect {
     "-D${it.key}=${it.value}"}
}
...

执行如下:

 gradle bootRun -Dmyapp.port=34501 -Dmyapp.member.name=server1

如果字符串以-D 开头,方法collect 总是返回空集合。如果它以其他任何内容开头,则返回预期的两个元素字符串集合。如果我在-D 之前放置空间,它也可以工作,但是它会在:findMainClass 上进一步破坏下游的构建,并用主类名误解-Dmyapp.port=...。它只需以-D 开头。

我也尝试了不同的字符串连接,但结果是一个以 -D 开头的字符串,它不起作用。

这是一个错误还是我遗漏了什么。这是我的第一个 Gradle 项目,我不是 Groovy 开发人员。 我应该报告错误吗?在哪里,Groovy 还是 Gradle?

注意事项: 我正在从 IntelliJ IDE 2016.1.2 运行 Gradle
使用 Gradle 3.5
Forked JVM 运行 Spring Boot 应用程序

更新
非常抱歉,我的错!事实上,JVM 参数使用上面的公式传递下来的;问题在于我如何测量它不是。我只是把打印输出:

 println "jvmArgs: ${jvmArgs}"
 println "jvmArgs.size: ${jvmArgs.size}"
 println "jvmArgs.class: ${jvmArgs.class}"

..如果jvmArgs.size == 0,则中止bootRun,以避免应用程序启动缓慢;也就是说,我并没有真正检查应用程序本身是否传递了参数。事实证明他们是。

仅供参考,输出是:

 jvmArgs: []
 jvmArgs.size: 0
 jvmArgs.class: java.lang.ArrayList

jvmArgs 类被报告为标准 ArrayList,但其行为更像 输入流使用者,无论 jvmArgs 分配给什么数组,都会扫描该数组以查找所有以“-D”开头的字符串,那些是消耗(被什么?),传递给一些 ProcessBuilder (??) 并且 jvmArgs 只剩下剩余的元素。

举个例子:

 jvmArgs = ["-Daaa=bbb", "foo", "bar"]
 jvmArgs = ["stuff", "-Dccc=ddd", "morestuff"]
 jvmArgs = ["-Deee=fff"]
 println "jvmArgs: ${jvmArgs}"

..它打印 jvmArgs: [] 并且 Spring Boot 应用程序以 -Daaa=bbb -Dccc=ddd -Deee=fff 启动。

有人能解释一下是什么原因导致这个神奇的流类似于 jvmArgs 的属性,否则它声称是一个简单的 ListArray?

【问题讨论】:

  • 这绝对不是一个错误——它早就被发现了。你如何运行gradle?从控制台,哪个外壳?或者可能来自 IDE。
  • 你是对的,它一直有效,请阅读我的解释。奇怪的行为似乎是设计使然。

标签: spring-boot gradle groovy


【解决方案1】:

这对我有用,但我对观察到的行为没有解释。无论如何,希望它有所帮助。

def array = System.properties.iterator().findAll{
   it.key.startsWith('myapp')
}.collect {
   "-D${it.key}=${it.value}"
}
jvmArgs.addAll(array)

编辑

jvmArgs = ["value"] 调用 setJvmArgs,如果我没有遗漏什么,它会从 JavaExec 转到 JavaExecHandleBuilder,然后是 JvmOptions。在这里,一些参数被删除。以 -D 开头的条目被添加到系统属性中。

setJvmArgs( ["-Dtest=1", "xx"])
println getJvmArgs() //[xx]
println systemProperties //[test:1]

您的应用程序是否无权访问这些属性?

https://github.com/gradle/gradle/blob/master/subprojects/core/src/main/java/org/gradle/process/internal/JvmOptions.java#L183

编辑:后台发生了什么

在 Groovy 中,属性赋值调用 setter,访问它会调用 getter。它们可以互换。如果您省略了 setter 和 getter 对,它将为您生成并在字节码中可见。但你甚至可以省略属性本身,只写 getter 和 setter 对并将其用作属性。

class Foo {
   def setBar(String foo) {println "no thanks"}
   String getBar() {"test"}
}
f = new Foo()
f.bar="write Var" // println "no thanks"
println f.bar instanceof String // --> f.getBar() inst... true
println f.bar // 

因此,您从未将 List 分配给变量,而是调用 setJvmArgs(List)。您可以使用 getAllJvmArgs() btw 列出所有参数。

结合委托策略和动态属性/方法,这可能是 DSL 编程的福音,但却是调试的祸根……

http://groovy-lang.org/style-guide.html#_getters_and_setters 如果您想了解有关此主题的更多信息,请搜索 groovy propertyMissing/groovy metaprogramming/groovy Resolve Strategies。

【讨论】:

  • 我尝试使用像您这样的传递变量,然后将其分配给jvmArgs。令人困惑的是,传递变量的打印输出与预期的一样,它的行为就像正常的集合,但jvmArgs 又是空的。我没有尝试过addAll(),但我怀疑它会产生相同的效果。
  • 感谢源代码,它看起来像是我正在寻找的解释。你是怎样找到它的?你是如何弄清楚事件链的?是否可以调试 Gradle?
  • @Espinosa 我已经更新了答案。可以肯定地调试 gradle 脚本,但我从来没有让它工作。我想我已经在 gradle docs 中找到了 javaExec 任务的起点,后来切换到了 github。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-12-02
  • 2011-04-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多