这里将一些其他的特性和测试覆盖率(主要是 jacoco)
maven 的 scope 主要就是用来限制和管理依赖的传递性,简单的说就是,每一个 scope 都有其对应的特性,并且会决定依赖包在打包和运行时是否会被使用
这里主要谈论的差别是 compile classpath 和 runtime classpath,前者是编译时存在的环境,后者是运行时存在的环境。
总共有 6 个 scopes
compile (default)
这个是默认的 scope,这个 scope 下的依赖会被打包到代码的最终代码里,它也代表着该依赖会被保存到 compile classpath 和 runtime classpath,粗暴的理解就是,打包好的 jar/war 文件会包含 runtime classpath 的代码
provided
这个 scope 代表着在部署时,JDK 或者容器在运行时会提供该依赖,所以在 compile classpath 可以找到这个依赖,但是 runtime classpath 中不会
例子就是 tomcat 这种 servlet api,编译时肯定是需要的,但是部署时肯定,环境里自己会启一个 servlet,因此 runtime classpath 不需要包涵
runtime
这个 scope 意味着依赖在编译时不需要,但是运行时需要,比如说 JDBC driver
test
顾名思义,只需要用在编译和测试,不会打包到最终的代码里
system
这个挺少用的,因为一旦用它就代表着要用到 systemPath
相关,也就会变得非常依赖于系统,似的其可移植性变低
import
比较特殊的 scope,用在 BOM 这种特殊的依赖,主要用来管理其他依赖版本
目前来说,从 central repo 上拉下来的 scope 还是比较准的,比如说 junit 相关的 scope 就是 test,不过这也可以按需修改。
这里分为三个部分:
主要应用场景都是对于依赖/插件的版本控制。重载版本的情况下,越下层(靠近执行项目的 pom)的值会取代上层设置的值
这个主要是通过在父元素中实现 dependencyManagement
,这样子元素中就不用重新声明版本,方便进行统一管理。
在父元素中定义 junit 的版本:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0modelVersion>
<groupId>com.goldenaarcher.productgroupId>
<artifactId>productparentartifactId>
<version>1.0version>
<packaging>pompackaging>
<name>productparentname>
<url>http://www.example.comurl>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>4.11version>
<scope>testscope>
dependency>
dependencies>
dependencyManagement>
<modules>
<module>productservicesmodule>
<module>productwebmodule>
modules>
project>
这个时候,如果子项目中重新声明了版本,eclipse 就会出现这样的报错:
子项目中的 pom 荏苒需要按需定义使用的依赖,只不过就可以跳过版本声明,方便统一管理
插件管理有个相似的 pluginManagement
,不过它需要被放到 build
下:
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.pluginsgroupId>
<artifactId>maven-compiler-pluginartifactId>
<version>3.8.0version>
<configuration>
<release>17release>
configuration>
plugin>
plugins>
pluginManagement>
build>
同理,子项目中也是需要声明同样的插件,但是可以不用实现 version
和 conviguration
除了直接将版本写到 version 中,如果一些依赖(如 spring 全家桶)都需要使用同一个版本,与其重复 cv,也可以在 properties 中声明版本变量,方便管理:
<properties>
<java.version>17java.version>
<junit.version>5.10.0junit.version>
properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.junit.jupitergroupId>
<artifactId>junit-jupiter-engineartifactId>
<version>${junit.version}version>
<scope>testscope>
dependency>
dependencies>
dependencyManagement>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.pluginsgroupId>
<artifactId>maven-compiler-pluginartifactId>
<version>3.8.0version>
<configuration>
<release>${java.version}release>
configuration>
plugin>
plugins>
pluginManagement>
build>
profile 是一些配置型的内容,可以用来重写默认值。
maven 中也可以用不同的项目家在加载不同的配置文件,祈祷方便管理的作用。
选择 quickstart 创建一个新的 demo 项目即可
这里的 profile 和 main 同级,新建 3 个案例即可:
❯ tree src
src
├── main
│ ├── java
│ │ └── com
│ │ └── goldenaarcher
│ │ └── maven
│ │ └── profiledemo
│ │ └── App.java
│ └── profiles
│ ├── dev
│ │ └── application.properties
│ ├── prod
│ │ └── application.properties
│ └── test
│ └── application.properties
└── test
└── java
└── com
└── goldenaarcher
└── maven
└── profiledemo
└── AppTest.java
里面的内容也很简单:
❯ cat src/main/profiles/dev/application.properties
db.url=devurl
db.userName=dev
db.password=dev%
其实 profiles 也可以放在其他地方,我记得一个项目是放到 resources 里,这点看项目习惯
profile 直接放在 xml 下即可:
<profiles>
<profile>
<id>devid>
<properties>
<build.profile.id>devbuild.profile.id>
properties>
<build>
<resources>
<resource>
<directory>src/main/profiles/devdirectory>
resource>
resources>
build>
profile>
<profile>
<id>prodid>
<properties>
<build.profile.id>prodbuild.profile.id>
properties>
<build>
<resources>
<resource>
<directory>src/main/profiles/proddirectory>
resource>
resources>
build>
profile>
<profile>
<id>testid>
<properties>
<build.profile.id>testbuild.profile.id>
properties>
<build>
<resources>
<resource>
<directory>src/main/profiles/testdirectory>
resource>
resources>
build>
profile>
profiles>
只有一个 profile 的话不需要设置 id,有一个以上不设置会报错
语法为: mvn
如:
❯ mvn install -Pdev
[INFO] Scanning for projects...
[INFO]
[INFO] ----------------< com.goldenaarcher.maven:profiledemo >-----------------
[INFO] Building profiledemo 0.0.1-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- maven-resources-plugin:3.0.2:resources (default-resources) @ profiledemo ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] Copying 1 resource
[INFO]
[INFO] --- maven-compiler-plugin:3.8.0:compile (default-compile) @ profiledemo ---
[INFO] Changes detected - recompiling the module!
[INFO] Compiling 1 source file to /Users/usr/study/maven/profiledemo/target/classes
[INFO]
[INFO] --- maven-resources-plugin:3.0.2:testResources (default-testResources) @ profiledemo ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] skip non existing resourceDirectory /Users/usr/study/maven/profiledemo/src/test/resources
[INFO]
[INFO] --- maven-compiler-plugin:3.8.0:testCompile (default-testCompile) @ profiledemo ---
[INFO] Changes detected - recompiling the module!
[INFO] Compiling 1 source file to /Users/usr/study/maven/profiledemo/target/test-classes
[INFO]
[INFO] --- maven-surefire-plugin:2.22.1:test (default-test) @ profiledemo ---
[INFO]
[INFO] -------------------------------------------------------
[INFO] T E S T S
[INFO] -------------------------------------------------------
[INFO] Running com.goldenaarcher.maven.profiledemo.AppTest
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.022 s - in com.goldenaarcher.maven.profiledemo.AppTest
[INFO]
[INFO] Results:
[INFO]
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
[INFO]
[INFO]
[INFO] --- maven-jar-plugin:3.0.2:jar (default-jar) @ profiledemo ---
[INFO] Building jar: /Users/usr/study/maven/profiledemo/target/profiledemo-0.0.1-SNAPSHOT.jar
[INFO]
[INFO] --- maven-install-plugin:2.5.2:install (default-install) @ profiledemo ---
[INFO] Installing /Users/usr/study/maven/profiledemo/target/profiledemo-0.0.1-SNAPSHOT.jar to /Users/usr/.m2/repository/com/goldenaarcher/maven/profiledemo/0.0.1-SNAPSHOT/profiledemo-0.0.1-SNAPSHOT.jar
[INFO] Installing /Users/usr/study/maven/profiledemo/pom.xml to /Users/usr/.m2/repository/com/goldenaarcher/maven/profiledemo/0.0.1-SNAPSHOT/profiledemo-0.0.1-SNAPSHOT.pom
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 2.714 s
[INFO] Finished at: 2023-09-14T22:44:31-04:00
[INFO] ------------------------------------------------------------------------
如果解压打包好的 jar 文件,就能看到里面的 application.properties 内容如下:
❯ cat target/profiledemo-0.0.1-SNAPSHOT/application.properties
db.url=devurl
db.userName=dev
db.password=dev%
这个在 project properties 修改就行:
sonarqube 执行失败
修改 pom:
<build>
<plugins>
<plugin>
<groupId>org.jacocogroupId>
<artifactId>jacoco-maven-pluginartifactId>
<version>0.8.7version>
<executions>
<execution>
<goals>
<goal>prepare-agentgoal>
goals>
execution>
<execution>
<id>reportid>
<phase>testphase>
<goals>
<goal>reportgoal>
goals>
execution>
executions>
plugin>
plugins>
build>
这个 plugin 放到 pluginManagement
下管理会报错,但是拉出来直接放到 build 下就好了,原因未明,从 Stack Overflow 上找到的解决方法:maven jacoco: not generating code coverage report
简单的过一遍 xml 的配置,goal 在 [maven] maven 简述及使用 maven 管理单个项目 提过了,execution 没有。
goal 是 plugin 提供的,这里只是负责调用。
execution 是用来配置 goal 应该在哪个 phase 中执行,这里有两个 execution,第一个 goal 就是 jacoco 提供的 prepare-agent,其他忽略代表着会从头开始执行。
第二个 execution 指定的是生成报告的阶段,生成测试报告的 phase 应该是测试,所以就是在测试这个 phase 执行 report 这个 goal。
运行结果:
# 这里需要用verify不能用test,test会跳过report
❯ mvn clean verify
[INFO] Scanning for projects...
[INFO]
[INFO] -------------< com.goldenaarcher.product:productservices >--------------
[INFO] Building productservices 1.0
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- maven-clean-plugin:3.1.0:clean (default-clean) @ productservices ---
[INFO] Deleting /Users/usr/study/maven/parent/productservices/target
[INFO]
[INFO] --- jacoco-maven-plugin:0.8.7:prepare-agent (default) @ productservices ---
[INFO] argLine set to -javaagent:/Users/usr/.m2/repository/org/jacoco/org.jacoco.agent/0.8.7/org.jacoco.agent-0.8.7-runtime.jar=destfile=/Users/usr/study/maven/parent/productservices/target/jacoco.exec
[INFO]
[INFO] --- maven-resources-plugin:3.0.2:resources (default-resources) @ productservices ---
[WARNING] Using platform encoding (UTF-8 actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] skip non existing resourceDirectory /Users/usr/study/maven/parent/productservices/src/main/resources
[INFO]
[INFO] --- maven-compiler-plugin:3.8.0:compile (default-compile) @ productservices ---
[INFO] Changes detected - recompiling the module!
[WARNING] File encoding has not been set, using platform encoding UTF-8, i.e. build is platform dependent!
[INFO] Compiling 5 source files to /Users/usr/study/maven/parent/productservices/target/classes
[INFO]
[INFO] --- maven-resources-plugin:3.0.2:testResources (default-testResources) @ productservices ---
[WARNING] Using platform encoding (UTF-8 actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] skip non existing resourceDirectory /Users/usr/study/maven/parent/productservices/src/test/resources
[INFO]
[INFO] --- maven-compiler-plugin:3.8.0:testCompile (default-testCompile) @ productservices ---
[INFO] Changes detected - recompiling the module!
[WARNING] File encoding has not been set, using platform encoding UTF-8, i.e. build is platform dependent!
[INFO] Compiling 1 source file to /Users/usr/study/maven/parent/productservices/target/test-classes
[INFO]
[INFO] --- maven-surefire-plugin:2.22.1:test (default-test) @ productservices ---
[INFO]
[INFO] -------------------------------------------------------
[INFO] T E S T S
[INFO] -------------------------------------------------------
[INFO] Running com.goldenaarcher.product.dao.ProductDAOImplTest
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.07 s - in com.goldenaarcher.product.dao.ProductDAOImplTest
[INFO]
[INFO] Results:
[INFO]
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
[INFO]
[INFO]
[INFO] --- jacoco-maven-plugin:0.8.7:report (report) @ productservices ---
[INFO] Loading execution data file /Users/usr/study/maven/parent/productservices/target/jacoco.exec
[INFO] Analyzed bundle 'productservices' with 3 classes
[INFO]
[INFO] --- maven-jar-plugin:3.0.2:jar (default-jar) @ productservices ---
[INFO] Building jar: /Users/usr/study/maven/parent/productservices/target/productservices-1.0.jar
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 4.440 s
[INFO] Finished at: 2023-09-15T00:01:59-04:00
[INFO] ------------------------------------------------------------------------
可以看到,运行到测试这里,jacoco 的 goal 被执行了:jacoco-maven-plugin:0.8.7:report (report) @ productservices
,最终生成报告的目录与结果:
❯ tree target/site
target/site
└── jacoco
├── com.goldenaarcher.product.bo
│ ├── ProductBOImpl.html
│ ├── ProductBOImpl.java.html
│ ├── index.html
│ └── index.source.html
├── com.goldenaarcher.product.dao
│ ├── ProductDAOImpl.html
│ ├── ProductDAOImpl.java.html
│ ├── index.html
│ └── index.source.html
├── com.goldenaarcher.product.dto
│ ├── Product.html
│ ├── Product.java.html
│ ├── index.html
│ └── index.source.html
├── index.html
├── jacoco-resources
│ ├── branchfc.gif
│ ├── branchnc.gif
│ ├── branchpc.gif
│ ├── bundle.gif
│ ├── class.gif
│ ├── down.gif
│ ├── greenbar.gif
│ ├── group.gif
│ ├── method.gif
│ ├── package.gif
│ ├── prettify.css
│ ├── prettify.js
│ ├── redbar.gif
│ ├── report.css
│ ├── report.gif
│ ├── session.gif
│ ├── sort.gif
│ ├── sort.js
│ ├── source.gif
│ └── up.gif
├── jacoco-sessions.html
├── jacoco.csv
└── jacoco.xml
6 directories, 36 files
sonarqube 也是一个挺好用的代码测试工具,不过它需要修改本机 proxy,并启动一个本地服务器去执行剩下的操作,很不幸的是工作机的 proxy 没法改,所以这里就……
它的运行方式还是挺简单的,sonarqube 提供了 sh/bat 文件,直接运行就能启动服务器,登陆后在 dashboard 生成一串登陆编号,maven 运行时添加登录编号 sonarqube 就可以对其进行分析,属于不太要修改 maven 配置的工具