本文目录导读:

我来提供一个完整的Java Sonar集成案例,涵盖本地环境和CI/CD流水线两种场景。
环境准备
安装SonarQube服务器
# 使用Docker快速启动SonarQube docker run -d --name sonarqube \ -p 9000:9000 \ -e SONAR_ES_BOOTSTRAP_CHECKS_DISABLE=true \ sonarqube:latest # 默认访问地址:http://localhost:9000 # 默认账号:admin 密码:admin
安装SonarScanner
# macOS brew install sonar-scanner # Linux wget https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-4.8.0.2856-linux.zip unzip sonar-scanner-cli-4.8.0.2856-linux.zip export PATH=$PATH:$(pwd)/sonar-scanner-4.8.0.2856-linux/bin
Maven项目集成
Maven配置(pom.xml)
<project>
<!-- ... 其他配置 ... -->
<properties>
<sonar.java.source>1.8</sonar.java.source>
<sonar.java.target>1.8</sonar.java.target>
<sonar.projectName>${project.artifactId}</sonar.projectName>
<sonar.projectKey>${project.groupId}:${project.artifactId}</sonar.projectKey>
<sonar.host.url>http://localhost:9000</sonar.host.url>
<sonar.login>${env.SONAR_TOKEN}</sonar.login>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.sonarsource.scanner.maven</groupId>
<artifactId>sonar-maven-plugin</artifactId>
<version>3.9.1.2184</version>
</plugin>
<!-- JaCoCo插件用于测试覆盖率 -->
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.8</version>
<executions>
<execution>
<goals>
<goal>prepare-agent</goal>
</goals>
</execution>
<execution>
<id>report</id>
<phase>test</phase>
<goals>
<goal>report</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
执行Sonar扫描
# 设置token(在SonarQube后台生成) export SONAR_TOKEN=your_generated_token # 执行扫描(自动运行测试并收集覆盖率) mvn clean verify sonar:sonar # 或者只运行Sonar分析 mvn sonar:sonar
Gradle项目集成
build.gradle配置
plugins {
id 'java'
id 'org.sonarqube' version '3.5.0.2730'
id 'jacoco'
}
group = 'com.example'
version = '1.0.0'
repositories {
mavenCentral()
}
dependencies {
testImplementation 'org.junit.jupiter:junit-jupiter:5.8.2'
testImplementation 'org.mockito:mockito-core:4.0.0'
}
// Sonar配置
sonarqube {
properties {
property "sonar.projectKey", "com.example:my-project"
property "sonar.projectName", "My Project"
property "sonar.projectVersion", version
property "sonar.host.url", "http://localhost:9000"
property "sonar.login", System.getenv("SONAR_TOKEN")
property "sonar.sourceEncoding", "UTF-8"
property "sonar.java.coveragePlugin", "jacoco"
}
}
// JaCoCo配置
jacocoTestReport {
reports {
xml.enabled true
html.enabled true
}
}
test {
useJUnitPlatform()
finalizedBy jacocoTestReport
}
执行扫描
# 运行测试并生成覆盖率报告 ./gradlew test jacocoTestReport # 执行Sonar扫描 ./gradlew sonarqube
CI/CD集成(Jenkins)
Jenkinsfile配置
pipeline {
agent any
environment {
SONAR_HOST_URL = 'http://sonarqube:9000'
SONAR_TOKEN = credentials('sonar-token')
}
stages {
stage('Checkout') {
steps {
checkout scm
}
}
stage('Build & Test') {
steps {
sh 'mvn clean verify'
}
post {
always {
junit 'target/surefire-reports/*.xml'
}
}
}
stage('SonarQube Analysis') {
steps {
withSonarQubeEnv('SonarQube') {
sh 'mvn sonar:sonar'
}
}
}
stage('Quality Gate') {
steps {
timeout(time: 1, unit: 'HOURS') {
waitForQualityGate abortPipeline: true
}
}
}
}
post {
success {
echo 'Pipeline succeeded!'
// 发送通知等
}
failure {
echo 'Pipeline failed!'
}
}
}
GitLab CI配置(.gitlab-ci.yml)
stages:
- build
- test
- sonar
variables:
SONAR_HOST_URL: "http://sonarqube:9000"
SONAR_TOKEN: $SONAR_TOKEN # 在GitLab中配置
cache:
paths:
- .m2/repository/
build:
stage: build
script:
- mvn clean compile
artifacts:
paths:
- target/
test:
stage: test
script:
- mvn test
- mvn jacoco:report
artifacts:
paths:
- target/surefire-reports/
- target/site/jacoco/
sonar:
stage: sonar
script:
- mvn sonar:sonar -Dsonar.host.url=$SONAR_HOST_URL -Dsonar.login=$SONAR_TOKEN
only:
- master
- develop
- merge_requests
代码质量门禁配置
sonar-project.properties
# 项目基本信息 sonar.projectKey=com.example:my-project sonar.projectName=My Enterprise Project sonar.projectVersion=1.0.0 # 源码目录 sonar.sources=src/main/java sonar.tests=src/test/java # Java版本 sonar.java.source=11 sonar.java.target=11 # 测试覆盖率 sonar.jacoco.reportPath=target/jacoco.exec sonar.junit.reportsPath=target/surefire-reports # 编码规则 sonar.exclusions=**/dto/**,**/config/** sonar.test.exclusions=**/test/** # 质量配置文件 sonar.profile=Sonar way
自定义质量规则(示例)
// 自定义规则示例 - 禁止使用System.out.println
public class CustomRules {
@Rule(
key = "no-system-out",
name = "Avoid System.out.println",
description = "Should use logging framework instead of System.out",
severity = "MAJOR",
tags = {"bad-practice"}
)
public class NoSystemOut extends BaseTreeVisitor implements JavaFileScanner {
private JavaFileScannerContext context;
@Override
public void scanFile(JavaFileScannerContext context) {
this.context = context;
scan(context.getTree());
}
@Override
public void visitMethodInvocation(MethodInvocationTree tree) {
if (isSystemOutPrintln(tree)) {
context.reportIssue(this, tree, "Use logger instead of System.out.println");
}
super.visitMethodInvocation(tree);
}
private boolean isSystemOutPrintln(MethodInvocationTree tree) {
// 检查是否是System.out.println调用
IdentifierTree identifier = (IdentifierTree) tree.methodSelect();
return identifier != null &&
"println".equals(identifier.name()) &&
tree.arguments().size() == 1;
}
}
}
最佳实践案例
多模块项目配置
<!-- 根pom.xml -->
<project>
<modules>
<module>core</module>
<module>service</module>
<module>web</module>
<module>common</module>
</modules>
<properties>
<sonar.coverage.jacoco.xmlReportPaths>
${project.basedir}/../target/site/jacoco/jacoco.xml
</sonar.coverage.jacoco.xmlReportPaths>
</properties>
</project>
Docker集成
FROM maven:3.8.4-jdk-11 AS build WORKDIR /app COPY pom.xml . RUN mvn dependency:go-offline COPY src ./src RUN mvn clean verify FROM sonarsource/sonar-scanner-cli:4.8 AS sonar COPY --from=build /app /app WORKDIR /app CMD ["sonar-scanner", "-Dsonar.projectKey=my-project"]
完整的CI/CD流程示例
# docker-compose.yml
version: '3'
services:
sonarqube:
image: sonarqube:latest
ports:
- "9000:9000"
environment:
- SONAR_ES_BOOTSTRAP_CHECKS_DISABLE=true
volumes:
- sonarqube_data:/opt/sonarqube/data
- sonarqube_extensions:/opt/sonarqube/extensions
jenkins:
image: jenkins/jenkins:lts
ports:
- "8080:8080"
volumes:
- jenkins_home:/var/jenkins_home
environment:
- SONAR_HOST_URL=http://sonarqube:9000
volumes:
sonarqube_data:
sonarqube_extensions:
jenkins_home:
优化与故障排查
性能优化
// 使用增量分析
<properties>
<sonar.scm.disabled>true</sonar.scm.disabled>
<sonar.analysis.mode>incremental</sonar.analysis.mode>
</properties>
常见问题解决
# 问题1: 数据库连接失败 docker logs sonarqube # 问题2: 内存不足 export SONAR_SCANNER_OPTS="-Xmx1g" # 问题3: 扫描超时 sonar-scanner -Dsonar.analysis.timeout=600 # 问题4: 排除特定文件 -Dsonar.exclusions=**/generated/**,**/test/**
监控与告警配置
// 在pom.xml中配置质量门禁
<profile>
<id>sonar-quality-gate</id>
<build>
<plugins>
<plugin>
<groupId>org.sonarsource.scanner.maven</groupId>
<artifactId>sonar-maven-plugin</artifactId>
<executions>
<execution>
<phase>verify</phase>
<goals>
<goal>sonar</goal>
</goals>
<configuration>
<sonarqualitygate>true</sonarqualitygate>
<sonarqualitygateTimeout>300</sonarqualitygateTimeout>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
验证与报告
# 查看分析结果 curl -u admin:admin http://localhost:9000/api/projects/search?key=my-project # 获取质量门禁状态 curl -u admin:admin http://localhost:9000/api/qualitygates/project_status?projectKey=my-project # 导出分析报告 sonar-scanner -Dsonar.report.export.path=sonar-report.json
这个案例涵盖了Java项目Sonar集成的完整流程,从环境搭建到CI/CD集成,再到质量门禁配置,根据实际需求,可以调整相应配置。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播