【Jenkins使用之七】代码质量之静态代码分析
一、常用Java静态代码分析工具的分析与比较
Java 静态代码分析(static code analysis)工具能够在代码构建过程中帮助开发人员快速、有效的定位代码缺陷并及时纠正这些问题,从而极大地提高软件可靠性并节省软件开发和测试成本。
常用的有Checkstyle、FindBugs、PMD,他们各有侧重,目前PMD集成阿里的p3c比较流行。
1、PMD
PMD是一款采用BSD协议发布的Java程序代码检查工具。该工具可以做到检查Java代码中是否含有未使用的变量、是否含有空的抓取块、是否含有不必要的对象等。该软件功能强大,扫描效率高,是Java程序员debug的好帮手。
PMD附带了许多可以直接使用的规则,利用这些规则可以找出Java源程序的许多问题,常见的类型如下:
①潜在的bug:空的try/catch/finally/switch语句
②未使用的代码:未使用的局部变量、参数、私有方法等
③可选的代码:String/StringBuffer的滥用
④复杂的表达式:不必须的if语句、可以使用while循环完成的for循环
⑤重复的代码:拷贝/粘贴代码意味着拷贝/粘贴bugs
⑥循环体创建新对象:尽量不要再for或while循环体内实例化一个新对象
⑦资源关闭:Connect,Result,Statement等使用之后确保关闭掉
此外,用户还可以自己定义规则,检查Java代码是否符合某些特定的编码规范,如集成阿里的p3c。
参考:静态分析工具PMD
2、FindBugs
FindBug 是一款开源的 Java 代码检查工具,遵循 GNU 公共许可协议。它可以检查 Java 类或者 JAR 文件,运行的是 Java 字节码而不是源码,检查原理是:将字节码与一组缺陷模式进行对比来发现可能存在的问题,这些问题包括空指针引用、无限递归循环、死锁等。检查的 bug 类型包括:
Malicious code vulnerability:恶意代码
Dodgy code:不符合规范的代码
Internationalization:国际化相关问题,如错误的字符串转换;
Bad practice:坏的实践:常见代码错误,序列化错误,用于静态代码检查时进行缺陷模式匹配;
Multithreaded correctness:多线程的正确性:如多线程编程时常见的同步,线程调度问题;
Performance:运行时性能问题,如由变量定义,方法调用导致的代码低效问题。
Correctness:可能导致错误的代码,如空指针引用等;
Experimental:可能受到的恶意攻击,如访问权限修饰符的定义等;
Security:安全性
参考:
使用 FindBugs-IDEA 插件查找代码中潜在的 BUG
3、CheckStyle
CheckStyle作为检验代码规范的插件,除了可以使用配置默认给定的开发规范,如Sun的,Google的开发规范啊,也可以导入像阿里的开发规范的插件。事实上,每一个公司都存在不同的开发规范要求,所以大部分公司会给定自己的check规范,一般导入给定的checkstyle.xml文件即可实现。
Javadoc 注释:检查类及方法的 Javadoc 注释
命名约定:检查命名是否符合命名规范
标题:检查文件是否以某些行开头
Import 语句:检查 Import 语句是否符合定义规范
代码块大小,即检查类、方法等代码块的行数
空白:检查空白符,如 tab,回车符等
修饰符:修饰符号的检查,如修饰符的定义顺序
块:检查是否有空块或无效块
代码问题:检查重复代码,条件判断,魔数等问题
类设计:检查类的定义是否符合规范,如构造函数的定义等问题
参考:
4、区别
参考:
代码质量检测工具FindBugs、PMD和CheckStyle对比
二、静态代码分析插件集成
通常这些工具都会提供IDE插件、maven插件、jenkins插件、sonarQube插件。
也就是说Checkstyle、FindBugs、PMD有:
针对于开发人员本机的代码检查使用的Eclipse、Idea都有对应的插件;
针对于构建jenkins、maven也有对应的插件,可以生成测试报告,用于自动化构建,避免开发人员不进行本机检查就上传代码的情况(sonarQube出来之前就是使用maven来生成报告);
针对于sonarQube代码管理平台既可以用于开发人员检查代码,也可以集成到自动化构建平台生成检查报告。
注意:为方便在后面的自动化构建中统一,在一个project中事务开发、自动化构建等环节要使用同一种分析工具。
公司里一般涉及两个环节:
1、开发环节
1)开发人员要求使用统一 的IDE(eclipse、Idea),然后安装统一的静态代码检查工具:比如checkStyle检查公司要求的代码规范、PMD或findbugs检查潜在问题代码;
2)当开发人员开发完成功能后,使用这些IDE集成插件检查代码,并修正插件检测出来的问题;
3)将代码提交的版本库(git或者svn);
2、自动构建环节
公司每天进行代码的全量构建,jenkins要事先安装相应的Checkstyle、FindBugs、PMD插件:
1)jenkins从版本库主干或分支拉取源代码;
2)使用maven插件编译;
3)通过maven调用Checkstyle、FindBugs、PMD插件代码检查,如果检测出来相应问题 则构建失败,并将问题、问题代码提交人发邮件通知相关人员修改。
以上两个环节出了使用这些插件以外,目前是使用sonarQube代码质量管理平台来检查,sonarQube除了有自身的检查规则以外,也可以集成Checkstyle、FindBugs、PMD插件,然后生成检查报告。
参考:
Jenkins下配置findbugs、pmd及checkstyle实现代码自动检测
三、SonarQube
SonarQube是一个代码质量数据报告工具,也是代码质量管理平台,相对于Checkstyle、FindBugs、PMD,有更加优秀的图形化界面,以及可以查询出其它软件难以定位到的问题。
SonarQube可以从以下七个维度检测代码质量:
(1)不遵循代码标准:SonarQube可以通过PMD,CheckStyle,Findbugs等等代码规则检测工具规范代码编写。
(2)潜在的缺陷:SonarQube可以通过PMD,CheckStyle,Findbugs等等代码规则检测工具检 测出潜在的缺陷。
(3)糟糕的复杂度分布:文件、类、方法等,如果复杂度过高将难以改变,这会使得开发人员 难以理解它们, 且如果没有自动化的单元测试,对于程序中的任何组件的改变都将可能导致需要全面的回归测试。
(4)重复:显然程序中包含大量复制粘贴的代码是质量低下的,sonar可以展示 源码中重复严重的地方。
(5)注释不足或者过多:没有注释将使代码可读性变差,特别是当不可避免地出现人员变动 时,程序的可读性将大幅下降 而过多的注释又会使得开发人员将精力过多地花费在阅读注释上,亦违背初衷。
(6)缺乏单元测试:SonarQube可以很方便地统计并展示单元测试覆盖率。
(7)糟糕的设计:通过SonarQube可以找出循环,展示包与包、类与类之间的相互依赖关系,可以检测自定义的架构规则 通过sonar可以管理第三方的jar包,可以利用LCOM4检测单个任务规则的应用情况, 检测藕合。
1、SonarQube安装
SonarQube是一个平台,要部署一个专门的Server应用,然后通过界面来管理和查看。SonarQube服务器主要包括web服务器,基于ElasticSearch的搜索服务器,计算引擎服务器。其中,web服务器,是供开发人员浏览查看代码分析结果,进行相应的配置等。计算引擎服务器主要是处理代码分析报表并将其存储在数据库。SonarQube数据库用来存储配置信息和代码分析报表。
关于SonarQube没有权威的书籍,只能查看官网文档:https://docs.sonarqube.org/ 选择相应版本查看就可以了。
(1)关于安装jdk、mysql、maven版本
jdk:jdk1.8
mysql:要求>=5.6 && < 8.0,默认是H2 embbed 内存类型数据库,用来保存元数据信息,为了长期管理肯定要用持久化数据库,这里选用mysql,当然也可以选择其他的。
maven:3.6.3
(2)下载SonarQube CE版本(其他版本收费):http://www.sonarqube.org/downloads/
SonarQube-7.8依赖Java 8,且支持mysql管理元数据的最后版本,以后的版本需要jdk11且不支持mysql 管理配置元数据。
(3)解压
[root@node106 src]# unzip sonarqube-7.8.zip -d /usr/local
(4)配置
修改为mysql数据库,url是数据库连接地址,username是数据库用户名,jdbc.password是数据库密码,login是sonarqube的登录名,sonar.password是sonarqube的密码
[root@node106 conf]# vim /usr/local/sonarqube-7.8/conf/sonar.properties
sonar.jdbc.url=jdbc:mysql://192.168.0.141:3306/qjfsonar?useUnicode=true&characterEncoding=utf8&rewriteBatchedStatements=true&useConfigs=maxPerformance
sonar.jdbc.username=gmsd
sonar.jdbc.password=gmsdtrade
sonar.sorceEncoding=UTF-8
sonar.login=admin
sonar.password=admin
(5)启动
#默认端口sonar.web.port=9000 可以修改
[root@node106 linux-x86-64]# /usr/local/sonarqube-7.8/bin/linux-x86-64/sonar.sh start
Starting SonarQube...
Started SonarQube.
报错:
1)、org.elasticsearch.bootstrap.StartupException: java.lang.RuntimeException: can not run elasticsearch as root
sonarqube里面有elasticsearch组件,ES不允许使用root启动,新建普通用户启动。
2)、[2] bootstrap checks failed
[1]: max file descriptors [4096] for elasticsearch process is too low, increase to at least [65535]
[2]: max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144]
修改/etc/security/limits.conf 后面追加如下内容:
[root@node106 conf]# vim /etc/security/limits.conf
* soft nofile 65536
* hard nofile 65536
* soft memlock unlimited
* hard memlock unlimited
3)、[1] bootstrap checks failed
[1]: max virtual memory areas vm.max_map_count [65536] is too low, increase to at least [262144]
#修改/etc/sysctl.conf
[root@node106 logs]# vim /etc/sysctl.conf
[root@node106 logs]# sysctl -p
vm.max_map_count = 655360
#注意修改后重新登录 才能生效
4)、java.lang.IllegalStateException: Fail to connect to database
修改mysql允许sonarQube所在的主机访问
grant all privileges on *.* to root@'%' identified by "123456";
完全启动需要较长时间:
(6)安装中文插件
进入Marketplace查找插件 并进行install
目前插件市场里提供匹配最新8.4版本的汉化插件,和我安装的7.8版本不匹配,install时会报错:
我们要下载7.8 对应版本中文插件 sonar-l10n-zh-plugin-1.28.jar,地址:https://github.com/SonarQubeCommunity/sonar-l10n-zh/releases
然后放入 sonarqube-7.8/extensions/plugins 目录
[root@node106 plugins]# pwd
/usr/local/sonarqube-7.8/extensions/plugins
[root@node106 plugins]# ll
total 88032
-rw-r--r-- 1 sonar sonar 224 Jun 17 2019 README.txt
-rw-r--r-- 1 sonar sonar 287504 Jun 17 2019 sonar-auth-github-plugin-1.5.0.870.jar
-rw-r--r-- 1 sonar sonar 3388540 Jun 17 2019 sonar-auth-saml-plugin-1.1.0.181.jar
-rw-r--r-- 1 sonar sonar 4092977 Jun 17 2019 sonar-csharp-plugin-7.14.0.8411.jar
-rw-r--r-- 1 sonar sonar 7016445 Jun 17 2019 sonar-css-plugin-1.1.0.993.jar
-rw-r--r-- 1 sonar sonar 1551459 Jun 17 2019 sonar-flex-plugin-2.4.0.1222.jar
-rw-r--r-- 1 sonar sonar 3903342 Jun 17 2019 sonar-go-plugin-1.1.1.2000.jar
-rw-r--r-- 1 sonar sonar 1727846 Jun 17 2019 sonar-html-plugin-3.1.0.1615.jar
-rw-r--r-- 1 sonar sonar 14629 Jun 17 2019 sonar-jacoco-plugin-1.0.1.143.jar
-rw-r--r-- 1 sonar sonar 8302512 Jun 17 2019 sonar-java-plugin-5.13.0.18197.jar
-rw-r--r-- 1 sonar sonar 6866969 Jun 17 2019 sonar-javascript-plugin-5.2.1.7778.jar
-rw-r--r-- 1 sonar sonar 7595999 Jun 17 2019 sonar-kotlin-plugin-1.5.0.315.jar
-rw-r--r-- 1 sonar sonar 47581 Sep 8 09:53 sonar-l10n-zh-plugin-1.28.jar
-rw-r--r-- 1 sonar sonar 300503 Jun 17 2019 sonar-ldap-plugin-2.2.0.608.jar
-rw-r--r-- 1 sonar sonar 5107348 Jun 17 2019 sonar-php-plugin-3.1.1.4762.jar
-rw-r--r-- 1 sonar sonar 2752193 Jun 17 2019 sonar-python-plugin-1.14.0.3086.jar
-rw-r--r-- 1 sonar sonar 10036210 Jun 17 2019 sonar-ruby-plugin-1.5.0.315.jar
-rw-r--r-- 1 sonar sonar 9202024 Jun 17 2019 sonar-scala-plugin-1.5.0.315.jar
-rw-r--r-- 1 sonar sonar 2622236 Jun 17 2019 sonar-scm-git-plugin-1.8.0.1574.jar
-rw-r--r-- 1 sonar sonar 7229293 Jun 17 2019 sonar-scm-svn-plugin-1.9.0.1295.jar
-rw-r--r-- 1 sonar sonar 2239156 Jun 17 2019 sonar-typescript-plugin-1.9.0.3766.jar
-rw-r--r-- 1 sonar sonar 3576923 Jun 17 2019 sonar-vbnet-plugin-7.14.0.8411.jar
-rw-r--r-- 1 sonar sonar 2242738 Jun 17 2019 sonar-xml-plugin-2.0.1.2020.jar
安装完成后需要重启sonarQube:
2、客户端
参见官网:Analyzing Source Code
SonarQube按照代码是否在本地还是托管分为本地分析和远程分析:
本地分析对应的客户端常用有三种:sonar-scanner、使用maven(gradle)插件、使用IDE插件sonarLint,另还有Ant Task 现在用的少了。
远程分析对应客户端是集成到jenkins里的sonar-scanner插件;
(一)本地分析
第一种客户端:sonar-scanner方式
SonarQube为代码检查的server,并提供可视化界面;sonar-scanner为client,进行分析并将分析报告并且发送到server中,也就是传统的C/S关系。
使用场景除了java、C++以外,其他语言scala,python,php或者一个项目使用多种语言时通过以下方式使用sonar-scanner(下载地址:https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/),这里使用sonar-scanner-cli-4.2.0.1873-windows.zip。在sonar-scanner早期版本叫sonar-runner注意版本太低会报错:Fail to download libraries from server。
示例拓扑:
这里我们将SonarQube服务端安装在192.168.118.106 linux上,然后将sonar-scanner安装在192.168.0.141 win7上,然后使用sonar-scanner扫描win7上工程E:\srcs\mybatis-3-mybatis-3.5.4里的代码。
(1)解压sonar-scanner-cli-4.2.0.1873-windows.zip
(2)配置 连接SonarQube同一个数据库 D:\sonar-scanner-cli-4.2.0.1873\conf\sonar-runner.properties
#Configure here general information about the environment, such as SonarQube server connection details for example
#No information about specific project should appear here
#----- Default SonarQube server SonarQube服务端
sonar.host.url=http://192.168.118.106:9000
#----- Default source code encoding
sonar.sourceEncoding=UTF-8
(3)设置环境变量
(4)示例工程mybatis-3-mybatis-3.5.4
在要进行代码分析的项目根目录下,新建sonar-project.properties文件
#----- Global database settings (not used for SonarQube 5.2+) 数据库用户和密码
sonar.jdbc.username=root
sonar.jdbc.password=123456
#----- MySQL mysql数据库连接 要和SonarQube服务端使用同一个数据库
sonar.jdbc.url=jdbc:mysql://192.168.0.141:3306/sonar?useUnicode=true&characterEncoding=utf8
sonar.login=admin
sonar.password=admin
# 项目key 保证唯一
sonar.projectKey=mybatis-3-mybatis-3.5.4
# 项目名字
sonar.projectName=mybatis-3-mybatis-3.5.4
sonar.projectVersion=3.5.4
sonar.language=java
sonar.modules=java-module
# sonar.sources是源文件所在的目录 注意如果下面还有css文件会要求安装Node.js
java-module.sonar.sources=src/main/java
java-module.sonar.projectBaseDir=.
# 指定class目录 从sonarQube 4.12开始,sonar将会进行程序的动态检查,不配置sonar.java.binaries属性将会出错
sonar.java.binaries=target/classes
# Encoding of the source code. Default is default system encoding
#sonar.sourceEncoding=UTF-8
(5)然后在该目录下打开命令运行窗口,执行sonar-scanner命令,分析成功之后显示如下:
到sonarQube界面查看
第二种方式:使用maven、gradle扫描方式
这里展示使用maven两种整合方式,前提项目是maven项目。
(1)修改$MAVEN_HOME/conf/settings.xml
<?xml version="1.0" encoding="UTF-8"?> <settings xmlns="http://maven.apache.org/SETTINGS/1.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd"> <localRepository>E:\workspace\repository</localRepository> <pluginGroups> <pluginGroup>org.sonarsource.scanner.maven</pluginGroup> </pluginGroups> <proxies> </proxies> <servers> <server> <id>releases</id> <username>admin</username> <password>Aa123456</password> </server> <server> <id>snapshots</id> <username>admin</username> <password>Aa123456</password> </server> </servers> <mirrors> <mirror> <id>alimaven</id> <name>aliyun maven</name> <url>http://maven.aliyun.com/nexus/content/groups/public/</url> <mirrorOf>central</mirrorOf> </mirror> </mirrors> <profiles> <profile> <id>sonar</id> <activation> <activeByDefault>true</activeByDefault> </activation> <properties> <sonar.host.url> http://192.168.118.106:9000 </sonar.host.url> </properties> </profile> </profiles> </settings>
(2)到Maven项目的根目录执行如下命令,即可使用SonarQube分析项目
方式一:直接在含有pom.xml的目录执行分析
mvn clean verify sonar:sonar -Dmaven.test.skip=true
方式二:多模块情况下 先执行install 确保代码最新
mvn clean install -Dmaven.test.skip=true
#然后执行分析 注意需要添加-Dsonar.java.binaries参数
mvn sonar:sonar
方式三:指定sonar的插件版本
mvn org.sonarsource.scanner.maven:sonar-maven-plugin:3.6.0.1398:sonar
建议可以在项目的pom.xml指定sonar-maven-plugin插件版本
<build> <pluginManagement> <plugins> <plugin> <groupId>org.sonarsource.scanner.maven</groupId> <artifactId>sonar-maven-plugin</artifactId> <version>3.6.0.1398</version> </plugin> </plugins> </pluginManagement> </build>
第三中方式:使用IDE插件sonarLint
这里以idea使用sonarLint举例,注意这种方式检查报告旨在idea里查看,sonaQube里看不到
(1)安装插件
插件里搜索sonarLint 然后install
使用方式(一)
(2)sonarLint全局配置 配置sonarQube服务器
(3)项目设置
SonarLint-->Project Setting配置选项卡中配置项目信息,勾选Binding project to SonarQube / SonarCloud,在Connection下拉框中选中刚刚配置好的服务链接,在project选项中点击Search in list选择相应的项目,点击OK;
注意这种方式是查询工程下面有sonar-project.properties的工程
(4)扫描后查看报告
使用方式(二)
(1)在需要进行代码分析的项目上点击右键,依次选择:AnaLyze—> AnaLyze with SonarLint(或者再SonarLint报告选项卡中点击AnaLyze All Project Files图标)在弹出对话框中点击Preceed,等待项目代码分析完毕;
(2)代码分析完毕后,在“SonarQube Report”选项卡中会显示代码分析结果,可对单个文件展开,显示该文件中的各个问题,单击某一条结果,可在右侧Rule选项卡中看到对问题的详细描述,双击某一条记录,可以快速跳转至该条结果对应的代码的位置;
(3)SonarLint插件默认是自动进行代码检查,但是为了保证代码检查结果的实时性和有效性,在每完成一定数量的代码以后,我们就对代码进行分析。
(二)远程分析-整合jenkins
3、界面使用教程
sonarQube参考: