SonarQube是代码检查工具的技术标杆之一,除了用来检查项目,它本身也是开源的,源码(代码结构/技术文档等)也必然是值得一读。

通过阅读源码,我们可以学到

  • 一款顶尖复杂的软件项目的结构与模块如何划分
  • 一个复杂前端的React实现
  • 如何混合使用ES与数据库

在阅读本文前,众所周知源码分析非常耗费时间,重复一下源码分析方法论

  • 能够充分使用过此项目,并阅读文档,这一步主要掌握上下文与术语
  • 分析项目的依赖,并全部过一遍
  • 找到免编译的路由断点与关键日志位置
  • 充分使用FindUsage快速Jump

预先准备

由于编译SonarQube非常繁琐耗时,我建议提前下载好编译好的二进制文件,导入源码后配置Remote断点以实现降低分析耗时(类似以前写的通过GDB断点JVM)

下载源码

  • 下载SonarQube编译好的二进制文件,并确保已经有数据
  • 通过Github下载源码,导入IDEA中,并将Head切到与二进制一样的版本

配置断点

在IDEA中配置Remote断点,并在源码中如下位置打下断点

org.sonar.ce.app.CeServer#start

在SonarQube中配置sonar.properties

sonar.ce.javaOpts=-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=5006
sonar.web.javaOpts=-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=5007

然后运行SonarQube,如果Ok的话断点就断上了

SonarQube组件构成

服务端(ServerSide)

在服务端(org.sonar.application.App)启动时,会依此启动如下Process(通过ps aux|grep sonar分析)

org.sonar.application.Apporg.elasticsearch.bootstrap.Elasticsearchorg.sonar.ce.app.CeServerorg.sonar.server.app.WebServer

它们的作用分别是

  • ElasticSearch: 内嵌的ElasticSearch,版本为5,它内部还没有用推荐的_doc作为type
  • Compute Engine(CE): 计算引擎,通过解析计算客户端上传的Zip,显示到前端
  • Web: 本质是数据仓库的前台。主要有用React实现的前端与API代理,通过内嵌的Tomcat实现部署

它们的PID分别如下

p_es=`ps aux|grep Elasticsearch|grep java |awk '{print $2}'`
p_ce=`ps aux|grep CeServer|grep java |awk '{print $2}'`
p_web=`ps aux|grep WebServer|grep java |awk '{print $2}'`

通过lsof查看每个服务的监听情况,并在源码中全局搜索

lsof -i -n -P |grep java|grep LISTEN|grep ${p_es}
# --> 9001(Elastic默认TCP端口)
lsof -i -n -P |grep java|grep LISTEN|grep ${p_ce}
# --> 54918(没查到,可能是随机端口)
lsof -i -n -P |grep java|grep LISTEN|grep ${p_web}
# --> 9000(HTTP端口), 9092(H2数据库端口)

客户端(ScannerSide)

  • Analyser: 源码分析器,在客户机上计算,通过HTTP将ZIP发给WebServer

组件实现

内嵌H2数据库

直接免密码访问如下JDBC即可

jdbc:h2:tcp://127.0.0.1:9092/sonar

ElasticSearch里存的啥

在SonarQube中,ElasticSearch的配置文件是程序生成的。由于默认关闭了HTTP端口的,导致难以通过外部工具进行连接,我们可以进行如下Hack实现在启动ElasticSearch前修改配置

# vi elasticsearch/bin/elasticsearch
# 这里改成你的安装位置
SONAR_HOME=Downloads/sonarqube-7.4
sed -i -e 's/false/true/g' ${SONAR_HOME}/temp/conf/es/elasticsearch.yml
echo "http.host: 'localhost'" >> ${SONAR_HOME}/temp/conf/es/elasticsearch.yml
echo "http.port: '9300'" >> ${SONAR_HOME}/temp/conf/es/elasticsearch.yml

这样启动后,通过Elasticsearch Head等工具访问http://localhost:9300/就可以知道里面存的啥了。至于存了什么,请接着看下面具体分析。

WebServer

它部署了一个嵌入的Tomcat,通过Java(而不是通过Spring的DSL)手动实现添加webApp

