Learn Jenkins the hard way (1) - 从源码运行Jenkins开始

本文涉及的产品
容器镜像服务 ACR,镜像仓库100个 不限时长
简介: ## 前言 在上一篇文章中,总结了Jenkins的罪与罚。从本文开始,我们将迈入Jenkins的源码学习部分。学习源码的方式有很多种,对于Jenkins而言,网上关于源码的学习非常有限,比较建议大家先阅读官方关于如何成为contributor的文档,了解大体的结构后再逐步深入。

前言

在上一篇文章中,总结了Jenkins的罪与罚。从本文开始,我们将迈入Jenkins的源码学习部分。学习源码的方式有很多种,对于Jenkins而言,网上关于源码的学习非常有限,比较建议大家先阅读官方关于如何成为contributor的文档,了解大体的结构后再逐步深入。

从源码本地运行Jenkins

学习任何源码前,首先要做的事情是将源码跑起来。克隆Jenkins的源码:

    git clone https://github.com/jenkinsci/jenkins.git
    
    //可以切换到当前的稳定分支 
    //git checkout jenkins-2.32.2

Jenkins2.0以上的版本依赖JDK1.7以上,以及Maven3.0.4以上(如果需要本地调试Jenkins还需要安装Node.js)。编译Jenkins可以依照官方的文档:

mvn -Plight-test install

默认情况下Jenkins编译的时候会进行单元测试,导致编译的时间比较长,也可以采用如下的方式skip掉单元测试的构建

mvn clean install -pl war -am -DskipTests

Jenkins是一个比较大的项目,里面有非常多的依赖,因此最好使用一个国内的Maven加速源进行加速,可以在.m2的settings.xml中配置mirror

 <mirrors>
    <mirror>
      <id>alimaven</id>
      <name>aliyun maven</name>
      <url>http://maven.aliyun.com/nexus/content/groups/public/</url>
      <mirrorOf>central</mirrorOf>        
    </mirror>
  </mirrors>

编译完成即可在target目录下找到jenkins.war了,运行如下命令Jenkins就启动起来了。

 java -jar jenkins.war 

如果希望从IDE里面调试Jenkins,Jenkins支持通过IDE进行远程调试,在Jenkins源代码的war文件路径下执行如下命令

mvnDebug jenkins-dev:run -f war

在IDE中配置远程调试端口

8371540400c029773e00dc9c03734f45.png
此时在浏览器中输入localhost:8080/jenkins即可访问从源码运行的Jenkins

Jenkins的架构

在正式接触Jenkins的源码前,需要大致理解下Jenkins的架构方式,这样有助于我们选择从什么位置入手代码的学习。Jenkins的整体代码是依托于Stapler来实现的,Stapler是一个将应用程序对象和 URL 装订在一起的 lib 库,使编写 web 应用程序更加方便。Stapler 的核心思想是自动为应用程序对象绑定 URL,并创建直观的 URL 层次结构,下面是一个Stapler架构的示意图。
img002.jpg
其实Stapler的原理非常好理解,他将一个对象绑定为Root Object,然后通过通过反射的机制,将不同的路由映射成不同的对象与方法。举一个简单的例子,Hudson实例被映射到了路由的根路径,对于二级路径/project,即会被映射为Hudson对象的一个getProject方法;如果Project下还有下一级的路由比如/project/status,那么getProject就会返回一个带有getStatus方法的对象依次类推。
当我们了解了Stapler的原理后,就可以开始从点到面的开始研究一些Jenkins的实现,然后进一步理解Jenkins的源码了。

摸索Jenkins

虽然我们已经了解了Stapler的原理了,可是对应到Jenkins大量的源码还是很难入手,在这里要介绍一个小窍门,Stapler的某些设计很有意思,可能在设计之初就考虑到了调试的复杂性,Stapler会将路由处理的链路通过Header头的方式进行传递,通过查看链路的传递信息就可以快速找到对应的代码位置与访问链路,下面带大家调试一下Jenkins的首页。访问http://localhost:8080/jenkins/,打开Chrome的Network调试,找到/jenkins的路由tab。
aea60d626a197d4a57f79a52735710c3.png
我们来仔细分析右侧的Stapler的trace信息,可以很快的明白页面是如何渲染的。

Stapler-Trace-001:-> evaluate(<hudson.model.Hudson@34079395> :hudson.model.Hudson,"")
Stapler-Trace-002:-> evaluate(((StaplerProxy)<hudson.model.Hudson@34079395>).getTarget(),"")
Stapler-Trace-003:-> evaluate(((StaplerFallback)<hudson.model.Hudson@34079395>).getStaplerFallback(),"")
Stapler-Trace-004:-> evaluate(<hudson.model.AllView@5a0669bd[view/All/]> :hudson.model.AllView,"")
Stapler-Trace-005:-> hudson/model/View/index.jelly on <hudson.model.AllView@5a0669bd[view/All/]>

