maven中的依赖机制简介
依赖管理是maven的一大特征,对于一个简单的项目,对依赖的管理并不是什么困难的事,但是如果这个项目依赖的库文件达到几十个甚至于上百个的时候就不是一个简单的问题了。在这个时候maven对于依赖管理的作用就显露出来了。下面主要讨论几个方面的内容:传递性依赖,依赖范围,依赖管理,系统依赖,可选依赖
传递性依赖:
传递性依赖是在maven2中添加的新特征,这个特征的作用就是你不需要考虑你依赖的库文件所需要依赖的库文件,能够将依赖模块的依赖自动的引入。例如我们依赖于spring的库文件,但是spring本身也有依赖,如果没有传递性依赖那就需要我们了解spring项目依赖,然后也要添加到我们的项目中。
由于没有限制依赖的数量,如果出现循环依赖的时候会出现问题,这个时候有两种方式处理,一种是通过build-helper-maven-plugin插件来规避,另一种就是重构两个相互依赖的项目。
通过传递性依赖,项目的依赖结构能够很快生成。但是因为这个新的特性会有一些其他的特性被添加进来来限制由于传递性依赖所引入的包。
依赖调节:如果在一个项目里面出现不同的模块,依赖了一个项目的不同版本的时候判断依赖的版本。maven2.0的时候仅仅支持最近原则也就是在依赖树中的最靠近项目的版本作为依赖版本。到了maven2.0.9的时候又提出了一个最先声明原则,也就是在项目中被最早声明的被判断为依赖的版本。
依赖管理:在传递性依赖或者没有指定版本的依赖的情况下,断定依赖的版本。
依赖范围:决定依赖在构建的那个阶段起作用。
排除依赖:在标签中可以明确的排除某个依赖。
可选依赖:标签这个依赖是可选的。
依赖范围
maven有三套classpath(编译classpath,运行classpath,测试classpath)分别对应构建的三个阶段。依赖范围就是控制依赖与这三套classpath的关系。依赖范围有六种:
compile:编译依赖范围,在三个classpath都有效。
test:测试依赖范围,在编译代码和运行代码是无效。
provided:以提供的依赖范围,在编译和测试的时候有效,在运行的时候无效。例如servlet-api,因为容器已经提供,在运行的时候是不需要的。
runtime:运行时依赖范围,仅在测试和运行的时候有效。例如jdbc只有在测试和运行的时候才有效。
system:系统依赖范围,与provided范围一致,但是依赖是通过系统变量来指定依赖,不利于移植。
import(在maven2.0.9后支持):导入依赖范围,对三个classpath没有实际影响。
依赖范围影响传递性依赖。假如a依赖于b,b依赖于c,那么第一个为第一个依赖,第二个为第二依赖。左边第一列是第一依赖,第一行是第二依赖。
compile | provided | runtime | test | |
compile | compile | - | runtime | - |
provided | provided | - | provided | - |
runtime | runtime | - | runtime | - |
test | test | - | test | - |
依赖管理
依赖管理是一个集中的依赖信息的一种方式。它可以提供一个将依赖信息放置在一个公共的POM中让子POM继承。但是它只是起到限制的作用并不会引入实际依赖。
下面提供两个例子
A项目
1: <project>
2: ...
3: <dependencies>
4: <dependency>
5: <groupId>group-a</groupId>
6: <artifactId>artifact-a</artifactId>
7: <version>1.0</version>
8: <exclusions>
9: <exclusion>
10: <groupId>group-c</groupId>
11: <artifactId>excluded-artifact</artifactId>
12: </exclusion>
13: </exclusions>
14: </dependency>
15: <dependency>
16: <groupId>group-a</groupId>
17: <artifactId>artifact-b</artifactId>
18: <version>1.0</version>
19: <type>bar</type>
20: <scope>runtime</scope>
21: </dependency>
22: </dependencies>
23: </project>
B项目
1: <project>
2: ...
3: <dependencies>
4: <dependency>
5: <groupId>group-c</groupId>
6: <artifactId>artifact-b</artifactId>
7: <version>1.0</version>
8: <type>war</type>
9: <scope>runtime</scope>
10: </dependency>
11: <dependency>
12: <groupId>group-a</groupId>
13: <artifactId>artifact-b</artifactId>
14: <version>1.0</version>
15: <type>bar</type>
16: <scope>runtime</scope>
17: </dependency>
18: </dependencies>
19: </project>
可以这两个pom里面有公共依赖,可以提到一个公共的父类POM中
1: <project>
2: ...
3: <dependencyManagement>
4: <dependencies>
5: <dependency>
6: <groupId>group-a</groupId>
7: <artifactId>artifact-a</artifactId>
8: <version>1.0</version>
9:
10: <exclusions>
11: <exclusion>
12: <groupId>group-c</groupId>
13: <artifactId>excluded-artifact</artifactId>
14: </exclusion>
15: </exclusions>
16:
17: </dependency>
18:
19: <dependency>
20: <groupId>group-c</groupId>
21: <artifactId>artifact-b</artifactId>
22: <version>1.0</version>
23: <type>war</type>
24: <scope>runtime</scope>
25: </dependency>
26:
27: <dependency>
28: <groupId>group-a</groupId>
29: <artifactId>artifact-b</artifactId>
30: <version>1.0</version>
31: <type>bar</type>
32: <scope>runtime</scope>
33: </dependency>
34: </dependencies>
35: </dependencyManagement>
36: </project>
通过这种做法,项目A和项目B的POM文件可以被简化
项目A
1: <project>
2: ...
3: <dependencies>
4: <dependency>
5: <groupId>group-a</groupId>
6: <artifactId>artifact-a</artifactId>
7: </dependency>
8:
9: <dependency>
10: <groupId>group-a</groupId>
11: <artifactId>artifact-b</artifactId>
12: <!-- This is not a jar dependency, so we must specify type. -->
13: <type>bar</type>
14: </dependency>
15: </dependencies>
16: </project>
项目B
1: <project>
2: ...
3: <dependencies>
4: <dependency>
5: <groupId>group-c</groupId>
6: <artifactId>artifact-b</artifactId>
7: <!-- This is not a jar dependency, so we must specify type. -->
8: <type>war</type>
9: </dependency>
10:
11: <dependency>
12: <groupId>group-a</groupId>
13: <artifactId>artifact-b</artifactId>
14: <!-- This is not a jar dependency, so we must specify type. -->
15: <type>bar</type>
16: </dependency>
17: </dependencies>
18: </project>
下面的例子是对于传递性依赖中版本控制
项目A
1: <project>
2: <modelVersion>4.0.0</modelVersion>
3: <groupId>maven</groupId>
4: <artifactId>A</artifactId>
5: <packaging>pom</packaging>
6: <name>A</name>
7: <version>1.0</version>
8: <dependencyManagement>
9: <dependencies>
10: <dependency>
11: <groupId>test</groupId>
12: <artifactId>a</artifactId>
13: <version>1.2</version>
14: </dependency>
15: <dependency>
16: <groupId>test</groupId>
17: <artifactId>b</artifactId>
18: <version>1.0</version>
19: <scope>compile</scope>
20: </dependency>
21: <dependency>
22: <groupId>test</groupId>
23: <artifactId>c</artifactId>
24: <version>1.0</version>
25: <scope>compile</scope>
26: </dependency>
27: <dependency>
28: <groupId>test</groupId>
29: <artifactId>d</artifactId>
30: <version>1.2</version>
31: </dependency>
32: </dependencies>
33: </dependencyManagement>
34: </project>
项目B
1: <project>
2: <parent>
3: <artifactId>A</artifactId>
4: <groupId>maven</groupId>
5: <version>1.0</version>
6: </parent>
7: <modelVersion>4.0.0</modelVersion>
8: <groupId>maven</groupId>
9: <artifactId>B</artifactId>
10: <packaging>pom</packaging>
11: <name>B</name>
12: <version>1.0</version>
13: <dependencyManagement>
14: <dependencies>
15: <dependency>
16: <groupId>test</groupId>
17: <artifactId>d</artifactId>
18: <version>1.0</version>
19: </dependency>
20: </dependencies>
21: </dependencyManagement>
22: <dependencies>
23: <dependency>
24: <groupId>test</groupId>
25: <artifactId>a</artifactId>
26: <version>1.0</version>
27: <scope>runtime</scope>
28: </dependency>
29: <dependency>
30: <groupId>test</groupId>
31: <artifactId>c</artifactId>
32: <scope>runtime</scope>
33: </dependency>
34: </dependencies>
35: </project>
当运行项目B的时候,a,b,c,d都是version1.0。
首先a,c被显式的声明,然后是b在parent中的依赖管理中设定。然后是d虽然在parent中有但是在本项目中也有定义,本项目优先于父项目,所有也是version1.0。
导入依赖
这个特性是在maven2.0.9中被添加的。在上面的例子中提供了一种通过继承的方式来管理依赖。下面提供一种导入的方式来引入依赖管理。通过设定scope为import来实现。
项目B
1: <project>
2: <modelVersion>4.0.0</modelVersion>
3: <groupId>maven</groupId>
4: <artifactId>B</artifactId>
5: <packaging>pom</packaging>
6: <name>B</name>
7: <version>1.0</version>
8: <dependencyManagement>
9: <dependencies>
10: <dependency>
11: <groupId>maven</groupId>
12: <artifactId>A</artifactId>
13: <version>1.0</version>
14: <type>pom</type>
15: <scope>import</scope>
16: </dependency>
17: <dependency>
18: <groupId>test</groupId>
19: <artifactId>d</artifactId>
20: <version>1.0</version>
21: </dependency>
22: </dependencies>
23: </dependencyManagement>
24: <dependencies>
25: <dependency>
26: <groupId>test</groupId>
27: <artifactId>a</artifactId>
28: <version>1.0</version>
29: <scope>runtime</scope>
30: </dependency>
31: <dependency>
32: <groupId>test</groupId>
33: <artifactId>c</artifactId>
34: <scope>runtime</scope>
35: </dependency>
36: </dependencies>
37: </project>
下面我们给出一个导入两个项目的时的例子。
X项目
1: <project>
2: <modelVersion>4.0.0</modelVersion>
3: <groupId>maven</groupId>
4: <artifactId>X</artifactId>
5: <packaging>pom</packaging>
6: <name>X</name>
7: <version>1.0</version>
8: <dependencyManagement>
9: <dependencies>
10: <dependency>
11: <groupId>test</groupId>
12: <artifactId>a</artifactId>
13: <version>1.1</version>
14: </dependency>
15: <dependency>
16: <groupId>test</groupId>
17: <artifactId>b</artifactId>
18: <version>1.0</version>
19: <scope>compile</scope>
20: </dependency>
21: </dependencies>
22: </dependencyManagement>
23: </project>
Y项目
1: <project>
2: <modelVersion>4.0.0</modelVersion>
3: <groupId>maven</groupId>
4: <artifactId>Y</artifactId>
5: <packaging>pom</packaging>
6: <name>Y</name>
7: <version>1.0</version>
8: <dependencyManagement>
9: <dependencies>
10: <dependency>
11: <groupId>test</groupId>
12: <artifactId>a</artifactId>
13: <version>1.2</version>
14: </dependency>
15: <dependency>
16: <groupId>test</groupId>
17: <artifactId>c</artifactId>
18: <version>1.0</version>
19: <scope>compile</scope>
20: </dependency>
21: </dependencies>
22: </dependencyManagement>
23: </project>
Z项目
1: <project>
2: <modelVersion>4.0.0</modelVersion>
3: <groupId>maven</groupId>
4: <artifactId>Z</artifactId>
5: <packaging>pom</packaging>
6: <name>Z</name>
7: <version>1.0</version>
8: <dependencyManagement>
9: <dependencies>
10: <dependency>
11: <groupId>maven</groupId>
12: <artifactId>X</artifactId>
13: <version>1.0</version>
14: <type>pom</type>
15: <scope>import</scope>
16: </dependency>
17: <dependency>
18: <groupId>maven</groupId>
19: <artifactId>Y</artifactId>
20: <version>1.0</version>
21: <type>pom</type>
22: <scope>import</scope>
23: </dependency>
24: </dependencies>
25: </dependencyManagement>
26: </project>
在这个例子中Z导入了X,Y,那么两个里面都有a,但是由于先导入X,所有a是1.1的版本。导入是递归的,如果X还导入了一个项目Q, 那么Q也会被导入到Z。
需要注意的地方,不要导入当前POM的子POM,因为它无法定位。
系统依赖
常常被用来告知jdk和虚拟机中提供的依赖。
例一:
1: <project>
2: ...
3: <dependencies>
4: <dependency>
5: <groupId>javax.sql</groupId>
6: <artifactId>jdbc-stdext</artifactId>
7: <version>2.0</version>
8: <scope>system</scope>
9: <systemPath>${java.home}/lib/rt.jar</systemPath>
10: </dependency>
11: </dependencies>
12: ...
13: </project>
例二:
1: <project>
2: ...
3: <dependencies>
4: <dependency>
5: <groupId>sun.jdk</groupId>
6: <artifactId>tools</artifactId>
7: <version>1.5.0</version>
8: <scope>system</scope>
9: <systemPath>${java.home}/../lib/tools.jar</systemPath>
10: </dependency>
11: </dependencies>
12: ...
13: </project>
可选依赖
可选依赖使用的情况是对于某个依赖来说系统只有在某个特定的情况下使用到它。例如数据库驱动,有mysql的,oracle的。只有在我们使用到mysql的时候才会被使用。
使用方式
1: <project>
2: ...
3: <dependencies>
4: <!-- declare the dependency to be set as optional -->
5: <dependency>
6: <groupId>sample.ProjectA</groupId>
7: <artifactId>Project-A</artifactId>
8: <version>1.0</version>
9: <scope>compile</scope>
10: <optional>true</optional> <!-- value will be true or false only -->
11: </dependency>
12: </dependencies>
13: </project>
依赖排除
对于某些因为某些原因被导入而你又不想引入的依赖进行排除。
1: <project>
2: ...
3: <dependencies>
4: <dependency>
5: <groupId>sample.ProjectA</groupId>
6: <artifactId>Project-A</artifactId>
7: <version>1.0</version>
8: <scope>compile</scope>
9: <exclusions>
10: <exclusion> <!-- declare the exclusion here -->
11: <groupId>sample.ProjectB</groupId>
12: <artifactId>Project-B</artifactId>
13: </exclusion>
14: </exclusions>
15: </dependency>
16: </dependencies>
17: </project>
相关推荐
5. **仓库**:Maven依赖的存储库,包括本地仓库(默认在用户目录下)和远程仓库(如中央仓库mvnrepository.com)。当本地仓库没有所需依赖时,Maven会尝试从远程仓库下载。 6. **排除依赖(exclude)**:有时候我们...
Maven的依赖管理还遵循一定的依赖解决机制。如果一个项目依赖A,A又依赖B,Maven会自动解决这种层级关系,确保所有依赖都被正确地引入。此外,Maven还有“排除依赖”功能,允许你在引入特定依赖时排除其中的子依赖。...
在这个名为“maven依赖小例子”的源码中,你可以看到如何实际配置和使用Maven依赖的示例。通过分析源码,你可以更好地理解Maven POM.xml文件的结构和依赖管理的工作方式。在实际开发中,熟练掌握Maven依赖管理不仅能...
在软件开发领域,Maven是一个广泛使用的项目管理和综合工具,主要负责构建、依赖管理和...在这个名为“maven依赖+继承+聚合”的示例中,我们可以期待看到如何实际应用这些概念,以实现一个简洁且易于管理的项目结构。
1. **依赖管理**:Maven依赖是项目中各个模块之间共享代码的关键机制。当你在POM.xml文件中声明一个依赖,Maven会自动下载并管理这些依赖的版本,避免版本冲突。依赖可以通过`<dependencies>`标签进行定义,如`...
总结来说,解决Maven依赖冲突需要深入理解Maven的依赖管理和类加载机制。在本案例中,通过修改冲突依赖的类路径,可以实现多版本依赖的共存,但这种方式并不适用于所有场景,因此在实际应用中应谨慎考虑。在可能的...
<groupId>org.apache.tomcat.maven</groupId> <artifactId>tomcat8-maven-plugin</artifactId> <version>3.0-r1655215</version> </plugin> ``` 但是,如果我们直接添加上面的依赖项,Maven 将无法找到该插件,...
然而,在实际开发中,我们常常会遇到一些不可以在公共 Maven 存储库中的依赖关系,这时我们需要手动添加这些依赖关系到 Maven 项目中。 添加非托管到 Maven 项目依赖关系的步骤: 1. 定义依赖关系的参数:首先,...
Maven插件同样在`pom.xml`中声明,位于`<build>`标签下: ```xml <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.8.1...
在软件开发中,Maven作为Java项目管理和构建工具,其依赖管理的核心机制是通过仓库(Repository)来获取项目所需的依赖库。Maven默认使用中央仓库,但有时我们需要配置多个仓库,例如私有仓库,以提高依赖下载速度或...
在实际开发中,遇到类似问题时,应仔细检查pom.xml配置,调整插件执行顺序,或者利用Maven的生命周期和插件机制来解决这类资源竞争和清理问题。同时,对Maven的源码进行一定的了解也有助于更好地理解问题的本质。
- **依赖管理**:Maven的依赖管理机制能够自动解决依赖冲突问题,减少手动处理依赖的时间。 - **多模块支持**:Maven支持多模块项目,便于大型项目的组织和管理。 - **社区资源丰富**:Maven拥有庞大的社区支持,...
然后运行`mvn install`命令,Maven会将这个jar包安装到本地仓库,之后就可以像引用其他Maven依赖一样引用它。 2. **在IntelliJ IDEA中配置本地jar包** - 打开IntelliJ IDEA,选择`File` -> `Project Structure` -...
依赖范围(scope)是Maven依赖管理的一个重要概念。scope定义了依赖项的使用范围,主要有以下几个选项:compile、provided、runtime和test。compile表示依赖项在编译时需要,provided表示依赖项在编译和测试时需要,但...
总的来说,`2.5.0-proto.exe`和对应的maven依赖是为Java开发者提供的一种工具集,使他们能够在项目中方便地使用protobuf进行数据序列化和网络通信。通过理解.proto文件的语法,配合`protoc.exe`编译器和相应的Maven...
Maven的依赖管理通过`pom.xml`中的`<dependencies>`标签实现。每个`<dependency>`标签代表一个外部库,包括其`groupId`、`artifactId`和`version`。`<scope>`属性定义了依赖的范围,如`compile`(编译时)、`test`...
<artifactId>maven-assembly-plugin</artifactId> <version>3.3.0</version> <configuration> <!-- 配置assembly描述符 --> <descriptorRefs> <descriptorRef>jar-with-dependencies</descriptorRef> </...
<groupId>org.apache.maven.plugins</groupId> <artifactId>maven-jar-plugin</artifactId> <configuration> <archive> <manifest> <addClasspath>true</addClasspath> <classpathPrefix>lib/</...
Maven的依赖机制遵循“传递性”原则,这意味着如果你的项目依赖A,而A又依赖B,那么Maven会自动将B也引入到你的项目中。但是,这可能导致版本冲突,因此Maven提供了`exclusions`标签来排除不需要的依赖。 在进行...
首先,`scope test`是Maven依赖管理中的一个关键概念。当我们在`pom.xml`文件中为某个依赖设置`scope`为`test`时,意味着这个依赖只会在单元测试阶段被引入。例如,JUnit或Mockito这样的测试框架通常会被标记为`test...