org.sonar.server.app.TomcatContexts#addContext

等Tomcat部署后,将调用PlatformServletContextListener启动Platform(这里并没有使用Spring作为依赖注入,而是使用了picocontainer实现,使用Java编码而没有用注解/XML等DSL进行描述依赖关系),启动API业务

最终部署如下业务

部署类型 ContextPath ByWho
API业务 /api WebServiceFilter, 类似于Struts
React静态文件 默认是/, 详见sonar.web.context web
插件Jar仓库静态文件 /deploy data/web/deploy

所有的API请求均可以通过如下位置进行断点分析到业务中

org.sonar.server.ws.WebServiceEngine#execute

这样本文的引导作用就达到了,剩下具体业务自行断点分析

我在这里耗费了较多时间,本以为API业务是由Servlet进行处理,没想到居然是通过全手写Filter与Action的方法处理(10年前这种方法很先进),可以看出SonarQube也是有历史债务的,但是它的代码质量经过长期maintain后仍然清晰。

注意项目中的StaticResourcesServlet已经事实上废弃,因为已经没有static文件夹了

CE如何录入计算结果?

总流程如下

Scanner-(HTTP)->Web-(MQ)->CE

首先在Scanner通过Maven等工具在Jenkins等平台(占用这些平台的计算资源)计算出项目的各种分析报告,然后Scanner调用Web中如下接口

// http://localhost:9000/api/ce/submit?projectKey=xxx&projectName=yyy
org.sonar.server.ce.ws.SubmitAction#handle

WebServer将原始RAW文件录入ce_task_input,接着通过消息队列(DB Based)

org.sonar.ce.queue.CeQueueImpl#submit(org.sonar.ce.queue.CeTaskSubmit)

CE侧通过线程池每隔两秒轮询查询任务

org.sonar.ce.taskprocessor.CeWorkerImpl#call

最终任务将通过路由到如下位置,执行数据仓库录入等任务

org.sonar.ce.task.step.ComputationStepExecutor#executeStep

疑问解答

SonarQube如何实现存储源码?

通过访问表file_sources中的BINARY_DATA与protobuf实现存储,它与File通过FILE_UUID进行关联

org.sonar.server.source.ws.LinesAction#handle

SonarQube与Markdown

通过基于正则表达式的规则引擎实现,这个做的比较简单,没有实现AST

org.sonar.channel.ChannelDispatcher#consume

SonarQube的React如何实现

前台使用了React与JSX实现业务,使用Webpack进行打包,使用WebPackDevServer作为API代理,前端通过如下启动外壳业务,打包脚本见server/sonar-web/config/webpack.config.js

# 启动业务(使用NodeJS提供Server)
node server/sonar-web/scripts/start.js
# 打包(后续交给Tomcat处理)
node server/sonar-web/scripts/build.js

SonarQube如何分析代码AST?

这里采用插件实现,比如Java在这里可以找到,分析后将转为通用格式发给Web进行处理

如果项目组需要定制Custom Rule,就可以通过访问onMethodInvocationFound实现自己的规则

Appendix

学到的其它技巧

// ThreadLocal更优雅的启动方法
ThreadLocal<Boolean> CACHING_ENABLED = ThreadLocal.withInitial(() -> Boolean.FALSE);

