Sonarqube源码解析
Sonarqube
一、简介
SonarQube 是一种自动代码审查工具,用于检测代码中的错误、漏洞和代码异味。它可以与您现有的工作流程集成,以实现跨项目分支和拉取请求的持续代码检查
二、组成
Sonar主要由sonar-scanner、sonar-server两个部分组成
sonar-scanner作用主要是负责代码扫描
sonar-server作用是负责sonar web展示工作、数据库交互工作、扫描计算工作、规则存储工作、第三方插件打通等
Sonar scanner cli源码
一、地址
- GitHub:https://github.com/SonarSource/sonar-scanner-cli
二、底层
- 执行org.sonarsource.scanner.cli.Main类下的主函数,并打入对应的环境变量
主要分为三块方法执行:
main():创建初始化部分对象
execute():扫描初始化,初始化properties、初始化sonar版本及下载sonar-scanner-engine-.jar
execute(Stats stats, Properties p):将扫描功能交由sonar-scanner-engine-.jar,开始代码扫描
public class Main {
//...
//主启动函数入口,先创建,初始化部分对象
public static void main(String[] args) {
Logs logs = new Logs(System.out, System.err); //创建一个简单的日志输出对象,还未到初始化配置对象内容
Exit exit = new Exit(); //#创建Exit对象,功能是扫描完成后退出jar运行
Cli cli = new Cli(exit, logs).parse(args); //#Cli对象负责将启动配置属性args初始化
// #Main对象为代码扫描执行入口
Main main = new Main(exit, cli, new Conf(cli, logs, System.getenv()), new ScannerFactory(logs), logs);
main.execute();
}
//扫描执行前的初始化,及执行扫描功能
void execute() {
Stats stats = new Stats(logger).start(); //扫描状态量标识
int status = Exit.INTERNAL_ERROR;
try {
Properties p = conf.properties();
checkSkip(p);
configureLogging(p); //配置日志属性
init(p); //初始化sonar版本信息
/**
* 划重点
* embeddedScanner.start();扫描前置准备工作,内部调用doStart()
* doStart()作用:
* 1.会初始化http clinet对象用于执行http请求(ServerConnection)
* 2.通过http请求调用/batch/index接口下载sonar-scanner-engine-shaded-9.5-SNAPSHOT-all.jar文件
* 3.初始化sonar-scanner-engine文件"org.sonarsource.scanner.api.internal.batch.BatchIsolatedLauncher"类对象
* 4.初始化BatchIsolatedLauncher对象,主要功能负责代码核心扫描部分
*/
embeddedScanner.start();
//...
execute(stats, p); //调用private void execute()方法
status = Exit.SUCCESS;
} catch (Throwable e) {
//...
} finally {
exit.exit(status); //扫描完成退出jar运行环境
}
}
//执行代码扫描入口
private void execute(Stats stats, Properties p) {
embeddedScanner.execute((Map) p); //执行扫描
displayExecutionResult(stats, "SUCCESS");
}
}
三、cli执行图
Sonar scanner engine源码
一、前言
通过sonar-scanner-cli源码,最终会调用BatchIsolatedLauncher.execute()
方法来创建Batch
对象来执行扫描
二、扫描流程
-
首先
Batch.exeute()
会创建一个GlobalContainer
对象去执行扫描
-
GlobalContainer.execute()
会先后去执行doBeforeStart()
pico.start()
doAfterStart()
doBeforeStart()
主要作用打入对应的插件【全局配置类、部分工厂类、插件库类等】、及传入的this.components
插件类
pico.start()
将打入的插件通过picocontainer框架【轻量级IOC容器框架】,进行实例化
doAfterStart()
执行new ProjectScanContainer(this).execute();
将能力交给ProjectScanContainer.execute()
执行
ProjectScanContainer.execute()
同样也会去执行doBeforeStart()
pico.start()
doAfterStart()
doBeforeStart()
主要作用打入对应的插件【扫描组件类:rules、file、issue、metric等】、及传入的this.components
插件类
pico.start()
将打入的插件通过picocontainer框架【轻量级IOC容器框架】,进行实例化
doAfterStart()
执行扫描核心操作包括两块,见下
核心操作一内容
doAfterStart().scanRecursively(tree, tree.root())
核心操作一,遍历被扫描项目下所有模块,然后各自初始化一个ModuleScanContainer
对象去执行
1.
ModuleScanContainer.doAfterStart()
会执行ModuleSensorsExecutor.execute()
将能力交由ModuleSensorsExecutor
(模块传感执行器)2.
ModuleSensorsExecutor
来记录命中的语言、文件及配置
核心操作二内容
-
getComponentByType(ProjectSensorsExecutor.class).execute();
通过项目传感执行器ProjectSensorsExecutor
分析被扫描项目源文件数据 -
getComponentByType(CpdExecutor.class).execute();
通过CpdExecutor执行器来讲扫描的结果数据进行分析计算(包括聚合)
1.该操作会调用
CpdExecutor.runCpdAnalysis()
方法将扫描计算结果生成一个reportxxx.zip文件2.然后调用
CpdExecutor.saveDuplications()
将生成的报告文件写入ReportPublisher
对象中
getComponentByType(ReportPublisher.class).execute();
将步骤6写入的报告读取出来,调用api/ce/submit
接口叫报告上传ce server中
-
Ce server收到接口调用会在ce_task_input表插入一条数据,且input_data通过字节流方式存放上传的报告
-
而后会在ce_queue中插入一条数据该数据会被ce server队列线程取出分析并将结果存入DB中
Ce server计算是通过线程异步的方式操作的,详情可查看
CeWorkerImpl
类实现的内容
-
CeWorkerImpl.class
有个内部类ExecuteTask
,主要通过异步执行的方式将结果打入监听器中计算 -
报告计算方式是交由
ReportTaskProcessor.process()
去完成
三、Container能力图
GlobalContainer.execute()
内部会去创建ProjectScanContainer
对象,将能力交由ProjectScanContainer
ProjectScanContainer.execute()
内部会调用ModuleScanContainer
来分析被扫描项目的结构,文件,配置及命中扫描语言
真正执行扫描分析的是通过
ProjectScanContainer.execute()
为入口去实现的
四、整体扫描流程图
Jenkins sonar scanner
一、安装
Jenkins安装sonar-scanner插件,会在该机器下生成sonar-scanner-${version}-linux目录
目录下分为bin、config、jre、lib四个子目录
bin:存放sonar-runner脚本执行文件
config:存放sonar-project.properties配置文件
Jre:存放sonar-scanner jar包的运行环境
Lib:存放sonar-scanner jar包做扫描执行
二、执行
-
Jenkins- job配置需要拉取对应仓库的源码地址
-
Jenkins- job配置,安装sonar-scanner插件可在Jenkins job 构建项选中execute sonarqube scanner配置指定内容
-
配置完成后,执行Jenkins job查看日志,分析运行流程
先拉取仓库代码到指定目录,在执行sonar-scanner shell脚本来启动代码扫描
- Sonar-scanner shell脚本,Jenkins安装的sonar-scanner目录下${sonar-scanner}/bin/sonar-runnner
该脚本运行内容:
A. 将${sonar-scanner}/config/sonar-scanner.properties配置文件内容打入环境变量B. 启动sonar-scanner-*/lib/sonar-scanner-cli-${version}.jar 执行扫描
C. 执行org.sonarsource.scanner.cli.Main类下的主函数,并打入对应的环境变量
Sonar-server源码
一、地址
GitHub:https://github.com/SonarSource/sonarqube
二、安装
-
由于9.5版本对应的JDK版本11,所以idea需要绑定JDK11的编译环境
-
idea 设置build tools对于gradle版本对应的jdk要选择jdk11
-
项目结构jdk也选择11版本
-
项目根目录build.gradle文件修改以下配置
repositories {
mavenCentral()
def repository = project.hasProperty('qa') ? 'sonarsource-qa' : 'sonarsource'
maven {
url "https://repox.jfrog.io/repox/${repository}"
}
}
5… 然后进行gradle项目构建下载依赖包,或者根目录执行./gradlew build命令
三、启动
a.脚本方式
- 根目录下start.sh,本质是执行/sonar-application/build/distributions/sonarqube-9.5-SNAPSHOT/bin/macosx-universal-64/sonar.sh该脚本文件
- 根目录下的build.sh,本质是执行根目录start.sh脚本文件
- sonar-application目录下的sonar.sh,主要内容是启动sonar服务
b.源码启动
- 启动入口为sonar-application模块下的App.java类启动
- 该启动类指向的homeDir目录为sonar-application/build/classes
1.需要将sonar-application/build/conf 目录拷贝到sonar-application/build/classes
2.需要将sonar-application/build/conf/elasticsearch 目录拷贝到sonar-application/build/classes
3.需要将sonar-application/build/conf/lib 目录拷贝到sonar-application/build/classes
4.需要将sonar-application/build/conf/web 目录拷贝到sonar-application/build/classes
以上目录不移动获取会导致homeDir找不到该目录下的内容而报错,退出执行
- 启动成功后jdbc默认使用H2数据库,用户名密码为空,不设置即可
- org.sonar.process.ProcessProperties 包含了启动默认配置项
- App.java类启动代码解释
//cliArguments启动参数不填任何内容
public void start(String[] cliArguments) {
AppSettingsLoader settingsLoader = new AppSettingsLoaderImpl(System2.INSTANCE, cliArguments, new ServiceLoaderWrapper());
//会加载org.sonar.process.ProcessProperties 属性配置想进行加载
AppSettings settings = settingsLoader.load();
// ...
try (AppState appState = new AppStateFactory(settings).create()) {
//...
//这个方法会启动es、web、ce【重点内容,建议多看】
scheduler.schedule();
//...
}
四、模块
- sonar-application sonar启动入口
- sonar-check-api. sonar校验自定义注解封装
- sonar-duplications 提供复制副本相关功能代码封装
- sonar-core sonar一些共享的功能封装
- sonar-markdown. sonar部分数据格式化成markdown格式
- sonar-plugin-api、sonar-plugin-api-impl、sonar-testing-sarness、sonar-testing-ldap 提供sonar单元测试及断言器
- sonar-scanner-engine sonar静态代码扫描引擎
- sonar-scanner-engin-sharde 提供给sonar-scanner代码扫描是用的jar【执行静态代码扫描sonar-scanner源码会下载这个jar】
- sonar-shutdowner 关闭所有sonar相关的服务进程
- sonar-ws 提供sonar 后端所有请求接口的入口类,等同于controller【该请求会执行到sonar-webserver-webapi调用其执行器service层】
- sonar-ws-generator 调试类
- ut-monitoring. 提供监控相关aop功能类
- server. sonar主要核心功能实现的模块
server子模块
- sonar-alm-clinet 提供ALM集成功能客户端,在web前端配置->通用设置体现
- sonar-auth-bitbucket 提供是bitbucket授权认证功能【bitbucket源码托管网站类似于gitlab、github】
- sonar-auth-common 提供oauth2.0客户端身份认证功能【oauth2.0功能类似于jet】
- sonar-auth-github 提供GitHub客户端身份认证功能
- sonar-auth-gitlab 提供GitHub客户端身份认证功能
- sonar-auth-ldap 提供ldap客户端身份认证功能
- sonar-auth-saml 提供saml客户端身份认证功能【SAML,全称为Security Assertion Markup Language,是一种用于安全性断言的标记预压,作用于单点登录】
- sonar-ce 计算JVM的模块应用,具备监听与调度功能
- sonar-ce-common 计算引擎和Web服务器共享的计算引擎相关的代码
- sonar-ce-task 计算引擎任务和实用工具的“框架”和类编码
- sonar-ce-task-analysis 计算引擎任务处理项目分析报告的代码
- sonar-db-core sonar与多种数据库实现代码
- sonar-db-dao sonar与数据库交互实现层
- sonar-db-migration 不同版本发布数据迁移类实现
- sonar-main sonar应用主启动封装的一些主要类【非启动入口】
- sonar-process sonar启动进程管理实现类【es、java、日志等】
- sonar-server-common sonar Web服务器和ce(计算引擎)之间共享的代码
- sonar-web 纯前端【ts、js、html】
- sonar-webserver sonar后端内置tomcat服务
- sonar-webserver-api SonarQube WebServer内部api,用于其他WebServer模块或核心扩展
- sonar-webserver-auth 后端对用户请求身份认证
- sonar-webserver-core 后端服务一些核心功能的封装
- sonar-webserver-es 后端对于es查询相关的查询条件封装
- sonar-webserver-monitor 后端任务监控
- sonar-webserver-webapi 后端请求代码实现层【等同于spring服务service层】,主要跟dao类交互获取数据返回response
- sonar-webserber-pushapi 静态代码扫描数据提交的API接口
- sonar-webserber-ws web服务器请求拦截器、过滤器封装
更多推荐
所有评论(0)