Java Sonar集成案例

wen java案例 1

本文目录导读:

Java Sonar集成案例

  1. 环境准备
  2. Maven项目集成
  3. Gradle项目集成
  4. CI/CD集成(Jenkins)
  5. 代码质量门禁配置
  6. 最佳实践案例
  7. 优化与故障排查
  8. 验证与报告

我来提供一个完整的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集成,再到质量门禁配置,根据实际需求,可以调整相应配置。

抱歉,评论功能暂时关闭!