Featured image of post maven相关知识梳理及常见问题

maven相关知识梳理及常见问题

maven 指定依赖版本范围有时我们为了不频繁修改依赖的版本号,会直接指定一个范围,如果你需要一直依赖最新版

Image

maven 指定依赖版本范围

有时我们为了不频繁修****改依赖的版本号,会直接指定一个范围,如果你需要一直依赖最新版本就能省些事儿,当然也可以根据你的版本需求进行配置。

  • A square bracket ( [ & ] ) means “closed” (inclusive).

  • A parenthesis ( ( & ) ) means “open” (exclusive).

Range

Meaning

描述

1.0

x >= 1.0 * The default Maven meaning for 1.0 is everything (,) but with 1.0 recommended. Obviously this doesn't work for enforcing versions here, so it has been redefined as a minimum version.

1.0的默认Maven含义是所有(,)但建议使用1.0。如果没有1.0则通常表示1.0或更高版本。


(,1.0]x <= 1.0

依赖小于等于1.0的版本

(,1.0)x < 1.0

依赖等于1.0的版本

[1.0]

x == 1.0

声明确切版本
[1.0,)x >= 1.0

依赖大于等于1.0的版本

(1.0,)

x > 1.0

依赖大于1.0的版本

(1.0,2.0)1.0 < x < 2.0

依赖大于1.0小于2.0的版本

[1.0,2.0]1.0 <= x <= 2.0

依赖大于等于1.0小于等于2.0的版本

(,1.0],[1.2,)x <= 1.0 or x >= 1.2. Multiple sets are comma-separated

依赖小于等于1.0,或大于等于1.2的版本(多组以逗号分隔)

(,1.1),(1.1,)x != 1.1

