Maven基本使用(上)
1、Maven环境
$ java -version
java version "1.8.0_77"
Java(TM) SE Runtime Environment (build 1.8.0_77-b03)
Java HotSpot(TM) 64-Bit Server VM (build 25.77-b03, mixed mode)
$ mvn -version
Apache Maven 3.3.9 (bb52d8502b132ec0a5a3f4c09453c07478323dc5; 2015-11-11T00:41:47+08:00)
Maven home: D:\DecompressionSoftwareInstall\apache-maven-3.3.9-bin
Java version: 1.8.0_77, vendor: Oracle Corporation
Java home: D:\OwnerSoftwareInstall\jdk\jre
Default locale: zh_CN, platform encoding: GBK
OS name: "windows 10", version: "10.0", arch: "amd64", family: "dos"
# 插件使用
$ mvn 插件名称:help
2、Maven Hello World
2.1 pom文件
<?xml version="1.0" encoding="UTF-8"?>
<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/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>hello-maven</artifactId>
<version>1.0-SNAPSHOT</version>
<name>maven hello world</name>
</project>
2.2 主程序
package org.apache;
/**
* @author zhangshixing
*/
public class HelloWorld {
public String sayHello(){
return "Hello Maven";
}
public static void main(String[] args) {
System.out.println(new HelloWorld().sayHello());
}
}
2.3 编译
$ mvn clean compile
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building maven hello world 1.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
......
[INFO] Compiling 1 source file to C:\Users\zhangshixing\Desktop\HelloMaven\target\classes
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 1.100 s
[INFO] Finished at: 2023-10-02T07:42:02+08:00
[INFO] Final Memory: 13M/209M
[INFO] ------------------------------------------------------------------------
2.4 pom添加依赖
<?xml version="1.0" encoding="UTF-8"?>
<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/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>hello-maven</artifactId>
<version>1.0-SNAPSHOT</version>
<name>maven hello world</name>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
2.5 编写测试
package org.apache;
import static org.junit.Assert.assertEquals;
import org.junit.Test;
public class HelloWorldTest {
@Test
public void testSayHello(){
HelloWorld helloWorld = new HelloWorld();
String result = helloWorld.sayHello();
assertEquals("Hello Maven",result);
}
}
2.6 编译测试
$ mvn clean test
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building maven hello world 1.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
......
[INFO] Surefire report directory: C:\Users\zhangshixing\Desktop\HelloMaven\target\surefire-reports
-------------------------------------------------------
T E S T S
-------------------------------------------------------
Running org.apache.HelloWorldTest
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.049 sec
Results :
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 1.701 s
[INFO] Finished at: 2023-10-02T08:00:56+08:00
[INFO] Final Memory: 15M/212M
[INFO] ------------------------------------------------------------------------
2.7 设置编译版本
<?xml version="1.0" encoding="UTF-8"?>
<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/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>hello-maven</artifactId>
<version>1.0-SNAPSHOT</version>
<name>maven hello world</name>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.10.1</version>
<configuration>
<source>1.8</source>
<source>1.8</source>
</configuration>
</plugin>
</plugins>
</build>
</project>
2.8 编译
$ mvn clean test
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building maven hello world 1.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
......
[INFO] Surefire report directory: C:\Users\zhangshixing\Desktop\HelloMaven\target\surefire-reports
-------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 1.686 s
[INFO] Finished at: 2023-10-02T08:45:48+08:00
[INFO] Final Memory: 15M/210M
[INFO] ------------------------------------------------------------------------
2.9 安装程序
$ mvn clean install
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building maven hello world 1.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
......
[INFO] Surefire report directory: C:\Users\zhangshixing\Desktop\HelloMaven\target\surefire-reports
-------------------------------------------------------
T E S T S
-------------------------------------------------------
Running org.apache.HelloWorldTest
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.048 sec
Results :
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
[INFO]
[INFO] --- maven-jar-plugin:2.4:jar (default-jar) @ hello-maven ---
[INFO] Building jar: C:\Users\zhangshixing\Desktop\HelloMaven\target\hello-maven-1.0-SNAPSHOT.jar
[INFO]
[INFO] --- maven-install-plugin:2.4:install (default-install) @ hello-maven ---
[INFO] Installing C:\Users\zhangshixing\Desktop\HelloMaven\target\hello-maven-1.0-SNAPSHOT.jar to D:\DecompressionSoftwareInstall\apache-maven-3.3.
9-bin\repository\org\example\hello-maven\1.0-SNAPSHOT\hello-maven-1.0-SNAPSHOT.jar
[INFO] Installing C:\Users\zhangshixing\Desktop\HelloMaven\pom.xml to D:\DecompressionSoftwareInstall\apache-maven-3.3.9-bin\repository\org\example
\hello-maven\1.0-SNAPSHOT\hello-maven-1.0-SNAPSHOT.pom
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 1.797 s
[INFO] Finished at: 2023-10-02T08:48:54+08:00
[INFO] Final Memory: 17M/213M
[INFO] ------------------------------------------------------------------------
2.10 运行打包后的程序
到目前为止,还没有运行Hello World项目,不要忘了 HelloWorld类可是有一个main 方法的。默认打包生成的jar
是不能够直接运行的,因为带有main 方法的类信息不会添加到manifest中(打开jar文件中的 META-
INF/MANIFEST.MF文件,将无法看到 Main-Class 一行)。为了生成可执行的jar 文件,需要借助 maven-shade-
plugin,配置该插件如下:
<?xml version="1.0" encoding="UTF-8"?>
<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/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>hello-maven</artifactId>
<version>1.0-SNAPSHOT</version>
<name>maven hello world</name>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.10.1</version>
<configuration>
<source>1.8</source>
<source>1.8</source>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.2.4</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>org.apache.HelloWorld</mainClass>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
编译打包:
$ mvn clean package
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building maven hello world 1.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
......
[INFO] Surefire report directory: C:\Users\zhangshixing\Desktop\HelloMaven\target\surefire-reports
-------------------------------------------------------
T E S T S
-------------------------------------------------------
Running org.apache.HelloWorldTest
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.048 sec
Results :
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
[INFO]
[INFO] --- maven-jar-plugin:2.4:jar (default-jar) @ hello-maven ---
[INFO] Building jar: C:\Users\zhangshixing\Desktop\HelloMaven\target\hello-maven-1.0-SNAPSHOT.jar
[INFO]
[INFO] --- maven-shade-plugin:3.2.4:shade (default) @ hello-maven ---
[INFO] Replacing original artifact with shaded artifact.
[INFO] Replacing C:\Users\zhangshixing\Desktop\HelloMaven\target\hello-maven-1.0-SNAPSHOT.jar with C:\Users\zhangshixing\Desktop\HelloMaven\target\
hello-maven-1.0-SNAPSHOT-shaded.jar
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 2.043 s
[INFO] Finished at: 2023-10-02T09:06:12+08:00
[INFO] Final Memory: 17M/209M
[INFO] ------------------------------------------------------------------------
查看 hello-maven-1.0-SNAPSHOT.jar
文件中 META-INF\MANIFEST.MF
文件的内容:
Manifest-Version: 1.0
Archiver-Version: Plexus Archiver
Built-By: zhangshixing
Created-By: Apache Maven 3.3.9
Build-Jdk: 1.8.0_77
Main-Class: org.apache.HelloWorld
运行项目:
$ java -jar hello-maven-1.0-SNAPSHOT.jar
Hello Maven
3、使用Archetype生成项目骨架
# 交互式
mvn archetype:generate
# 非交互式
mvn archetype:generate -DgroupId=com.mycompany.app -DartifactId=myapp -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false
$ mvn archetype:generate -DgroupId=com.mycompany.app -DartifactId=myapp -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building Maven Stub Project (No POM) 1
[INFO] ------------------------------------------------------------------------
......
[INFO] ----------------------------------------------------------------------------
[INFO] Using following parameters for creating project from Old (1.x) Archetype: maven-archetype-quickstart:1.0
[INFO] ----------------------------------------------------------------------------
[INFO] Parameter: basedir, Value: C:\Users\zhangshixing\Desktop\新建文件夹 (2)
[INFO] Parameter: package, Value: com.mycompany.app
[INFO] Parameter: groupId, Value: com.mycompany.app
[INFO] Parameter: artifactId, Value: myapp
[INFO] Parameter: packageName, Value: com.mycompany.app
[INFO] Parameter: version, Value: 1.0-SNAPSHOT
[INFO] project created from Old (1.x) Archetype in dir: C:\Users\zhangshixing\Desktop\新建文件夹 (2)\myapp
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 3.394 s
[INFO] Finished at: 2023-10-02T09:22:59+08:00
[INFO] Final Memory: 18M/219M
[INFO] ------------------------------------------------------------------------
# 生成的目录结构
myapp/
├── pom.xml
└── src
├── main
│ └── java
│ └── com
│ └── mycompany
│ └── app
│ └── App.java
└── test
└── java
└── com
└── mycompany
└── app
└── AppTest.java
<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/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.mycompany.app</groupId>
<artifactId>myapp</artifactId>
<packaging>jar</packaging>
<version>1.0-SNAPSHOT</version>
<name>myapp</name>
<url>http://maven.apache.org</url>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
package com.mycompany.app;
/**
* Hello world!
*
*/
public class App
{
public static void main( String[] args )
{
System.out.println( "Hello World!" );
}
}
package com.mycompany.app;
import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;
/**
* Unit test for simple App.
*/
public class AppTest
extends TestCase
{
/**
* Create the test case
*
* @param testName name of the test case
*/
public AppTest( String testName )
{
super( testName );
}
/**
* @return the suite of tests being tested
*/
public static Test suite()
{
return new TestSuite( AppTest.class );
}
/**
* Rigourous Test :-)
*/
public void testApp()
{
assertTrue( true );
}
}
4、坐标和依赖
4.1 坐标详解
Maven 坐标为各种构件引入了秩序,任何一个构件都必须明确定义自己的坐标,而一组 Maven 坐标是通过一些
元素定义的,它们是 groupld、artifactld、version、packaging、classifier。
<groupId>org.sonatype.nexus</groupId>
<artifactId>nexus-indexer</artifactId>
<version>2.0.0</ersion>
<packaging>jar</packaging>
这是 nexus-indexer 的坐标定义,nexus-indexer 是一个对 Maven 仓库编纂索引并提供搜索功能的类库,它是
Nexus 项目的一个子模块。后面会详细介绍 Nexus。
上述代码片段中,其坐标分别为 groupId:org.sonatype.nexus、artifactId:nexus-indexer、version:2.0.0、
packaging:jar,没有 classifier。
下面详细解释一下各个坐标元素:
-
groupId
:定义当前Maven项目隶属的实际项目。 -
artifactId
:该元素定义实际项目中的一个Maven 项目(模块),推荐的做法是使用实际项目名称作为artifactId 的前缀。
-
version
:该元素定义 Maven 项目当前所处的版本。 -
packaging
:该元素定义 Maven 项目的打包方式,默认是jar打包方式。 -
classifier
:该元素用来帮助定义构建输出的一些附属构件。
上述5个元素中,groupld,artifactld,version 是必须定义的,packaging 是可选的(默认为jar),而classifier是不
能直接定义的。同时,项目构件的文件名是与坐标相对应的,一般的规则为:
artifactld-version [-classifier].packaging
,[-classifier]
表示可选。
这里还要强调的一点是,packaging并非一定与构件扩展名对应,比如 packaging 为 maven-plugin 的构件扩展名
为jar。
4.2 dependency元素介绍
<dependency>
<groupId></groupId>
<artifactId></artifactId>
<version></version>
<type></type>
<optional></optional>
<scope></scope>
<classifier></classifier>
<systemPath></systemPath>
<exclusions></exclusions>
</dependency>
groupld、artifactld、version
:依赖的基本坐标,对于任何一个依赖来说,基本坐标是最重要的,Maven 根
据坐标才能找到需要的依赖。type 的默认值是 jar,classifier 的默认值是 null。
4.2.1 type依赖类型
依赖的类型,对应于项目坐标定义的 packaging。大部分情况下,该元素不必声明,其默认值为 jar。type 的值一
般有 jar、war、pom 等,声明引入的依赖的类型。
4.2.2 optional可选依赖
假设有这样一个依赖关系,项目A 依赖于项目B,项目B 依赖于项目X 和Y,B 对于X 和Y 的依赖都是可选依赖:
A->B、B->X(可选)、B->Y(可选)。根据传递性依赖的定义,如果所有这三个依赖的范围都是 compile,那么 X、Y
就是A 的 compile 范围传递性依赖。然而,由于这里X、Y 是可选依赖,依赖将不会得以传递。换句话说, X、Y
将不会对A有任何影响。
假如 B 是一个持久层隔离工具包,它支持多种数据库,包括 MySQL、PostgreSQL 等,在构建这个工具包的时
候,需要这两种数据库的驱动程序,但在使用这个工具包的时候,只会依赖一种数据库。
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.xiaoshan.mvnbook</groupId>
<artifactId>project-b</artifactId>
<version>1.0.0</version>
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.10</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>8.4-701.jdbc3</version>
<optional>true</optional>
</dependency>
</dependencies>
</project>
上述 XML代码片段中,使用<optional>
元素表示 mysql-connector-java
和 postgresql
这两个依赖为可选
依赖,它们只会对当前项目B产生影响,当其他项目依赖于B的时候,这两个依赖不会被传递。因此,当项目A依赖
于项目B的时候,如果其实际使用基于MySQL数据库,那么在项目A中就需要显式地声明 mysgl-connector-java
这一依赖。
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.xiaoshan.mvnbook</groupId>
<artifactId>project-a</artifactId>
<version>1.0.0</version>
<dependencies>
<dependency>
<groupId>com.xiaoshan.mvnbook</groupId>
<artifactId>project-b</artifactId>
<version>1.0.0</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.10</version>
</dependency>
</dependencies>
</project>
4.2.3 scope依赖范围
Maven 有以下几种依赖范围:
-
compile
:编译依赖范围。如果没有指定,就会默认使用该依赖范围。使用此依赖范围的 Maven 依赖,对于编译、测试、运行三种 classpath 都有效。典型的例子是 spring-core,在编译、测试和运行的时候都需要使
用该依赖。
-
test
:测试依赖范围。使用此依赖范围的 Maven 依赖,只对于测试classpath 有效,在编译主代码或者运行项目的使用时将无法使用此类依赖。典型的例子是 JUnit,它只有在编译测试代码及运行测试的时候才需要。
-
provided
:已提供依赖范围。使用此依赖范围的 Maven 依赖,对于编译和测试 class-path 有效,但在运行时无效。典型的例子是 servlet-api,编译和测试项目的时候需要该依赖,但在运行项目的时候,由于容器已经
提供,就不需要 Maven 重复地引入一遍。
-
runtime
:运行时依赖范围。使用此依赖范围的 Maven依赖,对于测试和运行 class-path 有效,但在编译主代码时无效。典型的例子是JDBC驱动实现,项目主代码的编译只需要JDK提供的JDBC接口,只有在执行测试
或者运行项目的时候才需要实现上述接口的具体JDBC驱动。
-
system
:系统依赖范围。该依赖与三种 classpath 的关系,和provided 依赖范围完全一致。但是,使用system 范围的依赖时必须通过 systemPath 元素显式地指定依赖文件的路径。由于此类依赖不是通过Maven
仓库解析的,而且往往与本机系统绑定,可能造成构建的不可移植,因此应该谨慎使用。systemPath 元素可
以引用环境变量。
-
import
(Maven 2.0.9及以上):导入依赖范围。该依赖范围不会对三种 classpath 产生实际的影响。
上述除 import 以外的各种依赖范围与三种 classpath 的关系如下表所示。
依赖范围(Scope) | 对于编译classpath有效 | 对于测试classpath有效 | 对于运行时classpath有效 | 例子 |
---|---|---|---|---|
compile | ✔️ | ✔️ | ✔️ | spring-core |
test | - | ✔️ | - | Junit |
provided | ✔️ | ✔️ | - | servlet-api |
runtime | - | ✔️ | ✔️ | JDBC驱动 |
system | ✔️ | ✔️ | - | 本地的 maven仓库之外的类库文件 |
4.2.4 exclusions依赖排除
依赖排除,就是有时候引入某一个依赖的时候,该依赖下有 jar 包冲突,可以排除掉,不引用该 jar。
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.xiaoshan.mvnbook</groupId>
<artifactId>project-a</artifactId>
<version>1.0.0</version>
<dependencies>
<dependency>
<groupId>com.xiaoshan.mvnbook</groupId>
<artifactId>project-b</artifactId>
<version>1.0.0</version>
<exclusions>
<exclusion>
<groupId>com.xiaoshan.mvnbook</groupId>
<artifactId>project-c</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.xiaoshan.mvnbook</groupId>
<artifactId>project-c</artifactId>
<version>1.1.0</version>
</dependency>
</dependencies>
</project>
4.2.5 systemPath
当 maven 依赖本地而非 repository 中的 jar 包,sytemPath 指明本地 jar 包路径。
<dependency>
<groupId>javax.sql</groupId>
<artifactId>jdbc-stdext</artifactId>
<version>2.0</version>
<scope>system</scope>
<systemPath>${java.home)/lib/rt.jar</systemPath>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-core</artifactId>
<version>1.5</version>
<scope>system</scope>
<systemPath>${basedir}/WebContent/WEB-INF/lib/hamcrest-core-1.3.jar</systemPath>
</dependency>
4.2.6 classifier
Classifier 可能是最容易被忽略的 Maven 特性,但它确实非常重要,我们也需要它来帮助规划坐标。设想这样一
个情况,有一个jar项目,就说是 dog-cli-1.0.jar 吧,运行它用户就能在命令行上画一只小狗出来。现在用户的要
求是希望你能提供一个zip包,里面不仅包含这个可运行的jar,还得包含源代码和文档,换句话说,这是比较正式
的分发包。这个文件名应该是怎样的呢? dog-cli-1.0.zip? 不够清楚,仅仅从扩展名很难分辨什么是 Maven 默认生
成的构件,什么是额外配置生成分发包。如果能是dog-cli-1.0-dist.zip就最好了。这里的dist就是classifier,默认
Maven只生成一个构件,我们称之为主构件,那当我们希望Maven生成其他附属构件的时候,就能用上
classifier。常见的classifier还有如dog-cli-1.0-sources.jar表示源码包,dog-cli-1.0-javadoc.jar表示JavaDoc包等
等。
classifier 它表示在相同版本下针对不同的环境或者jdk使用的jar,如果配置了这个元素,则会将这个元素名在加在
最后来查找相应的jar。
<!-- 上面的例子 -->
<classifier>sources</classifier>
<classifier>javadoc</classifier>
<!-- 给相同的version,构建不同的环境使用依赖 -->
<classifier>jdk17</classifier>
<classifier>jdk18</classifier>
4.3 依赖传递
scope元素的值会对这种传递依赖会有影响。
假设A依赖于B,B依赖于C,我们说A对于B是第一直接依赖,B对于C是第二直接依赖,而A对于C是传递性依赖,
而第一直接依赖的scope和第二直接依赖的scope决定了传递依赖的范围,即决定了A对于C的scope的值。
下面我们用表格来列一下这种依赖的效果,表格最左边一列表示第一直接依赖(即A->B的scope的值),而表格中的
第一行表示第二直接依赖(即B->C的scope的值),行列交叉的值显示的是A对于C最后产生的依赖效果。
compile | test | provided | runtime | |
---|---|---|---|---|
compile | compile | - | - | runtime |
test | test | - | - | test |
provided | provided | - | provided | provided |
runtime | runtime | - | - | runtime |
解释一下:
比如A->B的scope是compile,而B->C的scope是test,那么按照上面表格中,对应第2行第3列的值-,那么A对于C
是没有依赖的,A对C的依赖没有从B->C传递过来,所以A中是无法使用C的
比如A->B的scope是compile,而B->C的scope是runtime,那么按照上面表格中,对应第2行第5列的值为
runtime,那么A对于C是的依赖范围是runtime,表示A只有在运行的时候C才会被添加到A的classpath中,即对A
进行运行打包的时候,C会被打包到A的包中
大家仔细看一下,上面的表格是有规律的,当B->C依赖是compile的时候(表中第2列),那么A->C的依赖范围和
A->B的sope是一样的;当B->C的依赖是test时(表中第3列),那么B->C的依赖无法传递给A;当B->C的依赖是
provided(表第4列),只传递A->C的scope为provided的情况,其他情况B->C的依赖无法传递给A;当B->C的依
赖是runtime(表第5列),那么C按照B->C的scope传递给A。
4.4 优化依赖
在软件开发过程中,程序员会通过重构等方式不断地优化自己的代码,使其变得更简洁、更灵活。同理,程序员
也应该能够对Maven 项目的依赖了然于胸,并对其进行优化, 如去除多余的依赖,显式地声明某些必要的依赖。
本文前面的内容已经介绍到: Maven 会自动解析所有项目的直接依赖和传递性依赖,并且根据规则正确判断每个
依赖的范围,对于一些依赖冲突,也能进行调节,以确保任何一个构件只有唯一的版本在依赖中存在。在这些工作
之后,最后得到的那些依赖被称为已解析依赖(Resolved Dependency
)。 可以运行如下的命令查看当前项目的已
解析依赖:
$ mvn dependency:list
在项目中执行该命令,结果如下所示:
$ mvn dependency:list
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building maven hello world 1.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] --- maven-dependency-plugin:2.8:list (default-cli) @ hello-maven ---
[INFO]
[INFO] The following files have been resolved:
[INFO] junit:junit:jar:4.13.2:test
[INFO] org.hamcrest:hamcrest-core:jar:1.3:test
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 0.730 s
[INFO] Finished at: 2023-10-03T10:39:23+08:00
[INFO] Final Memory: 13M/245M
[INFO] ------------------------------------------------------------------------
上面显示了所有的已解析依赖,同时,每个依赖的范围也得以明确标示。 在此基础上,还能进一步了解已解析依
赖的信息。将直接在当前项目POM 声明的依赖定义为顶层依赖,而这些顶层依赖的依赖则定义为第二层依赖,以
此类推,有第三、第四层依赖。当这些依赖经 Maven 解析后,就会构成一个依赖树,通过这棵依赖树就能很清楚
地看到某个依赖是通过哪条传递路径引入的。可以运行如下命令查看当前项目的依赖树:
$ mvn dependency:tree
在项目中执行该命令,效果如下所示:
$ mvn dependency:tree
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building maven hello world 1.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] --- maven-dependency-plugin:2.8:tree (default-cli) @ hello-maven ---
[INFO] org.example:hello-maven:jar:1.0-SNAPSHOT
[INFO] \- junit:junit:jar:4.13.2:test
[INFO] \- org.hamcrest:hamcrest-core:jar:1.3:test
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 0.748 s
[INFO] Finished at: 2023-10-03T10:40:36+08:00
[INFO] Final Memory: 13M/245M
[INFO] ------------------------------------------------------------------------
使用 dependency:list
和 dependeney:tree
可以帮助我们详细了解项目中所有依赖的具体 信息,在此基础
上,还有 dependency:analyze
工具可以帮助分析当前项目的依赖。
现在再运行如下命令:
$ mvn dependency:analyze
结果如下所示:
$ mvn dependency:analyze
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building maven hello world 1.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
......
[INFO] --- maven-dependency-plugin:2.8:analyze (default-cli) @ hello-maven ---
[INFO] No dependency problems found
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 1.470 s
[INFO] Finished at: 2023-10-03T10:41:57+08:00
[INFO] Final Memory: 18M/214M
[INFO] ------------------------------------------------------------------------
该结果中重要的是两个部分。首先是Used undeclared dependencies
, 意指项目中使用到的,但是没有显式声
明的依赖。 这种依赖意味着潜在的风险,当前项目直接在使用它们,例如有很多相关的Java import 声明,而这种
依赖是通过直接依赖传递进来的,当升级直接依赖的时候,相关传递性依赖的版本也可能发生变化,这种变化不易
察觉,但是有可能导致当前项目出错。例如由于接口的改变,当前项目中的相关代码无法编译。这种隐藏的、潜在
的威胁一旦出现,就往往需要耗费大量的时间来查明真相。因此, 显式声明任何项目中直接用到的依赖。
结果中还有一个重要的部分是 Unused declared dependencies
, 意指项目中未使用的,但 显式声明的依赖,需
要注意的是, 对于这样一类依赖, 我们不应该简单地直接删除其声明,而是应该仔细分析。由于
dependeney:analyze
只会分析编译主代码和测试代码需要用到的依赖, 一些执行测试和运行时需要的依赖它就发
现不了。 当然,有时候确实能通过该信息找到一些没用的依赖,但一定要小心测试。
5、仓库搜索服务
使用 Maven 进行日常开发的时候,一个常见的问题就是如何寻找需要的依赖,我们可能只知道需要使用类库的项
目名称,但添加 Maven 依赖要求提供确切的 Maven 坐标。这时,就可以使用仓库搜索服务来根据关键字得到
Maven 坐标。本节介绍几个常用的、功能强大的公共 Maven 仓库搜索服务。
5.1 Sonatype Nexus
地址 :http://repository.sonatype.org/
Nexus 是当前最流行的开源 Maven 仓库管理软件,这里要介绍的是 Sonatype 架设的一个公共 Nexus 仓库实
例。
Nexus 提供了关键字搜索、类名搜索、坐标搜索、校验和搜索等功能。搜索后,页面清晰地列出了结果构件的坐
标及所属仓库。用户可以直接下载相应构件,还可以直接复制已经根据坐标自动生成的XML 依赖声明。
5.2 MVNrepository
地址:http://mvnrepository.com/
MVNrepository 的界面比较清新,它提供了基于关键字的搜索、依赖声明代码片段、构件下载、依赖与被依赖关
系信息、构件所含包信息等功能。 MVNrepository 还能提供一个简单的图表,显示某个构件各版本间的大小变
化。
5.3 其它
https://repo1.maven.org/maven2/
http://maven.aliyun.com/nexus/content/groups/public/
http://repository.jboss.org/nexus/content/groups/public
https://search.maven.org/
https://repo.maven.apache.org/maven2