SonarQube是如何工作的相关推荐

  1. SonarQube使用介绍

    目录 SonarQube使用介绍 工作流程: 工作流程介绍 主要作用 衡量代码质量的几个指标 SonarQube的UI界面: 个人解决项目中的bug,异味总结 ①:变量声明后不使用,多余变量 ②:方法 ...

  2. sonar检测java vue项目_Jenkins集成SonarQube 实现构建项目同时审查代码

    软件版本: SonarQube:7.7 Jenkins:2.164.3 一.简介 SonarQube是一个开源的代码质量分析平台,便于管理代码的质量,可检查出项目代码的漏洞和潜在的逻辑问题.同时,它提 ...

  3. 代码审查工具 sonarqube 简介

    目录 1. 什么是SonarQube? SonarQube的功能 1.糟糕的复杂度分布 2.重复 3.缺乏单元测试 4.没有代码标准 5.没有足够的或者过多的注释 6.潜在的bug 7.糟糕的设计(原 ...

  4. 【代码审计】使用SonarQube进行代码质量分析管理

    2019独角兽企业重金招聘Python工程师标准>>> 在之前的开发中,代码的工作量化和质量化都是一个问题,随着近几年互联网行业的快速发展,代码已经可以来工作量化和质量化,今天我们来 ...

  5. 如何搭建安卓开发持续化集成环境(Ubuntu + Jenkins + SonarQube)

    本文讲的是如何搭建安卓开发持续化集成环境(Ubuntu + Jenkins + SonarQube), 我最近换了一台新的 MacBook Pro 作为我的 Android 开发机.旧的 Mac Bo ...

  6. SonarQube 代码扫描任务集成

    1. SonarQube 是一种自动代码审查工具,用于检测代码中的错误,漏洞和代码异味.它可以与您现有的工作流程集成,以便在项目分支和拉取请求之间进行连续的代码检查. 2. SonarQube 分为四 ...

  7. SonarQube系列二、分析dotnet core/C#代码

    来源:https://www.cnblogs.com/7tiny/p/11342902.html [前言] 本系列主要讲述sonarqube的安装部署以及如何集成jenkins自动化分析.netcor ...

  8. SonarQube系列一、Linux安装与部署

    来源:https://www.cnblogs.com/7tiny/p/11269774.html [前言] 随着项目团队规模日益壮大,项目代码量也越来越多.且不说团队成员编码水平层次不齐,即便是老手, ...

  9. sonar扫描普通JAVA执行,SonarQube扫描源代码的方法

    SonarQube扫描源代码的方法 雷建锋 一.分析源代码综述 一旦成功安装了SonarQube平台,您就可以开始安装一个分析器并开始创建项目了.在第一次分析时,该平台会自动创建一个项目.如果您需要在 ...

最新文章

  1. 学习jvm(一)--java内存区域
  2. 2021年春季学期-信号与系统-第十四次作业参考答案-第九小题参考答案
  3. 大作完成了一部分,陆续往上放吧
  4. 【周报6.10-6.16】NLP,RL,GAN,DL框架等重磅专栏齐上线,这个月的有三AI你值得拥有...
  5. function module COM_PRODUCT_GETDETAIL_INTERNAL的内存分配问题
  6. 项目管理 计算机仿真,分析计算机仿真技术在工程项目施工管理中的运用.pdf
  7. 【HDU - 4635】Strongly connected(缩点,新图性质,建图,Tarjan求强连通分量)
  8. cocos2d-x的popScene的动画效果
  9. 1090. Highest Price in Supply Chain (25) dfs
  10. c语言输出教学日历表 节假日突出,[蓝桥杯][算法提高VIP]任意年月日历输出 (C语言代码)...
  11. 用MobaXterm远程连接Centos系统_使用技巧---Linux工作笔记047
  12. Anaconda 安装教程(Win10环境) Tensorflow安装
  13. element 使用阿里图标变形了_2TB不限速的阿里网盘App来了 终于不再忍受众生平等盘...
  14. Request header field storeid is not allowed by Access-Control-Allow-Headers in preflight response.
  15. Redis4.0之持久化存储
  16. 【原创】flv文件的三种下载方法
  17. element 日期选择器不能选择当天日期以后的日期
  18. 打印幻灯片去掉空白边缘
  19. 每日一犬 · 猴头梗
  20. 淘宝运营 钻展、智钻的定义 优势所在

热门文章

  1. 皮一皮:论家庭地位...
  2. Redis主从握手流程,你真的了解了吗?
  3. 原来这就是Java代码生成器的原理啊,太简单了
  4. 以为是行废代码,原来有这作用!
  5. MongoDB Server 3.4版本将于2020年1月31日停止支持
  6. 一点小兴趣,一份小生意
  7. linux服务器密码策略,windows与linux服务器平台密码策略管理
  8. yii2 mysql gone away,yii2 console MySQL server
  9. eclipse java代码某一行需要修改注释_看看这些Java代码开发规范吧!你好,我好,大家好!...
  10. linux设备模型 字符设备,Linux 字符设备驱动模型之框架解说