资讯动态

SonarQube 7.4实战:Java 8老项目代码质量扫描与踩坑指南

发布时间:2026/10/9 17:43:32 来源:尧图企业网站定制
简介SonarQube 7.4 是开源代码质量管理平台 SonarQube 的一个稳定版本面向需要持续检测代码质量、发现漏洞与代码异味的开发者和团队。压缩包以 rar 格式打包整体约 161.38MB解压后可看到 bin、conf、extensions、lib、web 等标准目录适合在内网或官网下载困难的环境下离线部署也便于本地搭建分析服务并接入 Jenkins、GitLab CI/CD 等流程。当前已有 637 人浏览学习。相比在线安装该离线包省去从官网缓慢下载的等待同时保留了 SonarQube 7.4 的核心分析与 Web 管理能力用户可基于 conf/sonar.properties 完成数据库与端口配置并通过 extensions 目录扩展语言插件和质量规则直接用于 Java、Python、C#、JavaScript 等项目的代码质量追踪与改进。1. SonarQube 7.4老项目做代码体检为什么这个版本还是能打SonarQube 7.4 这个版本在 2018 年发布放到今天看已经算老古董了但我给某公司维护的那套遗留 Java 系统至今还在用它做每次提交的代码体检。原因很直接7.4 是免费版里最后一个在 Java 8 环境下跑得极稳的版本旧项目的构建脚本、依赖树和 CI 流程全是围绕 Java 8 搭建的升到新版 SonarQube 意味着要重写整个扫描链路的镜像和插件性价比太低。它解决的核心问题是在代码合并之前把空指针风险、资源未关闭、重复代码、坏味道这些问题暴露出来而不是等测试环境翻车后再回滚。适合谁用维护老项目的团队、还没接入静态扫描的团队、以及需要内网离线部署的团队这个版本都能撑住场面。2. 安装前的版本矩阵JDK、数据库、内存参数怎么配才不翻车2.1 版本选择为什么 7.4 卡在 Java 8 这一代很多人以为 SonarQube 只是一个 Java 应用把 JDK 装到最新版就行。我接过多个从零搭 SonarQube 的活儿翻车最多的就是版本错配。7.4 这个版本对 JDK 的要求是 Java 8 以上但它内置的 Elasticsearch 对 JDK 的版本非常敏感。你如果拿 JDK 11 去跑 7.4启动阶段大概率会报Unsupported class version error或者 ES 节点直接起不来。这不是玄学是 SonarQube 7.4 发行时候还没适配 JDK 11内部的字节码和依赖库都锚定在 Java 8 上。数据库的选择也一样。7.4 官方支持 MySQL 5.7、PostgreSQL 9.6 等但不支持 MySQL 8.0 的默认认证插件。你如果非要装 MySQL 8连接时会被caching_sha2_password这种新认证方式挡住日志里留下一堆Public Key Retrieval is not allowed。我一般直接给项目配 PostgreSQL省去认证插件的麻烦。如果你只能用 MySQL记得在创建用户时指定mysql_native_password插件并且驱动 jar 要放到 SonarQube 的lib/jdbc目录下7.4 自带的驱动只有 5.1.x对 MySQL 8 的兼容性不够。版本矩阵的底层逻辑是SonarQube 7.4 自己内置了一个老版本 Elasticsearch它跟 JDK 的并发模型绑定得很死。ES 在 7.x 之后的版本里才支持 JDK 11但 7.4 内置的 ES 版本还停留在 5.x 时代。你只有把 JDK 锁在 8 的某个稳定小版本比如1.8.0_202ES 才不会出现线程调度异常。我自己踩过一次手动改了sonar.properties里的sonar.es.javaOpts想让 ES 多占内存结果因为 JDK 11 的--illegal-access策略ES 启动时直接报illegal reflective access那个下午全耗在排查上。组件7.4 推荐版本避开的版本原因JDKJava 8u202 或更老JDK 11ES 反射访问限制MySQL5.7.x8.0认证插件与驱动不兼容PostgreSQL9.6 ~ 11无兼容性较好内存物理机 ≥4GB2GBES 启动即 OOM2.2 建库和配置文件三条命令加一个 properties安装目录先准备好一般放/opt/sonarqube最好用单独的sonar用户跑后面会解释为什么。解压后第一步是建数据库。如果你走 PostgreSQL先建库和账号sudo -u postgres psql -c CREATE DATABASE sonar ENCODING UTF8 TEMPLATE template0; sudo -u postgres psql -c CREATE USER sonar WITH PASSWORD sonar; sudo -u postgres psql -c GRANT ALL PRIVILEGES ON DATABASE sonar TO sonar;注意TEMPLATE template0这个参数不能省。PostgreSQL 默认的 template1 可能带着旧编码导致后续 SonarQube 写入数据时出现中文乱码。用 template0 是从最干净的库模板创建编码强制 UTF8。SonarQube 7.4 的表结构很多字段是TEXT类型如果库编码不对扫描出来的中文问题描述会全部变成问号我当时还以为是系统字体问题结果查了半小时发现是建库时没指定编码。接着改 SonarQube 的配置文件conf/sonar.properties核心是数据库连接和 Web 端配置sonar.jdbc.usernamesonar sonar.jdbc.passwordsonar sonar.jdbc.urljdbc:postgresql://localhost:5432/sonar sonar.web.host0.0.0.0 sonar.web.port9000 sonar.web.context/sonarqubesonar.web.context是很多人忽略的坑。默认是/如果你直接配sonar.web.port9000访问地址是http://ip:9000但如果你配了/sonarqube那后面所有项目扫描的SONAR_HOST_URL都要带上/sonarqube这个前缀否则扫描器报 404。我习惯一开始就定好 context 路径避免后期反代层嘛。JDBC URL 里的参数也值得掰开说。PostgreSQL 比 MySQL 省心但还是要带上characterEncoding之类的参数不需要PostgreSQL 驱动自己处理。MySQL 才需要在 URL 后面拼?useUnicodetruecharacterEncodingutf8rewriteBatchedStatementstrueuseConfigsmaxPerformance。rewriteBatchedStatements这个参数对 SonarQube 大量批量插入很有用不加的话扫描一个大项目时数据库 CPU 会飙到 100%性能差好几倍。2.3 启动后的检查路径看日志、探端口、确认版本第一次启动别急着打开页面。先启动然后等一分钟看日志cd /opt/sonarqube/bin/linux-x86-64 su sonar -c ./sonar.sh start tail -f /opt/sonarqube/logs/sonar.logsonar.sh start这步常见的错误是忘记用su sonar。如果你直接用 root 跑SonarQube 会启动一个子进程给内置 Elasticsearch而 ES 出于安全原因不允许 root 用户运行日志里会明确写can not run elasticsearch as root。我见过的很多新手直接./sonar.sh start然后看到进程闪现一下没了回头看日志才明白原因。启动成功的标志是SonarQube is up。这时再用curl -I http://127.0.0.1:9000/sonarqube探一下 HTTP 状态码期望返回 200 或 302。如果返回 502说明 Web 端口没绑对检查sonar.web.port是否被占用。如果返回 503说明还在初始化数据库多看两分钟。最后登录 Web 界面右上角能看到精确的版本号 7.4同时能查系统信息里的组件版本包括 ES、数据库驱动、JDK 这些这一步相当于给整个安装过程拍个 X 光片。3. 项目接入扫描从 Maven 插件到命令行解析器3.1 在 Web 端生成 Token 并绑定权限SonarQube 7.4 的 Web 界面比新版本朴素但流程是一样的。用管理员账号登录后进入「我的账号」里的「安全」页签生成一个 Token。这个 Token 是审计字符串形如xjklsdfiqwe...生成后只显示一次后面每次扫描都靠它做身份认证。注意Token 不要用admin的默认密码裸跑因为扫描器通过 HTTP 调用 SonarQube APIToken 在网络传输中会被中间人截获公司内网也存在这种风险。Token 的权限范围取决于生成它的用户。我一般单独建一个ci用户只给Execute Analysis权限而不是直接用 admin。这样扫描器拿到 Token 后只能执行扫描和推状态不能改规则或门禁。你也可以在 Web 界面里给项目设置「项目管理员」角色让对应负责人自己管理质量配置这个在 7.4 里是「项目权限」页面配置。3.2 Maven 配置settings.xml 和 pom.xml 各写什么接手 Java 项目时最常见的是 Maven 多模块工程。Scanner 的 Maven 插件要识别到主工程需要在全局settings.xml里声明插件组和连接参数settings pluginGroups pluginGrouporg.sonarsource.scanner.maven/pluginGroup /pluginGroups profiles profile idsonar/id activation activeByDefaulttrue/activeByDefault /activation properties sonar.host.urlhttp://192.168.1.100:9000/sonarqube/sonar.host.url sonar.loginTOKEN_STRING/sonar.login /properties /profile /profiles /settings这里sonar.host.url必须和 Web 端访问地址完全一致包括 context 路径。如果 Web 是/sonarqube这里漏掉就会导致扫描器找不到服务器。sonar.login是上面生成的 Token占位符要替换成真实值。有人图省事把 Token 直接写进pom.xml这样会让每个开发者的本地构建都共用同一身份很难定位是谁提交的质量问题不推荐。真正干活的是pom.xml里的属性不用装插件Maven Scanner 会自动读取properties project.build.sourceEncodingUTF-8/project.build.sourceEncoding sonar.languagejava/sonar.language sonar.sourcessrc/main/java/sonar.sources sonar.testssrc/test/java/sonar.tests sonar.java.binariestarget/classes/sonar.java.binaries /propertiessonar.java.binaries必须指向编译产物目录。很多项目第一次扫描时报No files or directories matching target/classes就是因为直接用了源码目录而 SonarQube 需要分析字节码才能做类型推断和跨方法的数据流分析。你如果没有先执行mvn compile这个目录是不存在的所以扫描前一定保证构建通过。3.3 跑一次完整扫描命令行参数逐个拆解在项目根目录执行mvn clean verify sonar:sonar -Dsonar.projectKeylegacy-order-system \ -Dsonar.projectNamelegacy-order-system \ -Dsonar.projectVersion1.0.0 \ -Dsonar.sourceEncodingUTF-8clean verify是强制重新构建避免上次的编译残留干扰字节码分析。sonar:sonar会调用 Maven Scanner 插件执行扫描。sonar.projectKey是 SonarQube 里项目的唯一标识必须全局唯一如果和已有项目重名扫描结果会覆盖到那个项目上。sonar.projectVersion会显示在项目页面的版本位置CI 里可以直接取构建号。扫描完控制台会输出类似ANALYSIS SUCCESSFUL的字样还会给一个dashboard链接。这里有个细节7.4 的扫描默认是增量式的也就是说它只分析变动的文件而不是全量重扫。第一次扫描是全量后续扫描靠服务端保存的指纹判断变更。如果你发现修改了代码但扫描结果没变化先检查sonar.projectKey是否误指向了别的项目再看sonar.cpd.exclusions是否排除了太多文件。3.4 质量门禁设置覆盖率、重复率、复杂度怎么调SonarQube 7.4 默认自带一套「Sonar way」质量门禁但那是通用配置对老项目太严苛。比如它要求新代码覆盖率不低于 80%很多遗留代码的测试本来就为零一上来就打不通过。我一般是新建一套「Legacy Gate」指标阈值说明Bugs0必须先清零Vulnerabilities0高危漏洞Code Smells不设硬指标逐步优化Coverage≥50%老项目从低开始Duplicated Lines≤3%重复代码比例在 Web 界面「质量配置」里复制默认配置然后修改阈值。重点是「项目」页面里把新门禁配置绑定到具体项目或者在项目权限里让它成为默认门禁。如果你不绑定改了门禁也是白改。我当时就是修改了全局门禁但没重新关联项目扫描后 CI 照样绿灯排查了两轮才发现sonar.qualitygate的关联关系没弄对。4. 常见问题与排查五条血泪踩坑记录4.1 启动即退内置 ES 不允许 root 运行现象执行./sonar.sh start后进程秒退sonar.log只显示了启动的几行信息然后就没有然后了。原因用 root 用户启动了 SonarQube。SonarQube 内置的 Elasticsearch 进程出于安全考虑不允许以 root 身份运行日志里如果没有明确写可以用so_console看更详细输出。解决创建专用账户并切换运行useradd sonar chown -R sonar:sonar /opt/sonarqube su sonar -c /opt/sonarqube/bin/linux-x86-64/sonar.sh start从那以后我每次装新的 SonarQube 都会第一件事创建sonar用户成了肌肉记忆。4.2 数据库连不上驱动、时区、SSL 三个坑现象启动日志报Communications link failure或者Connection refusedWeb 界面一直初始化失败。原因一般有三种。第一种是 MySQL 驱动版本太老识别不了新库的认证方式第二种是 JDBC URL 没带useSSLfalseMySQL 8 默认开启 SSL第三种是连接串里的时区没指定驱动拿系统默认时区结果和数据库会话时区不一致偶尔报The server time zone value。解决如果你用 MySQL把驱动换成mysql-connector-java-5.1.47.jar放在lib/jdbc下同时 URL 加上三件套sonar.jdbc.urljdbc:mysql://localhost:3306/sonar?useUnicodetruecharacterEncodingutf8rewriteBatchedStatementstrueuseSSLfalseserverTimezoneAsia/ShanghaiuseSSLfalse在 5.1.47 里能让很多奇怪的握手中断消息消失serverTimezone则是把驱动和数据库的时区统一。如果你用 PostgreSQL基本不会遇到这几个问题所以我的原则是能用 PostgreSQL 就不碰 MySQL。4.3 中文乱码编码从不统一到强制 UTF-8现象扫描之后问题描述里的中文全部显示成问号或者源码文件里的中文注释被识别成很多无效的代码行。原因项目源码是 GBK 编码而扫描器强制按 UTF-8 读取文件。SonarQube 7.4 的解析器是按配置文件里的sonar.sourceEncoding来解字节流默认是平台编码Linux 上默认 UTF-8读 GBK 文件自然乱。解决先在pom.xml里锁定编码properties project.build.sourceEncodingUTF-8/project.build.sourceEncoding maven.compiler.encodingUTF-8/maven.compiler.encoding /properties接着在扫描命令里也显式指定mvn sonar:sonar -Dsonar.sourceEncodingUTF-8如果项目存量文件本身就是 GBK不可能一次性全部转码我建议在sonar.exclusions里先排除掉那些历史遗留的 GBK 文件等后续逐步转码后再去掉排除规则。这个操作能让你在接手老项目时不至于被成千上万个乱码问题淹没。4.4 覆盖率始终为 0JaCoCo 报告路径没有指定现象代码明明有单测Web 界面显示的覆盖率是 0%或者只有几行。原因SonarQube 不认识 JaCoCo 的 exec 文件需要 JaCoCo 先生成 XML 报告然后在扫描参数里显式告诉 SonarQube 报告路径。很多项目只加了 JaCoCo 插件但没有配置report目标或者执行顺序不对报告根本没生成。解决在pom.xml里配置 JaCoCo并确保verify阶段生成报告plugin groupIdorg.jacoco/groupId artifactIdjacoco-maven-plugin/artifactId version0.8.2/version executions execution goals goalprepare-agent/goal goalreport/goal /goals /execution /executions /plugin扫描参数里加上-Dsonar.coverage.jacoco.xmlReportPathstarget/site/jacoco/jacoco.xmltarget/site/jacoco/jacoco.xml是默认生成路径如果你的项目用了多模块注意每个模块的路径不一样最好用**/target/site/jacoco/jacoco.xml通配。这个参数不设置SonarQube 会扫描 target 目录找 report找不到就报 0%。我见过一套系统覆盖率高达 85%但显示 0%就是这个原因。4.5 页面卡死堆内存与系统参数要一起调现象扫描进行到一半Web 界面响应极慢或者 Elasticsearch 进程被系统杀掉日志提示Out of memory: Kill process。原因SonarQube 本身和计算引擎都要占内存默认的sonar.ce.javaOpts和sonar.web.javaOpts分别只有几百 MB而内置 ES 至少需要 1GB。物理机内存不够时系统 OOM killer 先杀大进程。解决修改conf/sonar.propertiessonar.web.javaOpts-Xms512m -Xmx1024m sonar.ce.javaOpts-Xms512m -Xmx1024m sonar.es.javaOpts-Xms512m -Xmx1024m同时调高系统内核参数否则 ES 会抱怨max virtual memory areas vm.max_map_count [65530] is too lowsysctl -w vm.max_map_count262144 echo vm.max_map_count262144 /etc/sysctl.confvm.max_map_count是进程能映射的最大内存映射区数量ES 用 mmap 加载索引默认 65530 只够并发几十个索引。你如果扫描一个大型多模块项目索引数量轻松破百不调这个参数 ES 直接拒绝启动。这三组内存参数要配合物理机内存调整我一般建议至少 6GB 内存跑 7.4低于这个数就得关掉计算引擎的并行度。5. 进阶把 7.4 变成开发流程里的一道闸门5.1 用 Quality Gate 阻塞 CI 的提交7.4 有个sonar.qualitygate.wait参数设置为true后扫描命令会一直阻塞到 SonarQube 计算出质量门禁结果然后返回非零退出码。CI 里如果扫描失败流水线就中断这样「扫描」就不是摆设了。我在某跨平台系统项目里是这样串的mvn clean verify sonar:sonar \ -Dsonar.qualitygate.waittrue \ -Dsonar.qualitygate.timeout300timeout是等待上限单位秒。一个大型项目扫描加计算门禁要十分钟设成 300 秒可能不够要根据项目历史扫描耗时上调到 600 甚至 900。门禁结果会直接反映在控制台输出里CI 日志里能看到QUALITY GATE STATUS: OK或ERROR比人工看网页靠谱。5.2 自定义规则的一个可复制操作7.4 的界面里规则管理可以自定义 XPath 规则对 XML 文件或某些结构化代码有效。比如我想禁止代码里出现System.out.println可以创建一条规则配方用 XPath//METHOD_INVOCATION[primaryMethod[matches(IMAGE, println)]]这个做法适合做团队内的编码红线。自定义规则保存后要把规则挂到自建的质量配置上然后把项目的「质量配置」指向这个配置。注意自定义规则在 7.4 里不会自动启用你得手动复制默认规则集加入自定义规则再应用到项目。我当时在团队推这条规则时很多人直接往代码里写System.out扫描红灯一亮他们才知道自己违规了比 code review 的提醒有效得多。我从那次之后养成了一个习惯不管给哪个项目接 SonarQube都先把版本矩阵确认一遍JDK、数据库、内存三个边界定下来再动手。装好后也绝不跳过启动日志检查那个SonarQube is up不代表一切正常还要看 ES 后端有没有报memory leak之类的隐性错误。这个检查流程沿用到现在几乎没有在 SonarQube 部署上返过工希望帮到你。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