依赖不包括1.1的版本

  1<dependency>
  2    <groupId>org.projectlombok</groupId>
  3    <artifactId>lombok</artifactId>
  4    <version>[1.18.8,1.18.12]</version>
  5</dependency>
  6
  7```html
  8
  9## 快照
 10
 11一般我们在开发阶段包的版本会定义为:**snapshot**
 12
 13```xml
 14 <dependency>
 15      <groupId>data-service</groupId>
 16       <artifactId>data-service</artifactId>
 17       <version>1.0-SNAPSHOT</version>
 18       <scope>test</scope>
 19 </dependency>
 20
 21```html
 22
 23每次构建项目时,Maven 将自动获取最新的快照。虽然,快照的情况下,Maven 在日常工作中会自动获取最新的快照, 你也可以在任何 maven 命令中使用 -U 参数强制 maven 现在最新的快照构建。
 24
 25mvn clean package -U
 26
 27**使用快照我们就不用频繁与依赖自己开发包的同事进行沟通了。maven会自动更新并引用最新快照。**
 28
 29## Maven 构建生命周期
 30
 31![Image](002-c2e02ea6.png "image.png")
 32
 33| 阶段 | 处理 | 描述 |
 34| --- | --- | --- |
 35| 验证 validate | 验证项目 | 验证项目是否正确且所有必须信息是可用的 |
 36| 编译 compile | 执行编译 | 源代码编译在此阶段完成 |
 37| 测试 Test | 测试 | 使用适当的单元测试框架(例如JUnit)运行测试。 |
 38| 包装 package | 打包 | 创建JAR/WAR包如在 pom.xml 中定义提及的包 |
 39| 检查 verify | 检查 | 对集成测试的结果进行检查,以保证质量达标 |
 40| 安装 install | 安装 | 安装打包的项目到本地仓库,以供其他项目使用 |
 41| 部署 deploy | 部署 | 拷贝最终的工程包到远程仓库中,以共享给其他开发人员和工程 |
 42
 43## 利用持续集成工具实现自动化构建
 44
 45比如你需要在本项目
 46
 47-   代码提交
 48
 49-   项目build
 50
 51-   项目deploy
 52
 53-   ......
 54
 55这些情况下其他项目跟着一起构建,比如你的jar包升级需要其他项目自动构建拉取最新版本时(可以结合版本范围控制)。
 56
 57**可以使用jenkins的自动化构建流程功能进行设计。(build after other projects are built)**
 58
 59**![Image](003-3f0ad123.png "image.png")**
 60
 61## 一些基础知识
 62
 63### 依赖传递(Transitive Dependencies)
 64
 65依赖传递(Transitive Dependencies)是Maven 2.0开始的提供的特性,依赖传递的好处是不言而喻的,可以让我们不需要去寻找和发现所必须依赖的库,而是将会自动将需要依赖的库帮我们加进来。
 66
 67例如A依赖了B,B依赖了C和D,那么你就可以在A中,像主动依赖了C和D一样使用它们。并且传递的依赖是没有数量和层级的限制的,非常方便。
 68
 69但依赖传递也不可避免的会带来一些问题,例如:
 70
 71-   当依赖层级很深的时候,可能造成循环依赖(cyclic dependency)
 72
 73-   当依赖的数量很多的时候,依赖树会非常大
 74
 75针对这些问题,Maven提供了很多管理依赖的特性
 76
 77### 依赖调节(Dependency mediation)
 78
 79依赖调节是为了解决版本不一致的问题(multiple versions),并采取就近原则(nearest definition)。
 80
 81举例来说,A项目通过依赖传递依赖了两个版本的D:
 82
 83A -> B -> C -> ( D 2.0) , A -> E -> (D 1.0),
 84
 85那么最终A依赖的D的version将会是1.0,因为1.0对应的层级更少,也就是更近。
 86
 87### scope 依赖范围
 88
 89    Maven的生命周期存在编译、测试、运行这些过程,那么显然
 90
 91-   有些依赖只用于测试比如junit;
 92
 93-   有些依赖编译用不到,只有运行的时候才能用到,比如mysql的驱动包在编译期就用不到(编译期用的是JDBC接口),而是在运行时用到的;
 94
 95-   还有些依赖,编译期要用到,而运行期不需要提供,因为有些容器已经提供了,比如servlet-api在tomcat中已经提供了,我们只需要的是编译期提供而已。
 96
 97总结说来,在POM 4中,,中还引入了,<dependency>中还引入了<scope>,它主要管理依赖的部署。大致有**compile、provided、runtime、test、system**等几个。
 98
 99| scope | 说明 | 示例 |
100| --- | --- | --- |
101| compile | 编译时需要用到该jar包(默认) | commons-logging |
102| test | 编译Test时需要用到该jar包 | junit |
103| runtime | 编译时不需要,但运行时需要用到 | mysql |
104| provided | 编译时需要用到,但运行时由JDK或某个服务器提供 | servlet-api |
105
106```xml
107<dependency>
108    <groupId>org.springframework</groupId>
109    <artifactId>spring-test</artifactId>
110    <scope>test</scope>
111</dependency>
112
113```html
114
115#### scope 的依赖传递
116
117     A -> B -> C   当前项目 A,A依赖于B,B依赖于C
118
119    **知道 B 在 A中的scope,怎么知道 C在 A 中的 scope ?** 即A需不需要 C的问题,本质由 C在B中的scope决定
120
121     当 C 在 B 中的scope 是test 或 provided 时,C 直接被丢弃,A不依赖C
122
123  否则 A 依赖 C,C的scope 继承与B 的scope
124
125### 依赖管理(Dependency management)
126
127通过声明Dependency management,可以大大简化子POM的依赖声明。
128
129举例来说项目A,B,C,D都有共同的Parent,并有类似的依赖声明如下:
130
131-   A、B、C、D/pom.xml
132
133```xml
134<dependencies>
135        <dependency>
136            <groupId>group-a</groupId>
137            <artifactId>artifact-a</artifactId>
138            <version>1.0</version>
139            <exclusions>
140                <exclusion>
141                    <groupId>group-c</groupId>
142                    <artifactId>excluded-artifact</artifactId>
143                </exclusion>
144            </exclusions>
145        </dependency>
146        <dependency>
147            <groupId>group-a</groupId>
148            <artifactId>artifact-b</artifactId>
149            <version>1.0</version>
150            <type>bar</type>
151            <scope>runtime</scope>
152        </dependency>
153</dependencies>

如果父pom声明了如下的Dependency management:

  • Parent/pom.xml
 1<dependencyManagement>
 2        <dependencies>
 3            <dependency>
 4                <groupId>group-a</groupId>
 5                <artifactId>artifact-a</artifactId>
 6                <version>1.0</version>
 7                <exclusions>
 8                    <exclusion>
 9                        <groupId>group-c</groupId>
