前言
在日常开发的过程中,经常使用到Jenkins执行相关的构建任务。因为经常使用,便对Jenkins产生了浓厚的兴趣,尤其是对它插件机制想一探究竟。当把Jenkins源码下载到本地之后,才发现阅读Jenkins源码是一份十分痛苦的事情,它并不是采用经常使用到的spring系列来开发出来。在网上了解一下Jenkins所使用的开发框架和相关的技术,发现相关的资料少的可怜。想根据请求的URL,找到该URL被路由到那个方法,完全不像SpringMVC只要搜索一下就找出来了,剩下的工作只需要打断点,慢慢调试就能弄清楚全部执行流程。不过好在它是用JAVA开发的,于是硬着头皮折腾一阵子,终于发现了一小窍门。原来Jenkins开发人员早就是意识到这个问题了,只需要在启动命令上面加上-Dstapler.trace=true 这一参数,就可以看到请求URL所对应的调用栈信息。
原理
Jenkins是采用Stapler框架开发,有关这个框架的详细介绍,大家可以在网上查找相关资料来了解它在此不在详述。通过阅读这个框架最核心的类 org.kohsuke.stapler.Stapler (类似于SpringMVC DispatcherServlet,用于将请求映射到具体的处理方法),发现该类存在如下变量
/** * This flag will activate the evaluation trace. * It adds the evaluation process as HTTP headers, * and when the evaluation failed, special diagnostic 404 page will be rendered. * Useful for developer assistance. */ public static boolean TRACE = Boolean.getBoolean("stapler.trace");
如果该变量值为true的话,将会将触发org.kohsuke.stapler.EvaluationTrace类的trace方法调用,该方法源码如下,该方法会将调用堆栈信息放到请求响应头中。
1 public class EvaluationTrace { 2 3 public void trace(StaplerResponse rsp, String msg) { 4 traces.add(msg); 5 // Firefox Live HTTP header plugin cannot nicely render multiple headers 6 // with the same name, so give each one unique name. 7 rsp.addHeader(String.format("Stapler-Trace-%03d",traces.size()),msg.replace("\n","\\n").replace("\r","\\r")); 8 } 9 10 }
设置参数
Boolean.getBoolean方法是从System.getProperties中获取变量值,所以只需要在启动命令上使用-D传入该参数即可。我在本地是使用tomcat部署jenkins的,使用eclipse没有跑起来,在tomcat上设置变量
值有多种方法,我采取是比较“暴力”的手段,直接修改启动脚本。打开tomcat/bin文件夹中的catalina.bat脚本文件,在文件开始部分添加如下变量,如下所示:
1 @echo off 2 rem Licensed to the Apache Software Foundation (ASF) under one or more 3 rem contributor license agreements. See the NOTICE file distributed with 4 rem this work for additional information regarding copyright ownership. 5 rem The ASF licenses this file to You under the Apache License, Version 2.0 6 rem (the "License"); you may not use this file except in compliance with 7 rem the License. You may obtain a copy of the License at 8 rem 9 rem http://www.apache.org/licenses/LICENSE-2.0 10 rem 11 rem Unless required by applicable law or agreed to in writing, software 12 rem distributed under the License is distributed on an "AS IS" BASIS, 13 rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 rem See the License for the specific language governing permissions and 15 rem limitations under the License. 16 17 rem --------------------------------------------------------------------------- 18 rem Start/Stop Script for the CATALINA Server 19 rem 20 rem For supported commands call "catalina.bat help" or see the usage section 21 rem towards the end of this file. 22 rem 23 rem Environment Variable Prerequisites 24 rem 25 rem Do not set the variables in this script. Instead put them into a script 26 rem setenv.bat in CATALINA_BASE/bin to keep your customizations separate. 27 rem 28 rem WHEN RUNNING TOMCAT AS A WINDOWS SERVICE: 29 rem Note that the environment variables that affect the behavior of this 30 rem script will have no effect at all on Windows Services. As such, any 31 rem local customizations made in a CATALINA_BASE/bin/setenv.bat script 32 rem will also have no effect on Tomcat when launched as a Windows Service. 33 rem The configuration that controls Windows Services is stored in the Windows 34 rem Registry, and is most conveniently maintained using the "tomcat8w.exe" 35 rem maintenance utility. 36 rem 37 rem CATALINA_HOME May point at your Catalina "build" directory. 38 rem 39 rem CATALINA_BASE (Optional) Base directory for resolving dynamic portions 40 rem of a Catalina installation. If not present, resolves to 41 rem the same directory that CATALINA_HOME points to. 42 rem 43 rem CATALINA_OPTS (Optional) Java runtime options used when the "start", 44 rem "run" or "debug" command is executed. 45 rem Include here and not in JAVA_OPTS all options, that should 46 rem only be used by Tomcat itself, not by the stop process, 47 rem the version command etc. 48 rem Examples are heap size, GC logging, JMX ports etc. 49 rem 50 rem CATALINA_TMPDIR (Optional) Directory path location of temporary directory 51 rem the JVM should use (java.io.tmpdir). Defaults to 52 rem %CATALINA_BASE%\temp. 53 rem 54 rem JAVA_HOME Must point at your Java Development Kit installation. 55 rem Required to run the with the "debug" argument. 56 rem 57 rem JRE_HOME Must point at your Java Runtime installation. 58 rem Defaults to JAVA_HOME if empty. If JRE_HOME and JAVA_HOME 59 rem are both set, JRE_HOME is used. 60 rem 61 rem JAVA_OPTS (Optional) Java runtime options used when any command 62 rem is executed. 63 rem Include here and not in CATALINA_OPTS all options, that 64 rem should be used by Tomcat and also by the stop process, 65 rem the version command etc. 66 rem Most options should go into CATALINA_OPTS. 67 rem 68 rem JAVA_ENDORSED_DIRS (Optional) Lists of of semi-colon separated directories 69 rem containing some jars in order to allow replacement of APIs 70 rem created outside of the JCP (i.e. DOM and SAX from W3C). 71 rem It can also be used to update the XML parser implementation. 72 rem This is only supported for Java <= 8. 73 rem Defaults to $CATALINA_HOME/endorsed. 74 rem 75 rem JPDA_TRANSPORT (Optional) JPDA transport used when the "jpda start" 76 rem command is executed. The default is "dt_socket". 77 rem 78 rem JPDA_ADDRESS (Optional) Java runtime options used when the "jpda start" 79 rem command is executed. The default is localhost:8000. 80 rem 81 rem JPDA_SUSPEND (Optional) Java runtime options used when the "jpda start" 82 rem command is executed. Specifies whether JVM should suspend 83 rem execution immediately after startup. Default is "n". 84 rem 85 rem JPDA_OPTS (Optional) Java runtime options used when the "jpda start" 86 rem command is executed. If used, JPDA_TRANSPORT, JPDA_ADDRESS, 87 rem and JPDA_SUSPEND are ignored. Thus, all required jpda 88 rem options MUST be specified. The default is: 89 rem 90 rem -agentlib:jdwp=transport=%JPDA_TRANSPORT%, 91 rem address=%JPDA_ADDRESS%,server=y,suspend=%JPDA_SUSPEND% 92 rem 93 rem JSSE_OPTS (Optional) Java runtime options used to control the TLS 94 rem implementation when JSSE is used. Default is: 95 rem "-Djdk.tls.ephemeralDHKeySize=2048" 96 rem 97 rem LOGGING_CONFIG (Optional) Override Tomcat's logging config file 98 rem Example (all one line) 99 rem set LOGGING_CONFIG="-Djava.util.logging.config.file=%CATALINA_BASE%\conf\logging.properties" 100 rem 101 rem LOGGING_MANAGER (Optional) Override Tomcat's logging manager 102 rem Example (all one line) 103 rem set LOGGING_MANAGER="-Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager" 104 rem 105 rem TITLE (Optional) Specify the title of Tomcat window. The default 106 rem TITLE is Tomcat if it's not specified. 107 rem Example (all one line) 108 rem set TITLE=Tomcat.Cluster#1.Server#1 [%DATE% %TIME%] 109 rem --------------------------------------------------------------------------- 110 111 setlocal 112 113 set JAVA_OPTS="-Djenkins.install.runSetupWizard=false" 114 set JAVA_OPTS="%JAVA_OPTS%" "-Dstapler.trace=true"
直接在 JAVA_OPTS变量名中设置-Dstapler.trace=true,-Djenkins.install.runSetupWizard=false 这个变量是用来跳过安装向导,因为安装jenkins是要下载插件而下载这些插件十分耗时,所以使用这个参数直接跳过安装向导。
效果
老套路,使用chrome浏览器,按F12,切换到Network,随便点击面板中某个请求链接(非请求静态资源),查看请求的响应头。比如请求 /jenkins/,该请求响应头包含的调用栈信息,如下所示:
1 Stapler-Trace-001: -> evaluate(<hudson.model.Hudson@28cec7> :hudson.model.Hudson,"") 2 Stapler-Trace-002: -> evaluate(((StaplerProxy)<hudson.model.Hudson@28cec7>).getTarget(),"") 3 Stapler-Trace-003: -> evaluate(((StaplerFallback)<hudson.model.Hudson@28cec7>).getStaplerFallback(),"") 4 Stapler-Trace-004: -> evaluate(<hudson.model.AllView@552d7b[view/all/]> :hudson.model.AllView,"") 5 Stapler-Trace-005: -> index on <hudson.model.AllView@552d7b[view/all/]>