Jenkins 'Could not initialize JFreeChart' 和 tomcat setenv.sh

Jenkins 有一系列插件,可以提供趋势图显示项目的情况,例如 Checkstyle, Dry, FindBugs, PMD, Tasks, 和 Warnings,还有把前面的内容合并显示的 Static Analysis Collector Plug-in。实际上,你只要装最后一个,前面的会作为依赖全部装上。

作为尝试,先配置了 Maven Warnings Trend,打开一看,图是裂的……

headless mode

一看有几个Exception,根源应该是这个:

1
Could not initialize class org.jfree.chart.JFreeChart

放Google,在官方issue里发现这个:https://issues.jenkins-ci.org/browse/JENKINS-21839

It’s not a bug in Jenkins but a miss-configuration. Anyway I couldn’t find it in any knowledge base. Maybe adding this solution in JIRA is enough … but let me suggest you to try to add it somewhere in plugin’s documentation, for example on “Configuration” section found here https://wiki.jenkins-ci.org/display/JENKINS/Performance+Plugin

The solution is just adding

-Djava.awt.headless=true

I’m running Jenkins as a webapp on my Tomcat, so I just added this line to my /opt/tomcat/bin/catalina.sh :

CATALINA_OPTS=-Djava.awt.headless=true

关于headless的信息:https://www.oschina.net/translate/using-headless-mode-in-java-se

简单说,JFreeChart 引用了awt 包,然后 awt 会尝试绑定本地 IO 设备——包括 显示器 和 Keyboard,结果失败就会引起异常。只要启用 headless mode 就可以避免。直接 java 命令启动的 Jenkins.war,在启动时加上参数即可。如果通过 tomcat 这样的容器启动,就要把参数加到容器去。

setenv.sh

一点题外话。

上面 issue 的讨论里,是直接往 catalina.sh 里加参数;当初配置 tomcat 时,也有文章说写到 startup.shshutdown.sh 里面去。

实际上这都是不那么好的做法,应该写在 setenv.sh 里。看一下就知道 startup.shshutdown.sh 最后都实际调用到 catalina.sh ,而它会自动加载 setenv.sh

跟分别写在 startup.shshutdown.sh 比,写在一处当然更容易管理;那为什么不直接写在catalina.sh 开头,要多此一举呢?除了单独写在一个文件,更清晰以外,还有方便管理多个实例的好处。

catalina.sh 会先检查 $CATALINA_BASE/bin/setenv.sh ,存在就加载,不存在再去检查 $CATALINA_HOME/bin/setenv.sh 并加载。也就是 CATALINA_BASE 的配置优先于 CATALINA_HOME 的配置。

1
2
3
4
5
if [ -r "$CATALINA_BASE/bin/setenv.sh" ]; then
. "$CATALINA_BASE/bin/setenv.sh"
elif [ -r "$CATALINA_HOME/bin/setenv.sh" ]; then
. "$CATALINA_HOME/bin/setenv.sh"
fi

CATALINA_HOME 就是 tomcat 的安装目录了。而 CATALINA_BASE 是工作目录,默认等于 CATALINA_HOME

1
2
3
4
5
# Only set CATALINA_HOME if not already set
[ -z "$CATALINA_HOME" ] && CATALINA_HOME=`cd "$PRGDIR/.." >/dev/null; pwd`
# Copy CATALINA_BASE from CATALINA_HOME if not already set
[ -z "$CATALINA_BASE" ] && CATALINA_BASE="$CATALINA_HOME"

如果需要安装一个 tomcat 跑多个实例,这时CATALINA_BASE 就会指向各个实例自己的目录。这时分别写在工作目录下的 setenv.sh 就可以分别设置不同的配置。

就酱。


知识共享 “署名-非商业性使用-相同方式共享” 4.0 (CC BY-NC-SA 4.0)”许可协议
本文为本人原创,采用知识共享 “署名-非商业性使用-相同方式共享” 4.0 (CC BY-NC-SA 4.0)”许可协议进行许可。
本作品可自由复制、传播及基于本作品进行演绎创作。如有以上需要,请留言告知,在文章开头明显位置加上署名(Jayce Chant)、原链接及许可协议信息,并明确指出修改(如有),不得用于商业用途。谢谢合作。
详情请点击查看协议具体内容。