10                        <artifactId>excluded-artifact</artifactId>
11                    </exclusion>
12                </exclusions>
13            </dependency>           
14            <dependency>
15                <groupId>group-a</groupId>
16                <artifactId>artifact-b</artifactId>
17                <version>1.0</version>
18                <type>bar</type>
19                <scope>runtime</scope>
20            </dependency>
21            <dependency>
22                <groupId>group-c</groupId>
23                <artifactId>artifact-b</artifactId>
24                <version>1.0</version>
25                <type>war</type>
26                <scope>runtime</scope>
27            </dependency>
28           
29        </dependencies>
30</dependencyManagement>
31
32```html
33
34那么子项目的依赖声明会非常简单:
35
36-   A、B、C、D/pom.xml
37
38```xml
39<dependencies>
40        <dependency>
41          <groupId>group-a</groupId>
42          <artifactId>artifact-a</artifactId>
43        </dependency>
44        <dependency>
45          <groupId>group-a</groupId>
46          <artifactId>artifact-b</artifactId>
47          <!-- 依赖的类型,对应于项目坐标定义的packaging。大部分情况下,该元素不必声明,其默认值是jar.-->
48          <type>bar</type>
49        </dependency>
50</dependencies>
51
52```html
53
54### 导入依赖范围
55
56它只使用在<dependencyManagement>中,表示从其它的pom中导入dependency的配置,例如 (B项目导入A项目中的包配置):
57
58想必大家在做SpringBoot应用的时候,都会有如下代码
59
60```xml
61<parent>
62    <groupId>org.springframework.boot</groupId>
63    <artifactId>spring-boot-starter-parent</artifactId>
64    <version>1.3.3.RELEASE</version>
65</parent>
66
67```html
68
69继承一个父模块,然后再引入相应的依赖。
70
71假如说,我不想继承,或者我想继承多个,怎么做?
72
73**我们知道Maven的继承和Java的继承一样,是无法实现多重继承的,如果10个、20个甚至更多模块继承自同一个模块,那么按照我们之前的做法,这个父模块的dependencyManagement会包含大量的依赖。如果你想把这些依赖分类以更清晰的管理,那就不可能了。**
74
75import scope依赖能解决这个问题。你可以把dependencyManagement放到单独的专门用来管理依赖的pom中,然后在需要使用依赖的模块中通过import scope依赖,就可以引入dependencyManagement。例如可以写这样一个用于依赖管理的pom:
76
77```xml
78<project>
79    <modelVersion>4.0.0</modelVersion>
80    <groupId>com.test.sample</groupId>
81    <artifactId>base-parent1</artifactId>
82    <packaging>pom</packaging>
83    <version>1.0.0-SNAPSHOT</version>
84    <dependencyManagement>
85        <dependencies>
86            <dependency>
87                <groupId>junit</groupId>
88                <artifactid>junit</artifactId>
89                <version>4.8.2</version>
90            </dependency>
91            <dependency>
92                <groupId>log4j</groupId>
93                <artifactid>log4j</artifactId>
94                <version>1.2.16</version>
95            </dependency>
96        </dependencies>
97    </dependencyManagement>
98</project>

然后我就可以通过非继承的方式来引入这段依赖管理配置

 1<dependencyManagement>
 2    <dependencies>
 3        <dependency>
 4            <groupId>com.test.sample</groupId>
 5            <artifactid>base-parent1</artifactId>
 6            <version>1.0.0-SNAPSHOT</version>
 7            <type>pom</type>
 8            <scope>import</scope>
 9        </dependency>
10    </dependencies>
11</dependencyManagement>
12 
13<dependency>
14    <groupId>junit</groupId>
15    <artifactid>junit</artifactId>
16</dependency>
17<dependency>
18    <groupId>log4j</groupId>
19    <artifactid>log4j</artifactId>
20</dependency>
21
22```html
23
24**注意:import scope只能用在dependencyManagement里面**
25
26这样,父模块的pom就会非常干净,由专门的packaging为pom来管理依赖,也契合的面向对象设计中的单一职责原则。此外,我们还能够创建多个这样的依赖管理pom,以更细化的方式管理依赖。这种做法与面向对象设计中使用组合而非继承也有点相似的味道。
27
28那么,如何用这个方法来解决SpringBoot的那个继承问题呢?
29
30配置如下:
31
32这样配置的话,自己的项目里面就不需要继承SpringBoot的module了,而可以继承自己项目的module了。
33
34```xml
35<dependencyManagement>
36    <dependencies>
37        <dependency>
38            <groupId>org.springframework.boot</groupId>
39            <artifactId>spring-boot-dependencies</artifactId>
40            <version>1.3.3.RELEASE</version>
41            <type>pom</type>
42            <scope>import</scope>
43        </dependency>
44    </dependencies>
45</dependencyManagement>
46 
47<dependencies>
48    <dependency>
49        <groupId>org.springframework.boot</groupId>
50        <artifactId>spring-boot-starter-web</artifactId>
51    </dependency>
52</dependencies>

Image

关注公众号 获取更多精彩内容

位旅人路过 次翻阅 初次见面