首先路由到达URL的根即Hudson.module.Hudson对象,然后通过StaplerFallback代理给了hudson.model.AllView对象,最终渲染了hudson/model/View/index.jelly这个文件。在这里需要补充的是,Stapler还有两种机制,一种是StaplerFallback,一种是StaplerProxy,如果对应URL的反射Model类实现了这两个接口,那么他们可以将页面的模板进行代理,或者对象镜像代理,因此如果单纯从Stapler的约定大于配置的机制中来学习Jenkins的源码会带来很多的困扰,因此有很多时候找不到对应的模板文件与类文件,这也就是为什么Stapler的Trace特别重要的原因。
我们回过头来看下Jenkins的首页,找到resources/hudson/model/View/index.jelly

<?jelly escape-by-default='true'?>
<st:compress xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:f="/lib/form" xmlns:i="jelly:fmt">
    <l:layout title="${it.class.name=='hudson.model.AllView' ? '%Dashboard' : it.viewName}${not empty it.ownerItemGroup.fullDisplayName?' ['+it.ownerItemGroup.fullDisplayName+']':''}" norefresh="${!it.automaticRefreshEnabled}">
      <j:set var="view" value="${it}"/> <!-- expose view to the scripts we include from owner -->
        <st:include page="sidepanel.jelly" />
        <l:main-panel>
          <st:include page="view-index-top.jelly" it="${it.owner}" optional="true">
            <!-- allow the owner to take over the top section, but we also need the default to be backward compatible -->
            <div id="view-message">
                <div id="systemmessage">
                  <j:out value="${app.systemMessage!=null ? app.markupFormatter.translate(app.systemMessage) : ''}" />
                </div>
              <t:editableDescription permission="${it.CONFIGURE}"/>
            </div>
          </st:include>
          
          <j:set var="items" value="${it.items}"/>
          <st:include page="main.jelly" />
        </l:main-panel>
        <l:header>
            <!-- for screen resolution detection -->
            <l:yui module="cookie" />
            <script>
              YAHOO.util.Cookie.set("screenResolution", screen.width+"x"+screen.height);
            </script>
        </l:header>
    </l:layout>
</st:compress>

此时可以尝试注释掉一些代码,比如注释掉main.jelly的这一行,然后刷新下页面,右侧的主面板已经被屏蔽掉了。

00185da4c8676d21ba933fa3d41fdd4b.jpeg
可以通过这种方法,快速对Jenkins感兴趣的页面进行学习、修改。

最后

在本篇文章中,我们讨论了Jenkins的基本的路由机制,以及如何通过调试Stapler Trace的方式快速的学习Jenkins,在下一篇文章中,我们将会对Jenkins中涉及到的关于Jelly模板的机制进行讨论。

目录
相关文章
|
jenkins 测试技术 Shell
Jenkins进阶之docker运行pytest并且出allure报告
最近想做一个简单的pytest 测试,用allure出报告,结果发现网上的方法都是在windows上装jenkins,然后用jenkins跑一个本地的运行环境。这种做法明显很不2021年。于是我决定做一个在jenkins上使用docker运行pytest,然后再出allure报告的文章。
1207 0
Jenkins进阶之docker运行pytest并且出allure报告
|
4月前
|
前端开发 jenkins 持续交付
jenkins学习笔记之二十:docker in docker运行pipeline
jenkins学习笔记之二十:docker in docker运行pipeline
|
5月前
|
Java jenkins 持续交付
Jenkins是开源CI/CD工具,用于自动化Java项目构建、测试和部署。通过配置源码管理、构建触发器、执行Maven目标,实现代码提交即触发构建和测试
【7月更文挑战第1天】Jenkins是开源CI/CD工具,用于自动化Java项目构建、测试和部署。通过配置源码管理、构建触发器、执行Maven目标,实现代码提交即触发构建和测试。成功后,Jenkins执行部署任务,发布到服务器或云环境。使用Jenkins能提升效率,保证软件质量,加速上线,并需维护其稳定运行。
132 0
|
7月前
|
人工智能 Oracle jenkins
【Jenkins】新手安装、运行Jenkins(详细教学)
【Jenkins】新手安装、运行Jenkins(详细教学)
|
Kubernetes jenkins 持续交付
jenkins结合k8s构建流水线如何提升运行性能和构建效率
jenkins结合k8s构建流水线如何提升运行性能和构建效率
|
jenkins 持续交付 Python
【Jenkins】Jenkins运行python脚本的简单操作(windows)
【Jenkins】Jenkins运行python脚本的简单操作(windows)
629 0
|
Oracle jenkins Java
【Jenkins】新手安装、运行Jenkins(详细教学)
【Jenkins】新手安装、运行Jenkins(详细教学)
270 0
|
安全 Java jenkins
Jenkins 解决Jenkins下java无法运行slave-agent jnlp程序连接Windows Slave主机
Jenkins 解决Jenkins下java无法运行slave-agent jnlp程序连接Windows Slave主机
326 0
|
jenkins 测试技术 持续交付
测试开发之:Jenkins持续集成(下),构建与运行(一)
测试开发之:Jenkins持续集成(下),构建与运行(一)
30982 2
测试开发之:Jenkins持续集成(下),构建与运行(一)
|
jenkins 持续交付
测试开发之:Jenkins持续集成(下),构建与运行(三)
测试开发之:Jenkins持续集成(下),构建与运行(三)
30948 1
测试开发之:Jenkins持续集成(下),构建与运行(三)