通过 Grab 添加的外部库的可选依赖项不可用
Optional dependencies of external library added via Grab not available
无法在 Jenkins 的共享库中正确使用具有可选依赖项的外部第三方库。
我有一个共享库,它使用 Commons Configurations 2 来读取各种配置文件,这些配置文件大多写成 YAML 文档。
Commons配置使用SnakeYAML读取YAML文档,SnakeYAML的依赖定义为可选如下:
<dependency>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
<version>1.26</version>
<optional>true</optional>
</dependency>
根据 documentation of Maven how optional dependencies work,默认情况下不会将可选依赖项添加到类路径中。如果一个人想要依赖可选依赖的库部分,就必须将这个依赖添加到自己的POM中。
由于我打算将 Commons Configuration 2 与 SnakeYAML 结合使用,因此我在 vars/readConfig.groovy
中定义了以下变量,如下所示:
@Grapes([
@Grab(group = "org.apache.commons", module = "commons-configuration2", version = "2.7"),
@Grab(group = "org.yaml", module = "snakeyaml", version = "1.26")
])
import org.apache.commons.configuration2.BaseConfiguration
import org.apache.commons.configuration2.Configuration
import org.apache.commons.configuration2.YAMLConfiguration
def call() {
Configuration config = new BaseConfiguration();
YAMLConfiguration yamlConfiguration = new YAMLConfiguration();
}
从共享库调用 readConfig()
会导致 java.lang.ClassNotFoundException
出现以下消息
java.lang.ClassNotFoundException: org.yaml.snakeyaml.DumperOptions
at jenkins.util.AntClassLoader.findClassInComponents(AntClassLoader.java:1387)
at jenkins.util.AntClassLoader.findClass(AntClassLoader.java:1342)
at jenkins.util.AntClassLoader.loadClass(AntClassLoader.java:1089)
at java.lang.ClassLoader.loadClass(ClassLoader.java:352)
at java.lang.Class.getDeclaredMethods0(Native Method)
at java.lang.Class.privateGetDeclaredMethods(Class.java:2701)
at java.lang.Class.privateGetPublicMethods(Class.java:2902)
at java.lang.Class.getMethods(Class.java:1615)
at java.beans.Introspector.getPublicDeclaredMethods(Introspector.java:1336)
at java.beans.Introspector.getTargetMethodInfo(Introspector.java:1197)
at java.beans.Introspector.getBeanInfo(Introspector.java:426)
at java.beans.Introspector.getBeanInfo(Introspector.java:173)
at groovy.lang.MetaClassImpl.run(MetaClassImpl.java:3313)
at java.security.AccessController.doPrivileged(Native Method)
at groovy.lang.MetaClassImpl.addProperties(MetaClassImpl.java:3311)
at groovy.lang.MetaClassImpl.initialize(MetaClassImpl.java:3288)
at org.codehaus.groovy.reflection.ClassInfo.getMetaClassUnderLock(ClassInfo.java:260)
at org.codehaus.groovy.reflection.ClassInfo.getMetaClass(ClassInfo.java:302)
...
我还检查了目录 ~/.groovy/grapes
是否存在所有需要的 jar,它们都在那里。
jenkins@cb765137c926:~/.groovy$ find . -name "*.jar"
./grapes/commons-logging/commons-logging/jars/commons-logging-1.2.jar
./grapes/org.apache.commons/commons-configuration2/jars/commons-configuration2-2.7.jar
./grapes/org.apache.commons/commons-lang3/jars/commons-lang3-3.9.jar
./grapes/org.apache.commons/commons-text/jars/commons-text-1.8.jar
./grapes/org.yaml/snakeyaml/jars/snakeyaml-1.26.jar
为了进行交叉检查,我编写了以下 Groovy 脚本并能够在我的计算机上成功执行它。
@Grapes([
@Grab(group = 'org.apache.commons', module = 'commons-configuration2', version = '2.7'),
@Grab(group = 'org.yaml', module = 'snakeyaml', version = '1.26'),
@GrabConfig(systemClassLoader = true)
])
import org.apache.commons.configuration2.*
println("Start")
YAMLConfiguration y = new YAMLConfiguration()
println y
所以,我猜不出这个问题的原因,因为我对 Jenkins 的内部结构不是很熟悉。但很高兴知道是否有办法让它按预期工作。
@Grab
在沙箱中不起作用,因此这仅在全局配置中定义的共享库中起作用。即使发生这种情况,您也很可能 运行 进入 class 加载问题,因为 Jenkins 为您的脚本创建环境的方式 运行 在。
Cloudbees 建议不要在共享库中使用 @Grab
,出于这个原因,但也出于性能原因。当您让它工作时,这段代码将做的是在该主控上的每个构建开始时,通过 Internet 在阻塞调用中下载这些依赖项。如果网络速度较慢,您可以通过这种方式很快 运行 执行程序。
最佳做法是安装 Pipeline Utility Steps Plugin,它提供了 readYaml 方法。它只是基于 SnakeYaml 源,它的工作原理是一样的。
Grab 建立在 Ivy 之上。我们在 Ivy 配置中获取可选依赖项的做法是将 optional
添加到注释的元素 conf
中。
@Grab(group='org.apache.commons', module='commons-configuration2',
version='2.7', conf='default,optional')
无法在 Jenkins 的共享库中正确使用具有可选依赖项的外部第三方库。
我有一个共享库,它使用 Commons Configurations 2 来读取各种配置文件,这些配置文件大多写成 YAML 文档。
Commons配置使用SnakeYAML读取YAML文档,SnakeYAML的依赖定义为可选如下:
<dependency>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
<version>1.26</version>
<optional>true</optional>
</dependency>
根据 documentation of Maven how optional dependencies work,默认情况下不会将可选依赖项添加到类路径中。如果一个人想要依赖可选依赖的库部分,就必须将这个依赖添加到自己的POM中。
由于我打算将 Commons Configuration 2 与 SnakeYAML 结合使用,因此我在 vars/readConfig.groovy
中定义了以下变量,如下所示:
@Grapes([
@Grab(group = "org.apache.commons", module = "commons-configuration2", version = "2.7"),
@Grab(group = "org.yaml", module = "snakeyaml", version = "1.26")
])
import org.apache.commons.configuration2.BaseConfiguration
import org.apache.commons.configuration2.Configuration
import org.apache.commons.configuration2.YAMLConfiguration
def call() {
Configuration config = new BaseConfiguration();
YAMLConfiguration yamlConfiguration = new YAMLConfiguration();
}
从共享库调用 readConfig()
会导致 java.lang.ClassNotFoundException
出现以下消息
java.lang.ClassNotFoundException: org.yaml.snakeyaml.DumperOptions
at jenkins.util.AntClassLoader.findClassInComponents(AntClassLoader.java:1387)
at jenkins.util.AntClassLoader.findClass(AntClassLoader.java:1342)
at jenkins.util.AntClassLoader.loadClass(AntClassLoader.java:1089)
at java.lang.ClassLoader.loadClass(ClassLoader.java:352)
at java.lang.Class.getDeclaredMethods0(Native Method)
at java.lang.Class.privateGetDeclaredMethods(Class.java:2701)
at java.lang.Class.privateGetPublicMethods(Class.java:2902)
at java.lang.Class.getMethods(Class.java:1615)
at java.beans.Introspector.getPublicDeclaredMethods(Introspector.java:1336)
at java.beans.Introspector.getTargetMethodInfo(Introspector.java:1197)
at java.beans.Introspector.getBeanInfo(Introspector.java:426)
at java.beans.Introspector.getBeanInfo(Introspector.java:173)
at groovy.lang.MetaClassImpl.run(MetaClassImpl.java:3313)
at java.security.AccessController.doPrivileged(Native Method)
at groovy.lang.MetaClassImpl.addProperties(MetaClassImpl.java:3311)
at groovy.lang.MetaClassImpl.initialize(MetaClassImpl.java:3288)
at org.codehaus.groovy.reflection.ClassInfo.getMetaClassUnderLock(ClassInfo.java:260)
at org.codehaus.groovy.reflection.ClassInfo.getMetaClass(ClassInfo.java:302)
...
我还检查了目录 ~/.groovy/grapes
是否存在所有需要的 jar,它们都在那里。
jenkins@cb765137c926:~/.groovy$ find . -name "*.jar"
./grapes/commons-logging/commons-logging/jars/commons-logging-1.2.jar
./grapes/org.apache.commons/commons-configuration2/jars/commons-configuration2-2.7.jar
./grapes/org.apache.commons/commons-lang3/jars/commons-lang3-3.9.jar
./grapes/org.apache.commons/commons-text/jars/commons-text-1.8.jar
./grapes/org.yaml/snakeyaml/jars/snakeyaml-1.26.jar
为了进行交叉检查,我编写了以下 Groovy 脚本并能够在我的计算机上成功执行它。
@Grapes([
@Grab(group = 'org.apache.commons', module = 'commons-configuration2', version = '2.7'),
@Grab(group = 'org.yaml', module = 'snakeyaml', version = '1.26'),
@GrabConfig(systemClassLoader = true)
])
import org.apache.commons.configuration2.*
println("Start")
YAMLConfiguration y = new YAMLConfiguration()
println y
所以,我猜不出这个问题的原因,因为我对 Jenkins 的内部结构不是很熟悉。但很高兴知道是否有办法让它按预期工作。
@Grab
在沙箱中不起作用,因此这仅在全局配置中定义的共享库中起作用。即使发生这种情况,您也很可能 运行 进入 class 加载问题,因为 Jenkins 为您的脚本创建环境的方式 运行 在。
Cloudbees 建议不要在共享库中使用 @Grab
,出于这个原因,但也出于性能原因。当您让它工作时,这段代码将做的是在该主控上的每个构建开始时,通过 Internet 在阻塞调用中下载这些依赖项。如果网络速度较慢,您可以通过这种方式很快 运行 执行程序。
最佳做法是安装 Pipeline Utility Steps Plugin,它提供了 readYaml 方法。它只是基于 SnakeYaml 源,它的工作原理是一样的。
Grab 建立在 Ivy 之上。我们在 Ivy 配置中获取可选依赖项的做法是将 optional
添加到注释的元素 conf
中。
@Grab(group='org.apache.commons', module='commons-configuration2',
version='2.7', conf='default,optional')