Maven介绍#
在了解Maven之前,我们先来看看一个Java项目需要的东西。首先,我们需要确定引入哪些依赖包。例如,如果我们需要用到commons logging,我们就必须把commons logging的jar包放入classpath。如果我们还需要log4j,就需要把log4j相关的jar包都放到classpath中。这些就是依赖包的管理。
其次,我们要确定项目的目录结构。例如,src
目录存放Java源码,resources
目录存放配置文件,bin
目录存放编译生成的.class
文件。
此外,我们还需要配置环境,例如JDK的版本,编译打包的流程,当前代码的版本号。
最后,除了使用Eclipse这样的IDE进行编译外,我们还必须能通过命令行工具进行编译,才能够让项目在一个独立的服务器上编译、测试、部署。
这些工作难度不大,但是非常琐碎且耗时。如果每一个项目都自己搞一套配置,肯定会一团糟。我们需要的是一个标准化的Java项目管理和构建工具。
Maven就是是专门为Java项目打造的管理和构建工具,它的主要功能有:
- 提供了一套标准化的项目结构;
- 提供了一套标准化的构建流程(编译,测试,打包,发布……);
- 提供了一套依赖管理机制。
Maven项目结构#
一个使用Maven管理的普通的Java项目,它的目录结构默认如下:
1
2
3
4
5
6
7
8
9
10
|
a-maven-project
├── pom.xml
├── src
│ ├── main
│ │ ├── java
│ │ └── resources
│ └── test
│ ├── java
│ └── resources
└── target
|
项目的根目录a-maven-project
是项目名,它有一个项目描述文件pom.xml
,存放Java源码的目录是src/main/java
,存放资源文件的目录是src/main/resources
,存放测试源码的目录是src/test/java
,存放测试资源的目录是src/test/resources
,最后,所有编译、打包生成的文件都放在target
目录里。这些就是一个Maven项目的标准目录结构。
所有的目录结构都是约定好的标准结构,我们千万不要随意修改目录结构。使用标准结构不需要做任何配置,Maven就可以正常使用。
我们再来看最关键的一个项目描述文件pom.xml
,它的内容长得像下面:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
<project ...>
<modelVersion>4.0.0</modelVersion>
<groupId>com.itranswarp.learnjava</groupId>
<artifactId>hello</artifactId>
<version>1.0</version>
<packaging>jar</packaging>
<properties>
...
</properties>
<dependencies>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
</dependency>
</dependencies>
</project>
|
其中,groupId
类似于Java的包名,通常是公司或组织名称,artifactId
类似于Java的类名,通常是项目名称,再加上version
,一个Maven工程就是由groupId
,artifactId
和version
作为唯一标识。我们在引用其他第三方库的时候,也是通过这3个变量确定。例如,依赖commons-logging
:
1
2
3
4
5
|
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
</dependency>
|
使用<dependency>
声明一个依赖后,Maven就会自动下载这个依赖包并把它放到classpath中。
安装Maven#
要安装Maven,可以从Maven官网下载最新的Maven 3.6.x,然后在本地解压,设置几个环境变量:
1
2
|
M2_HOME=/path/to/maven-3.6.x
PATH=$PATH:$M2_HOME/bin
|
Windows可以把%M2_HOME%\bin
添加到系统Path变量中。
然后,打开命令行窗口,输入mvn -version
,应该看到Maven的版本信息:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
┌────────────────────────────────────────────────────────┐
│Command Prompt - □ x │
├────────────────────────────────────────────────────────┤
│Microsoft Windows [Version 10.0.0] │
│(c) 2015 Microsoft Corporation. All rights reserved. │
│ │
│C:\> mvn -version │
│Apache Maven 3.6.0 (97c98ec64a1fdfee7767ce5ffb20918...) │
│Maven home: C:\Users\liaoxuefeng\maven │
│Java version: ... │
│... │
│C:\> _ │
│ │
│ │
└────────────────────────────────────────────────────────┘
|
如果提示命令未找到,说明系统PATH路径有误,需要修复后再运行。
Maven是一个Java项目的管理和构建工具:
- Maven使用
pom.xml
定义项目内容,并使用预设的目录结构;
- 在Maven中声明一个依赖项可以自动下载并导入classpath;
- Maven使用
groupId
,artifactId
和version
唯一定位一个依赖。
通过pom.xml中的配置,就能够获取到想要的jar包,这些jar包存放在仓库中。
仓库有三种:本地仓库、第三方仓库、中央仓库
中央仓库#
Maven维护了一个中央仓库:https://repo1.maven.org/
这个公共仓库是由Maven自己维护,里面有大量的常用类库,并包含了世界上大部分流行的开源项目,以java项目为主。如果本地仓库没有项目依赖的jar包,默认先从中央仓库下载到本地。
Maven并不会每次都从中央仓库下载jar包。一个jar包一旦被下载过,就会被Maven自动缓存在本地目录(用户主目录的.m2目录),所以,除了第一次编译时因为下载需要时间会比较慢,后续过程因为有本地缓存,并不会重复下载相同的jar包。jar包获取顺序:本地 -> 私服(如果有) ->中央仓库
本地仓库#
Maven会将工程中依赖的构建(jar包)从远程下载到本机的一个目录下管理,仓库的默认位置是:
C:\Users\Administrator\.m2\repository
可以通过修改setting.xml
中的配置,来修改仓库的位置,以及jar包的下载源。
修改仓库位置:
找到localRepository标签,将路径修改为想要修改的路径。
修改jar包下载源:
找到mirror标签,修改为阿里的源
1
2
3
4
5
6
|
<mirror>
<id>alimaven</id>
<mirrorOf>central</mirrorOf>
<name>aliyun maven</name>
<url>http://maven.aliyun.com/nexus/content/groups/public/</url>
</mirror>
|
idea是自带maven插件的,无需自行安装,也可以修改仓库位置以及镜像源。
ctrl+alt+s -> maven
最下面两行分别是setting.xml文件以及仓库位置。
第三方仓库#
又称为内部仓库,也叫私服,一般是公司自己创建的,只内部使用,减少外部访问和下载的频率。
一般公司可能会创建这种第三方仓库,保证项目开发时,项目所需用的jar都从该仓库中拿,每个人的版本就都一样。
依赖管理#
如果我们的项目依赖第三方的jar包,例如commons logging,那么问题来了:commons logging发布的jar包在哪下载?
如果我们还希望依赖log4j,那么使用log4j需要哪些jar包?
类似的依赖还包括:JUnit,JavaMail,MySQL驱动等等,一个可行的方法是通过搜索引擎搜索到项目的官网,然后手动下载zip包,解压,放入classpath。但是,这个过程非常繁琐。
Maven解决了依赖管理问题。例如,我们的项目依赖abc
这个jar包,而abc
又依赖xyz
这个jar包:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
┌──────────────┐
│Sample Project│
└──────────────┘
│
▼
┌──────────────┐
│ abc │
└──────────────┘
│
▼
┌──────────────┐
│ xyz │
└──────────────┘
|
当我们声明了abc
的依赖时,Maven自动把abc
和xyz
都加入了我们的项目依赖,不需要我们自己去研究abc
是否需要依赖xyz
。
因此,Maven的第一个作用就是解决依赖管理。我们声明了自己的项目需要abc
,Maven会自动导入abc
的jar包,再判断出abc
需要xyz
,又会自动导入xyz
的jar包,这样,最终我们的项目会依赖abc
和xyz
两个jar包。
我们来看一个复杂依赖示例:
1
2
3
4
5
|
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>1.4.2.RELEASE</version>
</dependency>
|
当我们声明一个spring-boot-starter-web
依赖时,Maven会自动解析并判断最终需要大概二三十个其他依赖:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
spring-boot-starter-web
spring-boot-starter
spring-boot
sprint-boot-autoconfigure
spring-boot-starter-logging
logback-classic
logback-core
slf4j-api
jcl-over-slf4j
slf4j-api
jul-to-slf4j
slf4j-api
log4j-over-slf4j
slf4j-api
spring-core
snakeyaml
spring-boot-starter-tomcat
tomcat-embed-core
tomcat-embed-el
tomcat-embed-websocket
tomcat-embed-core
jackson-databind
...
|
如果我们自己去手动管理这些依赖是非常费时费力的,而且出错的概率很大。
依赖关系#
Maven定义了几种依赖关系,分别是compile
、test
、runtime
和provided
:
scope |
说明 |
示例 |
compile |
编译时需要用到该jar包(默认) |
commons-logging |
test |
编译Test时需要用到该jar包 |
junit |
runtime |
编译时不需要,但运行时需要用到 |
mysql |
provided |
编译时需要用到,但运行时由JDK或某个服务器提供 |
servlet-api |
其中,默认的compile
是最常用的,Maven会把这种类型的依赖直接放入classpath。
test
依赖表示仅在测试时使用,正常运行时并不需要。最常用的test
依赖就是JUnit:
1
2
3
4
5
6
|
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.3.2</version>
<scope>test</scope>
</dependency>
|
runtime
依赖表示编译时不需要,但运行时需要。最典型的runtime
依赖是JDBC驱动,例如MySQL驱动:
1
2
3
4
5
6
|
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.48</version>
<scope>runtime</scope>
</dependency>
|
provided
依赖表示编译时需要,但运行时不需要。最典型的provided
依赖是Servlet API,编译的时候需要,但是运行时,Servlet服务器内置了相关的jar,所以运行期不需要:
1
2
3
4
5
6
|
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.0</version>
<scope>provided</scope>
</dependency>
|
最后一个问题是,Maven如何知道从何处下载所需的依赖?也就是相关的jar包?答案是Maven维护了一个中央仓库(repo1.maven.org),所有第三方库将自身的jar以及相关信息上传至中央仓库,Maven就可以从中央仓库把所需依赖下载到本地。
Maven并不会每次都从中央仓库下载jar包。一个jar包一旦被下载过,就会被Maven自动缓存在本地目录(用户主目录的.m2
目录),所以,除了第一次编译时因为下载需要时间会比较慢,后续过程因为有本地缓存,并不会重复下载相同的jar包。
唯一ID#
对于某个依赖,Maven只需要3个变量即可唯一确定某个jar包:
- groupId:属于组织的名称,类似Java的包名;
- artifactId:该jar包自身的名称,类似Java的类名;
- version:该jar包的版本。
通过上述3个变量,即可唯一确定某个jar包。Maven通过对jar包进行PGP签名确保任何一个jar包一经发布就无法修改。修改已发布jar包的唯一方法是发布一个新版本。
因此,某个jar包一旦被Maven下载过,即可永久地安全缓存在本地。
注:只有以-SNAPSHOT
结尾的版本号会被Maven视为开发版本,开发版本每次都会重复下载,这种SNAPSHOT版本只能用于内部私有的Maven repo,公开发布的版本不允许出现SNAPSHOT。
Maven镜像#
除了可以从Maven的中央仓库下载外,还可以从Maven的镜像仓库下载。如果访问Maven的中央仓库非常慢,我们可以选择一个速度较快的Maven的镜像仓库。Maven镜像仓库定期从中央仓库同步:
1
2
3
4
5
6
7
8
9
|
slow ┌───────────────────┐
┌─────────────>│Maven Central Repo.│
│ └───────────────────┘
│ │
│ │sync
│ ▼
┌───────┐ fast ┌───────────────────┐
│ User │─────────>│Maven Mirror Repo. │
└───────┘ └───────────────────┘
|
中国区用户可以使用阿里云提供的Maven镜像仓库。使用Maven镜像仓库需要一个配置,在用户主目录下进入.m2
目录,创建一个settings.xml
配置文件,内容如下:
1
2
3
4
5
6
7
8
9
10
11
|
<settings>
<mirrors>
<mirror>
<id>aliyun</id>
<name>aliyun</name>
<mirrorOf>central</mirrorOf>
<!-- 国内推荐阿里云的Maven镜像 -->
<url>https://maven.aliyun.com/repository/central</url>
</mirror>
</mirrors>
</settings>
|
配置镜像仓库后,Maven的下载速度就会非常快。
搜索第三方组件#
最后一个问题:如果我们要引用一个第三方组件,比如okhttp
,如何确切地获得它的groupId
、artifactId
和version
?方法是通过search.maven.org搜索关键字,找到对应的组件后,直接复制。
命令行编译#
在命令中,进入到pom.xml
所在目录,输入以下命令:
1
|
$ mvn clean package
|
如果一切顺利,即可在target
目录下获得编译后自动打包的jar。
在IDE中使用Maven#
几乎所有的IDE都内置了对Maven的支持。在Eclipse中,可以直接创建或导入Maven项目。如果导入后的Maven项目有错误,可以尝试选择项目后点击右键,选择Maven - Update Project…更新:
构建流程#
Maven不但有标准化的项目结构,而且还有一套标准化的构建流程,可以自动化实现编译,打包,发布,等等。
Lifecycle和Phase#
使用Maven时,我们首先要了解什么是Maven的生命周期(lifecycle)。
Maven的生命周期由一系列阶段(phase)构成,以内置的生命周期default
为例,它包含以下phase:
- validate
- initialize
- generate-sources
- process-sources
- generate-resources
- process-resources
- compile
- process-classes
- generate-test-sources
- process-test-sources
- generate-test-resources
- process-test-resources
- test-compile
- process-test-classes
- test
- prepare-package
- package
- pre-integration-test
- integration-test
- post-integration-test
- verify
- install
- deploy
如果我们运行mvn package
,Maven就会执行default
生命周期,它会从开始一直运行到package
这个phase为止:
如果我们运行mvn compile
,Maven也会执行default
生命周期,但这次它只会运行到compile
,即以下几个phase:
Maven另一个常用的生命周期是clean
,它会执行3个phase:
- pre-clean
- clean (注意这个clean不是lifecycle而是phase)
- post-clean
所以,我们使用mvn
这个命令时,后面的参数是phase,Maven自动根据生命周期运行到指定的phase。
更复杂的例子是指定多个phase,例如,运行mvn clean package
,Maven先执行clean
生命周期并运行到clean
这个phase,然后执行default
生命周期并运行到package
这个phase,实际执行的phase如下:
- pre-clean
- clean (注意这个clean是phase)
- validate
- …
- package
常用命令#
注意:执行mvn命令,必须和 pom.xml 同级目录。
编译:mvn compile
将src/main/java
目录下的java源码编译,并生成class文件到 target 目录下。
测试:mvn test
编译src/test/java
目录下的文件,即测试文件。
清理:mvn clean
删除target目录,将所有生成的class和jar一并删除。
mvn clean compile:先清理,再执行到compile;
mvn clean package:先清理,再执行到package。
打包:mvn package
将项目打成jar包或war包,然后放到target目录下。
安装:mvn install
将压缩文件(jar或者war)上传到本地仓库。
部署|发布:mvn deploy
将jar包上传私服。
大多数phase在执行过程中,因为我们通常没有在pom.xml
中配置相关的设置,所以这些phase什么事情都不做。
经常用到的phase其实只有几个:
- clean:清理
- compile:编译
- test:运行测试
- package:打包
Goal#
执行一个phase又会触发一个或多个goal:
执行的Phase |
对应执行的Goal |
compile |
compiler:compile |
test |
compiler:testCompile surefire:test |
goal的命名总是abc:xyz
这种形式。
看到这里,相信大家对lifecycle、phase和goal已经明白了吧?
其实我们类比一下就明白了:
- lifecycle相当于Java的package,它包含一个或多个phase;
- phase相当于Java的class,它包含一个或多个goal;
- goal相当于class的method,它其实才是真正干活的。
大多数情况,我们只要指定phase,就默认执行这些phase默认绑定的goal,只有少数情况,我们可以直接指定运行一个goal,例如,启动Tomcat服务器:
Maven通过lifecycle、phase和goal来提供标准的构建流程。
最常用的构建命令是指定phase,然后让Maven执行到指定的phase:
- mvn clean
- mvn clean compile
- mvn clean test
- mvn clean package
通常情况,我们总是执行phase默认绑定的goal,因此不必指定goal。
使用插件#
我们在前面介绍了Maven的lifecycle,phase和goal:使用Maven构建项目就是执行lifecycle,执行到指定的phase为止。每个phase会执行自己默认的一个或多个goal。goal是最小任务单元。
我们以compile
这个phase为例,如果执行:
Maven将执行compile
这个phase,这个phase会调用compiler
插件执行关联的compiler:compile
这个goal。
实际上,执行每个phase,都是通过某个插件(plugin)来执行的,Maven本身其实并不知道如何执行compile
,它只是负责找到对应的compiler
插件,然后执行默认的compiler:compile
这个goal来完成编译。
所以,使用Maven,实际上就是配置好需要使用的插件,然后通过phase调用它们。
Maven已经内置了一些常用的标准插件:
插件名称 |
对应执行的phase |
clean |
clean |
compiler |
compile |
surefire |
test |
jar |
package |
如果标准插件无法满足需求,我们还可以使用自定义插件。使用自定义插件的时候,需要声明。例如,使用maven-shade-plugin
可以创建一个可执行的jar,要使用这个插件,需要在pom.xml
中声明它:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
<project>
...
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.2.1</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
...
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
|
自定义插件往往需要一些配置,例如,maven-shade-plugin
需要指定Java程序的入口,它的配置是:
1
2
3
4
5
6
7
|
<configuration>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>com.itranswarp.learnjava.Main</mainClass>
</transformer>
</transformers>
</configuration>
|
注意,Maven自带的标准插件例如compiler
是无需声明的,只有引入其它的插件才需要声明。
下面列举了一些常用的插件:
- maven-shade-plugin:打包所有依赖包并生成可执行jar;
- cobertura-maven-plugin:生成单元测试覆盖率报告;
- findbugs-maven-plugin:对Java源码进行静态分析以找出潜在问题。
模块管理#
在软件开发中,把一个大项目分拆为多个模块是降低软件复杂度的有效方法:
1
2
3
4
5
6
7
8
9
10
11
|
┌ ─ ─ ─ ─ ─ ─ ┐
┌─────────┐
│ │Module A │ │
└─────────┘
┌──────────────┐ split │ ┌─────────┐ │
│Single Project│───────> │Module B │
└──────────────┘ │ └─────────┘ │
┌─────────┐
│ │Module C │ │
└─────────┘
└ ─ ─ ─ ─ ─ ─ ┘
|
对于Maven工程来说,原来是一个大项目:
1
2
3
|
single-project
├── pom.xml
└── src
|
现在可以分拆成3个模块:
1
2
3
4
5
6
7
8
9
10
|
mutiple-project
├── module-a
│ ├── pom.xml
│ └── src
├── module-b
│ ├── pom.xml
│ └── src
└── module-c
├── pom.xml
└── src
|
Maven可以有效地管理多个模块,我们只需要把每个模块当作一个独立的Maven项目,它们有各自独立的pom.xml
。例如,模块A的pom.xml
:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
|
<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.0</modelVersion>
<groupId>com.itranswarp.learnjava</groupId>
<artifactId>module-a</artifactId>
<version>1.0</version>
<packaging>jar</packaging>
<name>module-a</name>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<java.version>11</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.28</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.5.2</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
|
模块B的pom.xml
:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
|
<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.0</modelVersion>
<groupId>com.itranswarp.learnjava</groupId>
<artifactId>module-b</artifactId>
<version>1.0</version>
<packaging>jar</packaging>
<name>module-b</name>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<java.version>11</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.28</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.5.2</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
|
可以看出来,模块A和模块B的pom.xml
高度相似,因此,我们可以提取出共同部分作为parent
:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
|
<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.0</modelVersion>
<groupId>com.itranswarp.learnjava</groupId>
<artifactId>parent</artifactId>
<version>1.0</version>
<packaging>pom</packaging>
<name>parent</name>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<java.version>11</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.28</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.5.2</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
|
注意到parent的<packaging>
是pom
而不是jar
,因为parent
本身不含任何Java代码。编写parent
的pom.xml
只是为了在各个模块中减少重复的配置。现在我们的整个工程结构如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
multiple-project
├── pom.xml
├── parent
│ └── pom.xml
├── module-a
│ ├── pom.xml
│ └── src
├── module-b
│ ├── pom.xml
│ └── src
└── module-c
├── pom.xml
└── src
|
这样模块A就可以简化为:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
<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.0</modelVersion>
<parent>
<groupId>com.itranswarp.learnjava</groupId>
<artifactId>parent</artifactId>
<version>1.0</version>
<relativePath>../parent/pom.xml</relativePath>
</parent>
<artifactId>module-a</artifactId>
<packaging>jar</packaging>
<name>module-a</name>
</project>
|
模块B、模块C都可以直接从parent
继承,大幅简化了pom.xml
的编写。
如果模块A依赖模块B,则模块A需要模块B的jar包才能正常编译,我们需要在模块A中引入模块B:
1
2
3
4
5
6
7
8
|
...
<dependencies>
<dependency>
<groupId>com.itranswarp.learnjava</groupId>
<artifactId>module-b</artifactId>
<version>1.0</version>
</dependency>
</dependencies>
|
最后,在编译的时候,需要在根目录创建一个pom.xml
统一编译:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
<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.itranswarp.learnjava</groupId>
<artifactId>build</artifactId>
<version>1.0</version>
<packaging>pom</packaging>
<name>build</name>
<modules>
<module>parent</module>
<module>module-a</module>
<module>module-b</module>
<module>module-c</module>
</modules>
</project>
|
这样,在根目录执行mvn clean package
时,Maven根据根目录的pom.xml
找到包括parent
在内的共4个<module>
,一次性全部编译。
使用mvnw#
我们使用Maven时,基本上只会用到mvn
这一个命令。有些童鞋可能听说过mvnw
,这个是啥?
mvnw
是Maven Wrapper的缩写。因为我们安装Maven时,默认情况下,系统所有项目都会使用全局安装的这个Maven版本。但是,对于某些项目来说,它可能必须使用某个特定的Maven版本,这个时候,就可以使用Maven Wrapper,它可以负责给这个特定的项目安装指定版本的Maven,而其他项目不受影响。
简单地说,Maven Wrapper就是给一个项目提供一个独立的,指定版本的Maven给它使用。
安装Maven Wrapper#
安装Maven Wrapper最简单的方式是在项目的根目录(即pom.xml
所在的目录)下运行安装命令:
1
|
mvn -N io.takari:maven:0.7.6:wrapper
|
它会自动使用最新版本的Maven。注意0.7.6
是Maven Wrapper的版本。最新的Maven Wrapper版本可以去官方网站查看。
如果要指定使用的Maven版本,使用下面的安装命令指定版本,例如3.3.3
:
1
|
mvn -N io.takari:maven:0.7.6:wrapper -Dmaven=3.3.3
|
安装后,查看项目结构:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
my-project
├── .mvn
│ └── wrapper
│ ├── MavenWrapperDownloader.java
│ ├── maven-wrapper.jar
│ └── maven-wrapper.properties
├── mvnw
├── mvnw.cmd
├── pom.xml
└── src
├── main
│ ├── java
│ └── resources
└── test
├── java
└── resources
|
发现多了mvnw
、mvnw.cmd
和.mvn
目录,我们只需要把mvn
命令改成mvnw
就可以使用跟项目关联的Maven。例如:
1
|
mvnw clean package
|
在Linux或macOS下运行时需要加上./
:
1
|
./mvnw clean package
|
Maven Wrapper的另一个作用是把项目的mvnw
、mvnw.cmd
和.mvn
提交到版本库中,可以使所有开发人员使用统一的Maven版本。
发布Artifact#
当我们使用commons-logging
这些第三方开源库的时候,我们实际上是通过Maven自动下载它的jar包,并根据其pom.xml
解析依赖,自动把相关依赖包都下载后加入到classpath。
那么问题来了:当我们自己写了一个牛逼的开源库时,非常希望别人也能使用,总不能直接放个jar包的链接让别人下载吧?
如果我们把自己的开源库放到Maven的repo中,那么,别人只需按标准引用groupId:artifactId:version
,即可自动下载jar包以及相关依赖。因此,本节我们介绍如何发布一个库到Maven的repo中。
把自己的库发布到Maven的repo中有好几种方法,我们介绍3种最常用的方法。
以静态文件发布#
如果我们观察一个中央仓库的Artifact结构,例如Commons Math,它的groupId是org.apache.commons
,artifactId是commons-math3
,以版本3.6.1
为例,发布在中央仓库的文件夹路径就是https://repo1.maven.org/maven2/org/apache/commons/commons-math3/3.6.1/,在此文件夹下,commons-math3-3.6.1.jar
就是发布的jar包,commons-math3-3.6.1.pom
就是它的pom.xml
描述文件,commons-math3-3.6.1-sources.jar
是源代码,commons-math3-3.6.1-javadoc.jar
是文档。其它以.asc
、.md5
、.sha1
结尾的文件分别是GPG签名、MD5摘要和SHA-1摘要。
我们只要按照这种目录结构组织文件,它就是一个有效的Maven仓库。
我们以广受好评的开源项目how-to-become-rich为例,先创建Maven工程目录结构如下:
1
2
3
4
5
6
7
8
9
10
11
|
how-to-become-rich
├── maven-repo <-- Maven本地文件仓库
├── pom.xml <-- 项目文件
├── src
│ ├── main
│ │ ├── java <-- 源码目录
│ │ └── resources <-- 资源目录
│ └── test
│ ├── java <-- 测试源码目录
│ └── resources <-- 测试资源目录
└── target <-- 编译输出目录
|
在pom.xml
中添加如下内容:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
<project ...>
...
<distributionManagement>
<repository>
<id>local-repo-release</id>
<name>GitHub Release</name>
<url>file://${project.basedir}/maven-repo</url>
</repository>
</distributionManagement>
<build>
<plugins>
<plugin>
<artifactId>maven-source-plugin</artifactId>
<executions>
<execution>
<id>attach-sources</id>
<phase>package</phase>
<goals>
<goal>jar-no-fork</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-javadoc-plugin</artifactId>
<executions>
<execution>
<id>attach-javadocs</id>
<phase>package</phase>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
|
注意到<distributionManagement>
,它指示了发布的软件包的位置,这里的<url>
是项目根目录下的maven-repo
目录,在<build>
中定义的两个插件maven-source-plugin
和maven-javadoc-plugin
分别用来创建源码和javadoc,如果不想发布源码,可以把对应的插件去掉。
我们直接在项目根目录下运行Maven命令mvn clean package deploy
,如果一切顺利,我们就可以在maven-repo
目录下找到部署后的所有文件如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
maven-repo
└── com
└── itranswarp
└── rich
└── how-to-become-rich
├── 1.0.0
│ ├── how-to-become-rich-1.0.0-javadoc.jar
│ ├── how-to-become-rich-1.0.0-javadoc.jar.md5
│ ├── how-to-become-rich-1.0.0-javadoc.jar.sha1
│ ├── how-to-become-rich-1.0.0-sources.jar
│ ├── how-to-become-rich-1.0.0-sources.jar.md5
│ ├── how-to-become-rich-1.0.0-sources.jar.sha1
│ ├── how-to-become-rich-1.0.0.jar
│ ├── how-to-become-rich-1.0.0.jar.md5
│ ├── how-to-become-rich-1.0.0.jar.sha1
│ ├── how-to-become-rich-1.0.0.pom
│ ├── how-to-become-rich-1.0.0.pom.md5
│ └── how-to-become-rich-1.0.0.pom.sha1
├── maven-metadata.xml
├── maven-metadata.xml.md5
└── maven-metadata.xml.sha1
|
最后一步,是把这个工程推到GitHub上,并选择Settings
-GitHub Pages
,选择master branch
启用Pages服务。
这样,把全部内容推送至GitHub后,即可作为静态网站访问Maven的repo,它的地址是https://michaelliao.github.io/how-to-become-rich/maven-repo/。版本1.0.0
对应的jar包地址是:
1
|
https://michaelliao.github.io/how-to-become-rich/maven-repo/com/itranswarp/rich/how-to-become-rich/1.0.0/how-to-become-rich-1.0.0.jar
|
现在,如果其他人希望引用这个Maven包,我们可以告知如下依赖即可:
1
2
3
4
5
|
<dependency>
<groupId>com.itranswarp.rich</groupId>
<artifactId>how-to-become-rich</artifactId>
<version>1.0.0</version>
</dependency>
|
但是,除了正常导入依赖外,对方还需要再添加一个<repository>
的声明,即使用方完整的pom.xml
如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
<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.0</modelVersion>
<groupId>example</groupId>
<artifactId>how-to-become-rich-usage</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<java.version>11</java.version>
</properties>
<repositories>
<repository>
<id>github-rich-repo</id>
<name>The Maven Repository on Github</name>
<url>https://michaelliao.github.io/how-to-become-rich/maven-repo/</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>com.itranswarp.rich</groupId>
<artifactId>how-to-become-rich</artifactId>
<version>1.0.0</version>
</dependency>
</dependencies>
</project>
|
在<repository>
中,我们必须声明发布的Maven的repo地址,其中<id>
和<name>
可以任意填写,<url>
填入GitHub Pages提供的地址+/maven-repo/
后缀。现在,即可正常引用这个库并编写代码如下:
1
2
|
Millionaire millionaire = new Millionaire();
System.out.println(millionaire.howToBecomeRich());
|
有的童鞋会问,为什么使用commons-logging
等第三方库时,并不需要声明repo地址?这是因为这些库都是发布到Maven中央仓库的,发布到中央仓库后,不需要告诉Maven仓库地址,因为它知道中央仓库的地址默认是https://repo1.maven.org/maven2/,也可以通过~/.m2/settings.xml
指定一个代理仓库地址以替代中央仓库来提高速度(参考依赖管理的Maven镜像)。
因为GitHub Pages并不会把我们发布的Maven包同步到中央仓库,所以自然使用方必须手动添加一个我们提供的仓库地址。
此外,通过GitHub Pages发布Maven repo时需要注意一点,即不要改动已发布的版本。因为Maven的仓库是不允许修改任何版本的,对一个库进行修改的唯一方法是发布一个新版本。但是通过静态文件的方式发布repo,实际上我们是可以修改jar文件的,但最好遵守规范,不要修改已发布版本。
通过Nexus发布到中央仓库#
有的童鞋会问,能不能把自己的开源库发布到Maven的中央仓库,这样用户就不需要声明repo地址,可以直接引用,显得更专业。
当然可以,但我们不能直接发布到Maven中央仓库,而是通过曲线救国的方式,发布到central.sonatype.org,它会定期自动同步到Maven的中央仓库。Nexus是一个支持Maven仓库的软件,由Sonatype开发,有免费版和专业版两个版本,很多大公司内部都使用Nexus作为自己的私有Maven仓库,而这个central.sonatype.org相当于面向开源的一个Nexus公共服务。
所以,第一步是在central.sonatype.org上注册一个账号,注册链接非常隐蔽,可以自己先找找,找半小时没找到点这里查看攻略。
如果注册顺利并审核通过,会得到一个登录账号,然后,通过这个页面一步一步操作就可以成功地将自己的Artifact发布到Nexus上,再耐心等待几个小时后,你的Artifact就会出现在Maven的中央仓库中。
这里简单提一下发布重点与难点:
- 必须正确创建GPG签名,Linux和Mac下推荐使用gnupg2;
- 必须在
~/.m2/settings.xml
中配置好登录用户名和口令,以及GPG口令:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
<settings ...>
...
<servers>
<server>
<id>ossrh</id>
<username>OSSRH-USERNAME</username>
<password>OSSRH-PASSWORD</password>
</server>
</servers>
<profiles>
<profile>
<id>ossrh</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<gpg.executable>gpg2</gpg.executable>
<gpg.passphrase>GPG-PASSWORD</gpg.passphrase>
</properties>
</profile>
</profiles>
</settings>
|
在待发布的Artifact的pom.xml
中添加OSS的Maven repo地址,以及maven-jar-plugin
、maven-source-plugin
、maven-javadoc-plugin
、maven-gpg-plugin
、nexus-staging-maven-plugin
:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
|
<project ...>
...
<distributionManagement>
<snapshotRepository>
<id>ossrh</id>
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
</snapshotRepository>
<repository>
<id>ossrh</id>
<name>Nexus Release Repository</name>
<url>http://oss.sonatype.org/service/local/staging/deploy/maven2/</url>
</repository>
</distributionManagement>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>jar</goal>
<goal>test-jar</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar-no-fork</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<executions>
<execution>
<id>attach-javadocs</id>
<goals>
<goal>jar</goal>
</goals>
<configuration>
<additionalOption>
<additionalOption>-Xdoclint:none</additionalOption>
</additionalOption>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-gpg-plugin</artifactId>
<executions>
<execution>
<id>sign-artifacts</id>
<phase>verify</phase>
<goals>
<goal>sign</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.sonatype.plugins</groupId>
<artifactId>nexus-staging-maven-plugin</artifactId>
<version>1.6.3</version>
<extensions>true</extensions>
<configuration>
<serverId>ossrh</serverId>
<nexusUrl>https://oss.sonatype.org/</nexusUrl>
<autoReleaseAfterClose>true</autoReleaseAfterClose>
</configuration>
</plugin>
</plugins>
</build>
</project>
|
最后执行命令mvn clean package deploy
即可发布至central.sonatype.org。
此方法前期需要复杂的申请账号和项目的流程,后期需要安装调试GPG,但只要跑通流程,后续发布都只需要一行命令。
发布到私有仓库#
通过nexus-staging-maven-plugin
除了可以发布到central.sonatype.org外,也可以发布到私有仓库,例如,公司内部自己搭建的Nexus服务器。
如果没有私有Nexus服务器,还可以发布到GitHub Packages。GitHub Packages是GitHub提供的仓库服务,支持Maven、NPM、Docker等。使用GitHub Packages时,无论是发布Artifact,还是引用已发布的Artifact,都需要明确的授权Token,因此,GitHub Packages只能作为私有仓库使用。
在发布前,我们必须首先登录后在用户的Settings
-Developer settings
-Personal access tokens
中创建两个Token,一个用于发布,一个用于使用。发布Artifact的Token必须有repo
、write:packages
和read:packages
权限。
使用Artifact的Token只需要read:packages
权限。
在发布端,把GitHub的用户名和发布Token写入~/.m2/settings.xml
配置中:
1
2
3
4
5
6
7
8
9
10
|
<settings ...>
...
<servers>
<server>
<id>github-release</id>
<username>GITHUB-USERNAME</username>
<password>f052...c21f</password>
</server>
</servers>
</settings>
|
然后,在需要发布的Artifact的pom.xml
中,添加一个<repository>
声明:
1
2
3
4
5
6
7
8
9
10
|
<project ...>
...
<distributionManagement>
<repository>
<id>github-release</id>
<name>GitHub Release</name>
<url>https://maven.pkg.github.com/michaelliao/complex</url>
</repository>
</distributionManagement>
</project>
|
注意到<id>
和~/.m2/settings.xml
配置中的<id>
要保持一致,因为发布时Maven根据id找到用于登录的用户名和Token,才能成功上传文件到GitHub。我们直接通过命令mvn clean package deploy
部署,成功后,在GitHub用户页面可以看到该Artifact。
完整的配置请参考complex项目,这是一个非常简单的支持复数运算的库。
使用该Artifact时,因为GitHub的Package只能作为私有仓库使用,所以除了在使用方的pom.xml
中声明<repository>
外:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
<project ...>
...
<repositories>
<repository>
<id>github-release</id>
<name>GitHub Release</name>
<url>https://maven.pkg.github.com/michaelliao/complex</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>com.itranswarp</groupId>
<artifactId>complex</artifactId>
<version>1.0.0</version>
</dependency>
</dependencies>
...
</project>
|
还需要把有读权限的Token配置到~/.m2/settings.xml
文件中。
pom.xml的依赖关系讲解#
dependency的属性#
-
type:依赖的类型,比如是jar包还是war包等,默认为jar,表示依赖的jar包。
-
optional:标记依赖是否可选。默认值false。
-
exclusions:排除传递依赖,解决jar冲突问题。
当一个项目A依赖项目B,而项目B同时依赖项目C,如果项目A不想引用项目C,在配置项目B的依赖时,可以排除对C的依赖。
-
scope:依赖范围,意思就是通过pom.xml加载进来的jar包,在什么范围内使用生效,范围包括编译时,运行时,测试时。scope包含下面的值:
- compile:默认值,如果选择此值,表示编译、测试和运行都使用当前jar,Maven会把这种类型的依赖直接放入classpath。
- test:test依赖表示仅在测试时使用,正常运行时并不需要。最常用的test依赖就是JUnit:
- runtime:runtime依赖表示编译时不需要,但运行时需要。最典型的runtime依赖是JDBC驱动,例如MySQL驱动:
- provided:表示编译时需要,但运行时不需要。最典型的provided依赖是Servlet API,编译的时候需要,但是运行时,Servlet服务器内置了相关的jar,所以运行期不需要:
- system:表示我们自己手动加入的jar包,不属于maven仓库(本地,第三方等),属于别得类库的这样的jar包,只在编译和测试期生效,运行时无效。一般不用。
依赖调节原则#
依赖调节原则是:maven解决传递依赖时jar包冲突问题的方法。
第一原则:近路优先原则#
项目 A 依赖于项目 B,项目 B 依赖于项目 C(v1),项目 A 依赖于项目 D,项目 D依赖于项目 E,项目 E 依赖于 C(v2)
1
2
|
A--->B---->C(v1)
A------>D---->E----->C(v2)
|
项目 A 隐形依赖了两个版本的 C,那到底采用哪个版本呢?
依据近路优先原则,很明显,第一种路径深度是 3,第二种路径深度是 4,所以,maven 会采用 C(v1)
第二原则:第一声明者优先原则。#
就是如果路径相同,maven 默认配置在前面的优先使用
A–>B –> X(1.6)
C–>D–> X(2.0)
这样就是路径相同,那么如果A在前面,C在后面,则使用X(1.6)
maven会先根据第一原则进行选择,第一原则不成,则按第二原则处理。
maven引入本地jar包#
将jar包复制到项目中,建议放到/src/main/resources/lib
下。
在pom.xml中加入配置
1
2
3
4
5
6
7
|
<dependency>
<groupId>com.aspose</groupId>
<artifactId>aspose-words</artifactId>
<version>19.10</version>
<scope>system</scope>
<systemPath>${basedir}/src/main/resources/lib/aspose-words-19.10-jdk17.jar</systemPath>
</dependency>
|
不使用maven导包#
Porject Structure->Libraries
点击左上角的加号,选择java
,然后一层层找到你项目中的jar包。
使用dependency引入的jar包Linux上失效#
1
2
3
4
5
6
7
|
<dependency>
<groupId>aspose-slides</groupId>
<artifactId>aspose-slides</artifactId>
<scope>system</scope>
<version>19.6</version>
<systemPath>${basedir}/src/main/resources/lib/aspose-slides-19.6.jar</systemPath>
</dependency>
|
system scope引入的包,在使用jar-with-dependencies打包时将不会被包含,就是如果我maven install
打包,这个打不进去。到时候调用的时候就会报:classNotFound
。
执行命令
windows:
mvn install:install-file -DgroupId=aspose-cells -DartifactId=aspose-cells -Dversion=16.8 -Dpackaging=jar -Dfile=E:\work\aspose-cells-18.9.jar
linux:
mvn install:install-file -DgroupId=aspose-words -DartifactId=aspose-words -Dversion=16.8 -Dpackaging=jar -Dfile=/usr/local/src/aspose-words-16.8.0-jdk16.jar
mvn install:install-file -DgroupId=aspose-slides -DartifactId=aspose-slides -Dversion=19.6 -Dpackaging=jar -Dfile=/usr/local/src/aspose-slides-19.6.jar
mvn install:install-file -DgroupId=aspose-cells -DartifactId=aspose-cells -Dversion=18.9 -Dpackaging=jar -Dfile=/usr/local/src/aspose-cells-18.9.jar
区别只是路径不同,注意修改groupId、artifactId、version和file后的路径。
然后使用时,在pom中添加
1
2
3
4
5
|
<dependency>
<groupId>alipay</groupId>
<artifactId>alipay-trade-sdk</artifactId>
<version>1.0</version>
</dependency>
|
这里的groupId、artifactId、version,随便写,只需要和上边命令中的参数一致即可。
参考1
参考2
卸载jar包#
上边使用mvn install:install-file
安装了本地的jar包,现在卸载它。
-
从Maven本地仓库删除jar
//清除某个jar
mvn dependency:purge-local-repository -DmanualInclude="groupId:artifactId"
//清除多个属于不同groupId的jar
mvn dependency:purge-local-repository -DmanualInclude="groupId1:artifactId1,groupId2:artifactId2,..."
-
阻止Maven对已删除的jar进行reResolve
mvn dependency:purge-local-repository -DreResolve=false
使用maven命令创建项目#
创建 maven java 项目#
在合适的位置执行命令:
1
2
3
4
|
mvn archetype:create
-DgroupId=com.wuhao.maven.quickstart
-DartifactId=simple
-DarchetypeArtifactId=maven-archetype-quickstart
|
mvn:核心命令
archetype:create
:
创建项目,现在maven高一点的版本都弃用了create命令而使用generate命令
-DgroupId=com.wjy.maven.quickstart
:
创建该maven项目时的groupId是什么,该作用在上面已经解释了。一般使用包名的写法。因为包名是用公司的域名的反写,独一无二。
-DartifactId=simple
:
创建该maven项目时的artifactId是什么,就是项目名称
-DarchetypeArtifactId=maven-archetype-quickstart
:
表示创建的是maven项目
注意:需要联网,必须上网下载一个小文件
创建成功后会提示:build success!
在当前文件夹下会生成一个simple的文件夹,这就是maven java项目
maven java项目的结构:
1
2
3
4
5
6
7
8
9
10
|
project_name
---pom.xml:核心配置,根目录下
---src
------main
---------java:java源码目录
---------resources:java配置文件目录
------test
---------java:测试源码目录
---------resources:测试配置目录
---target:src/main/java下的源代码就会编译成.class文件放入target目录中,target就是输出目录
|
创建 maven javaWeb 项目#
命令:
1
2
3
4
5
|
mvn archetype:create
-DgroupId=com.wjy.maven.quickstart
-DartifactId=myWebApp
-DarchetypeArtifactId=maven-archetype-webapp
-Dversion=0.0.1-snapshot
|
创建成功后会提示:build success!
在当前文件夹下会生成一个simple的文件夹,这就是maven javaWeb项目
maven javaWeb 项目结构:
1
2
3
4
5
6
7
8
|
pom.xml:核心配置
src/main/java:java源码
src/main/resources:java配置
src/main/webapp:myeclipse web项目中 WebRoot目录
|-- WEB-INF
|-- web.xml
src/test:测试
target:输出目录
|
maven 标签#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
|
<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">
<!-- 指定当前pom的版本 -->
<modelVersion>4.0.0</modelVersion>
<!-- 一、项目的坐标信息-->
<groupId>反写的公司网址+项目名</groupId>
<artifactId>项目名+模块名</artifactId>
<!--
第一个0:大版本:号
第二个0:分支版本号
第三个0:小版本号
版本类型划分: 1.SNAPSHOT(快照)
2.alpha(内测)
3.beta(公测)
4.Release(稳定)
5.GA(正式)
-->
<version>0.0.1SNAPSHOT</version>
<!--maven项目打包方式:默认:jar,可指定war、zip、pom--->
<packaging></packaging>
<!--项目描述名-->
<name></name>
<!--项目地址-->
<url></url>
<!--项目描述-->
<description></description>
<!--开发人员信息-->
<developers></developers>
<!--许可证信息-->
<licenses></licenses>
<!--组织信息-->
<organization></organization>
<!--二、依赖列表-->
<dependencies>
<!--依赖坐标-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.10</version>
<type></type>
<!-- 依赖范围:test-->
<scope>test</scope>
<!--设置依赖是否可选:true/false默认是后者(为true会消除依赖此pom的项目依赖此dependency)-->
<optional>false</optional>
<!--排除依赖传递列表-->
<exclusions>
<!--排除部分不需要的依赖-->
<exclusion></exclusion>
</exclusions>
</dependency>
</dependencies>
<!--三、依赖的管理:定义父模块的jar包便于子模块的继承-->
<dependencyManagement>
<dependencies>
<dependency></dependency>
</dependencies>
</dependencyManagement>
<!--四、插件列表:需指定插件的坐标-->
<build>
<plugin>
<groupId></groupId>
<artifactId></artifactId>
<version></version>
</plugin>
</build>
<!--五、用于子模块对于父模块pom的继承-->
<parent></parent>
<!--六、指定多个模块,可同时编译等操作-->
<modules></modules>
</project>
|