背景:最近在找静态扫描的工具,发现了SonarQube,发现其服务端支持本地部署,安装过程中遇到不少问题,于是形成本文备忘。
项目使用的Java 8,SonarQube使用的是25.2的社区版本(Community Build),记录本文时,25.3已经发布。从官网的介绍来看,SonarQube的新版本是不会影响扫描Java 8的项目,所以不存在兼容性问题。但是,安装SonarQube本身是对Java 版本有要求的,这里要求至少是17或者21,官网介绍如下:
一、安装
1、安装SonarQube:直接下载zip包,解压即可。
2、安装java 17:前面提到了SonarQube是基于java 17/21运行的,所以,还需要安装java 17/21,我这里就直接使用17了。java 17也是一个压缩包,所以可以解压到指定的目录即可。由于部署SonarQube这台机器还需要跑基于java 8的项目,所以,这里就不设置java 17的环境变量了,稍后会介绍如何在启动的时候指定为java 17版本,使其正常运行。
3、安装数据库:可选,官网有介绍支持的数据库类型,数据库安装这块就不赘述了,根据需求自行决定。如果不安装,SonarQube默认是使用的内存数据库。目前发现在启动服务端的时候,CE进程会很慢,一般要几分钟之后才能正常使用,可能和没有安装数据库有关。
二、配置
安装好了之后,需要一些简单的配置,不然可能导致运行不起来。
1、SonarQube需要使用非root账号来启动,所以需要创建一个账号,比如就创建名为sonar的用户:
adduser sonar
2、修改SonarQube目录的权限为新建的sonar用户:
chown -R sonar:snoar ./sonarqube-25.2.xxxxx
3、修改sonar的配置文件sonar.properties,比如修改端口号等。如果部署的机器不能访问外网,则需要配置代理,因为SonarQube启动时,会访问https://update.sonarsource.org/update-center.properties
也可以修改配置文件的sonar.updatecenter.activate=false,启动时不访问上述链接。
4、修改启动脚本sonar.sh,直接指定java 17的路径:
# JDK 17
JAVA_CMD="/opt/jdk-17.0.13+11-jre/bin/java"
COMMAND_LINE="$JAVA_CMD $XMS $XMX $HAZELCAST_ADDITIONAL -jar $LIB_DIR/sonar-application-25.2.0.102705.jar"
5、配置数据库,这块参考官网介绍。
三、启动
一切准备就绪后,就可以启动了,执行sonar.sh脚本,等待所有进程都启动成功之后,就可以访问http://x.x.x.x/9000,进入到管理界面。前面已经提到过,默认安装时,启动CE的过程很慢,需要花几分钟时间。完整的进程列表如下图:
[root@localhost linux-x86-64]# jps
26897 Jps
14643 CliToolLauncher
14615 sonar-application-25.2.0.102705.jar
14920 WebServer
14730 org.elasticsearch.bootstrap.Elasticsearch
15647 CeServer
[root@localhost linux-x86-64]#
如果能进入管理界面,说明安装就成功了。如果访问不了,那就看下sonarqube下的log目录,里面包含每个进程对应的日志,根据日志信息排查问题。
四、客户端使用
上面把服务端部署好了,接下来就是介绍客户端的使用了。
1、服务端上新建一个本地项目,比如test,然后跟着向导一路next,最后会生成执行命令:
2、maven工程中引入sonar插件,配置如下:
<plugin>
<groupId>org.sonarsource.scanner.maven</groupId>
<artifactId>sonar-maven-plugin</artifactId>
<version>5.0.0.4389</version>
</plugin>
sonar插件执行的时候对java版本以及sonarqube的版本都是有依赖的,上述5.0的版本,最低要求java 17,同时,对maven的版本也有要求,必须是3.2.5+,官网介绍如下:
现在问题来了,sonar插件和sonar服务器都是使用的java 17,而我们的项目是使用的java 8,如果不做任何修改,执行mvn verify sonar:sonar时会报错,错误信息就是java版本不兼容的问题。因为要以项目为主,所以,我们可以换种思路,在不改变任何环境变量的情况下,通过脚本来解决这个问题:
@echo off
set JAVA_HOME=C:\soft\jdks\jdk8u392-b08
echo Compiling with JDK 8...
echo JAVA_HOME before compile: %JAVA_HOME%
call mvn verify
echo Errorlevel after compile: %ERRORLEVEL%
echo JAVA_HOME after compile: %JAVA_HOME%
echo Compile finished, proceeding to scan...
set JAVA_HOME=C:\soft\jdks\jdk-17.0.14+7
echo JAVA_HOME before scan: %JAVA_HOME%
echo Scanning with JDK 17...
call mvn sonar:sonar -Dsonar.projectKey=test -Dsonar.projectName="test" -Dsonar.host.url=http://10.10.10.10:9000 -Dsonar.token=sqp_c6ea69672794d8b42ee0cf7d65c5bb1cb57778f5 -Dsonar.java.jdkHome="C:\soft\jdks\jdk-17.0.14+7" -Dsonar.spotbugs.reportPaths=target/spotbugs-reports/spotbugsXml.xml
echo reset JAVA_HOME to JDK 8...
set JAVA_HOME=C:\soft\jdks\jdk8u392-b08
echo JAVA_HOME after scan: %JAVA_HOME%
echo Done!
执行上述脚本,就可以使得编译项目时使用的是java 8,在执行代码扫描时,使用的是java 17,最后为了避免重复使用命令行工具时的不便,我们又把环境变量改回java 8。
因为脚本里面对环境变量的修改都是临时的,随着命令行进程的结束就消失了,所以,对系统本身的环境变量没有影响,这是我觉得相对友好的方式了。
3、spotbugs插件介绍:上面的脚本,还顺带提到了如何将spotbugs插件的扫描结果集成到sonar中,就是这个参数:
-Dsonar.spotbugs.reportPaths=target/spotbugs-reports/spotbugsXml.xml
所以,这里一并讲讲spotbugs插件的使用,spotbugs其实是findbugs的继任者,先简单说说spotbugs和sonar的差别:
1、spotbugs插件也是用于静态代码扫描的工具,但是spotbugs仅仅只能扫描java语言,而sonar则可以扫描更多的语言。
2、spotbugs只有客户端,生成的报告都是单独的页面,不能像sonar那样,汇总到服务端显示。但是,借助sonar.spotbugs.reportPaths参数,可实现和sonar的集成。
在maven中 引入spotbugs:
<plugin>
<groupId>com.github.spotbugs</groupId>
<artifactId>spotbugs-maven-plugin</artifactId>
<version>4.8.6.6</version>
<executions>
<!-- 在 verify 阶段执行 SpotBugs 检查 -->
<execution>
<id>spotbugs-check</id>
<phase>verify</phase>
<goals>
<goal>spotbugs</goal>
</goals>
</execution>
</executions>
<configuration>
<includeFilterFile>${spotbugs.rules.file}</includeFilterFile>
<!-- 配置 SpotBugs 输出报告的格式 -->
<xmlOutput>true</xmlOutput>
<htmlOutput>true</htmlOutput>
<outputDirectory>${project.build.directory}/spotbugs-reports</outputDirectory>
<maxHeap>2048</maxHeap>
<effort>Min</effort>
<threshold>Low</threshold>
</configuration>
</plugin>
执行mvn verify时,就会自动执行代码扫描的功能了,然后报告保存在每个module的target目录下。
回到sonar,客户端除了sonar的maven插件,也提供了IDE插件,通过界面上的设置,可以连接到我们前面本地部署的服务器。这个具体的使用方法就不再介绍了,有需要的同学可自行研究。
好了,完结,撒花!