Maven笔记 - 第三章
第3篇:坐标和依赖详解
maven系列目标:从入门开始开始掌握一个高级开发所需要的maven技能。**
这是maven系列第3篇。
我们先来回顾一下什么是maven?
maven是由apache软件基金会组织维护的一款自动化构建工具,专注于服务于java平台的项目构建以及依赖管理
预备知识
Maven系列:第1篇:Maven未出世前,我们那些痛苦的经历!
Maven系列第2篇:安装、配置、mvn运行过程详解
本文主要内容
感受一下maven的效果
maven约定配置
maven中pom文件
maven坐标
maven依赖导入功能
maven依赖范围详解
maven依赖的传递
maven中依赖调解功能
可选依赖(optional元素)的使用
排除依赖的使用
先来感受一下maven的神奇
安装maven3.6.10
采用的是Maven 3.6.2版本,并且该版本运行中可能遇到一些问题,请您参考上一篇内容重新安装Maven 3.6.1版本以解决相关问题。
idea中配置maven
再说几句:假如你的开发环境中运行着Eclipse的话,请务必尝试一下IDEA这个开发工具。它是一款非常优秀的软件解决方案!在后续的内容中,默认以IDEA作为我们的开发平台来进行案例演示。我们鼓励所有读者也下载并安装IDEA以便实践操作。
打开idea,点击File->setting
外部链接中的图片无法正常上传,请您尝试将该文件保存到本地设备后再重新上传
按照如下配置maven的信息,点击“ok”,idea中maven配置完成
注意"Maven home directory"选择我们上面安装的3.6.1
User settings file 和 Local repository 我们使用用户级别的。
建议先将图像保存到本地设备后再进行上传操作以确保文件能够正常加载并避免因防盗链机制导致的访问问题
使用mven创建一个springboot项目
我们来搭建一个Web应用的基础,并通过Maven工具实现项目的构建来看看是否简便
打开idea,点击File->New->Project,选择Spring Initializr,如下:
由于外链图片无法正常上传(...),可能存在防盗链等技术防护措施,请您考虑将图片保存至本地电脑后再重新发布对应的链接信息(img-8JDmQPwi-1629908465211)
点击"Next",如下图,按照图中的信息输入,点击"Next":
咱们先不用关注需要输入的信息具体是什么意思,后面会讲解。
外部链接的图片无法正常存取可能导致存储异常,请检查相关服务器设置并采取相应措施以避免此类问题;同时建议将图片保存到本地后再重新插入以确保上传成功
选择springboot版本,勾选"Lombook"、“Spring Web”,如下图:
该图片外链存储过程中出现无法正常转存的情况,请留意源站点可能存在缓存机制以防止过度访问,并按照提示操作。
外链图片无法正常显示,可能因目标网站采用防止图片防盗链的技术,建议将图片保存后重新上传
点击"Next"->"Finish"完成springboot项目的创建,如下图:
外链图片转存失败,可能由于服务器端的防盗链配置导致,建议检查相关服务器设置并联系管理员进一步排查问题
删掉下图中无关的文件
按住Shift健,多选,然后点击Del健删除。
注
外部链接中的图片无法正常上传
新建一个Controller类:
com.javacode2018.controller;
org.springframework.web.bind.annotation.RequestMapping;
org.springframework.web.bind.annotation.RestController;
@RestController
IndexController {
@RequestMapping("")
String index() {
"你好,欢迎你和【马士兵老师】一起学些Maven相关技术!";
}
}
springboot-chat01目录中打开cmd窗口,执行下面命令
mvn spring-boot:run
cmd中输出如下:
D:\code\IdeaProjects\springboot-chat01>mvn spring-boot:run
[INFO] Scanning for projects...
[INFO]
[INFO] -----------------< com.javacode2018:springboot-chat01 >-----------------
[INFO] Building springboot-chat01 0.0.1-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] >>> spring-boot-maven-plugin:2.2.1.RELEASE:run (default-cli) > test-compile @ springboot-chat01 >>>
[INFO]
[INFO] --- maven-resources-plugin:3.1.0:resources (default-resources) @ springboot-chat01 ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] Copying 1 resource
[INFO] Copying 0 resource
[INFO]
[INFO] --- maven-compiler-plugin:3.8.1:compile (default-compile) @ springboot-chat01 ---
[INFO] Changes detected - recompiling the module!
[INFO] Compiling 2 source files to D:\code\IdeaProjects\springboot-chat01\target\classes
[INFO]
[INFO] --- maven-resources-plugin:3.1.0:testResources (default-testResources) @ springboot-chat01 ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] skip non existing resourceDirectory D:\code\IdeaProjects\springboot-chat01\src\test\resources
[INFO]
[INFO] --- maven-compiler-plugin:3.8.1:testCompile (default-testCompile) @ springboot-chat01 ---
[INFO] Changes detected - recompiling the module!
[INFO] Compiling 1 source file to D:\code\IdeaProjects\springboot-chat01\target\test-classes
[INFO]
[INFO] <<< spring-boot-maven-plugin:2.2.1.RELEASE:run (default-cli) < test-compile @ springboot-chat01 <<<
[INFO]
[INFO]
[INFO] --- spring-boot-maven-plugin:2.2.1.RELEASE:run (default-cli) @ springboot-chat01 ---
[INFO] Attaching agents: []
. ____ _ __ _ _
/\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\ / ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.2.1.RELEASE)
2019-11-11 14:43:58.758 INFO 19004 --- [ main] c.j.SpringbootChat01Application : Starting SpringbootChat01Application on DESKTOP-3OB6NA3 with PID 19004 (D:\code\IdeaProjects\springboot-chat01\target\classes started by Think in D:\code\IdeaProjects\springboot-chat01)
2019-11-11 14:43:58.761 INFO 19004 --- [ main] c.j.SpringbootChat01Application : No active profile set, falling back to default profiles: default
2019-11-11 14:44:01.116 INFO 19004 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http)
2019-11-11 14:44:01.125 INFO 19004 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
2019-11-11 14:44:01.125 INFO 19004 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.27]
2019-11-11 14:44:01.213 INFO 19004 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2019-11-11 14:44:01.213 INFO 19004 --- [ main] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 2417 ms
2019-11-11 14:44:01.339 INFO 19004 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor'
2019-11-11 14:44:01.457 INFO 19004 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''
2019-11-11 14:44:01.460 INFO 19004 --- [ main] c.j.SpringbootChat01Application : Started SpringbootChat01Application in 2.972 seconds (JVM running for 3.348)
2019-11-11 14:44:25.892 INFO 19004 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet'
2019-11-11 14:44:25.892 INFO 19004 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet'
2019-11-11 14:44:25.896 INFO 19004 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 3 ms
浏览器中访问
http:
效果如下:
你好,欢迎你和【马士兵老师】一起学些Maven相关技术!
在整个过程中
在开发一个基于SpringMVC的Java项目时, 我们需要确保项目的依赖性得到满足. 为此, 我们会收集与SpringMVC相关的各种依赖项, 将这些依赖项复制到项目的lib目录下, 并将其添加进classpath环境变量中. 在实际操作过程中, 通常会遇到Java Virtual Machine(JVM)版本不兼容或依赖项缺失的情况, 这使得我们不得不将大量时间投入到解决这些问题的过程中.
在项目管理中,我们采用了Maven工具来解决问题。在创建项目后,请注意其中最为关键的是pom.xml文件。大家都可以查看一下具体情况如下:
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.1.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.javacode2018</groupId>
<artifactId>springboot-chat01</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springboot-chat01</name>
<description>Demo project Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional></optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
生成自pom.xml的文件能够自动集成springmvc所需的所有组件,并且提供了支持mvn spring-boot:run启动功能的可能性。听起来很神奇的是这些功能都是通过maven这一强大的工具来实现配置工作的。maven能够解析pom中的配置信息并加载项目中所需的依赖项jar包等信息来进行构建工作。此外maven还允许我们在pOM文件中详细设置如何构建项目以及相关的其他参数等信息
了解如何通过mvn spring-boot:run启动项目。当您学到maven声明周期与插件的相关知识时,请不要着急,请耐心等待。相信您很快就能理解这些概念,请您稍等片刻。
熟悉ant的朋友都知道,在ant项目中有一个build.xml文件需要进行特定配置;而pom.xml文件则承担着与build.xml类似的功能,并非由ant直接执行相关操作;相反,在maven生态系统中,默认提供了一系列标准化的服务功能:包括版本管理、解决依赖冲突、打包与部署等;如果希望利用maven来解决上述问题,则必须提供一个pom.xml配置文件,并严格遵循我所指定的项目结构安排;这是所谓的约定配置方式;而在使用ant时,则允许用户自行定义项目源码位置、资源存放处所及输出目录等细节;因此在那种情况下确实需要编写较多的配置参数;而在maven环境下则无需过多考虑这些细节问题;这就是maven的优势所在
约定配置
Maven 推行一个常规的标准目录结构。
Maven 是一种基于约定优于配置的原则来组织项目的工具。
大家努力使自己遵循这一规范以保证代码的一致性和可维护性。
如下所示:
| 目录 | 目的 |
|---|---|
| ${basedir} | 存放pom.xml和所有的子目录 |
| ${basedir}/src/main/java | 项目的java源代码 |
| ${basedir}/src/main/resources | 项目的资源,比如说property文件,springmvc.xml |
| ${basedir}/src/test/java | 项目的测试类,比如说Junit代码 |
| ${basedir}/src/test/resources | 测试用的资源 |
| ${basedir}/src/main/webapp/WEB-INF | web应用文件目录,web项目的信息,比如存放web.xml、本地图片、jsp视图页面 |
| ${basedir}/target | 打包输出目录 |
| ${basedir}/target/classes | 编译输出目录 |
| ${basedir}/target/test-classes | 测试编译输出目录 |
| Test.java | Maven只会自动运行符合该命名规则的测试类 |
| ~/.m2/repository | Maven默认的本地仓库目录位置 |
通过查看上述表格中的信息, 再了解 springboot-chat01 项目的结构, 这是遵循 Maven 项目标准的架构, 大家普遍遵循这一约定来进行开发工作。这样一来, 在 Maven 中打包、运行和部署会非常便捷, Maven能够识别并管理你的项目源码以及相关的资源和测试代码, 并知道这些文件应放置在哪里以实现打包输出。这些都是 Maven 预先定义的标准位置, 而非随意构建的架构, 因此无需额外配置即可开始使用。
在现实中有很多实际案例可供参考。例如 USB 接口和电压等基本概念都是预先规定的标准参数。假如 USB 接口的不同厂商生产的尺寸不统一,则会导致我们在实际应用中体验起来非常不便。
pom文件
当我们在项目中需要用到maven辅助完成jar包依赖问题时,在开发流程中的几个关键环节(如编译、测试、打包和部署)也会遇到困难时,则每个项目的开发团队都必须创建一个pom.xml配置文件。所有功能都是基于pom.xml文件进行配置实现的。
POM(Project Object Model)作为Maven工程的核心单元,在软件开发中扮演着关键角色。它采用XML格式存储详细的信息,并用于明确项目的构建过程以及项目的依赖关系之外的其他重要细节。
在当前目录中存在一个用于执行任务的POM文件位置。该POM文件包含了所需配置的信息内容并进行了相应的处理步骤。
POM 中可以指定以下配置:
项目依赖
插件
执行目标
项目构件 profile
项目版本
项目开发者列表
相关邮件列表信息
在创建 POM 之前,我们首先需要描述项目组 (groupId),项目的唯一ID。
version="1.0" encoding="UTF-8"
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"
4.0.0
com.javacode2018
maven-chat02
1.0-SNAPSHOT
pom的内容比较多,我们慢慢讲,大家慢慢吸收,利于消化。
maven坐标
在采用Maven构建项目的流程中,必须明确标识出项目的具体坐标位置,以便于各个构建阶段能够准确地定位和管理项目的结构关系.每个构件都具有独特的坐标值,这个值决定了它在整个项目的空间布局中的具体位置和作用范围.在构建过程中,项目在运行过程中会调用到一些外部组件或依赖项,这些外部组件或依赖项也必须提供它们自身的定位信息,以便于整个系统的协调运作.
Maven项目的构件坐标由一系列参数配置决定, 包括groupId, artifactId, version, packaging以及classifier等关键属性. 例如我们之前创建的Spring Boot项目, 其pom文件中的坐标参数设置如下:
com.javacode2018
springboot-chat01
0.0.1-SNAPSHOT
jar
goupId:定义当前构件所属的组,通常与域名反向一一对应。
artifactId:项目组中构件的编号。
Version:当前组件的唯一标识符。每个组件可能会发布多个 version number以区分不同的 components。
package:指定该组件的打包类型。例如,在需要将项目打包为JAR文件时,默认情况下运行命令
java \-jar即可实现;若需要部署到Web服务器上,则应将打包结果设为WAR格式。具体来说:
如果当前项目是一个Web应用,则应将其打包为WAR格式并部署至Tomcat服务器。
常见的打包类型包括JAR(适用于独立应用)、WAR(适用于Web应用)、EAR(适用于Java EE应用程序)、POM(用于Maven项目的构建)以及Maven插件。
这些打包类型的选择将直接影响最终部署环境下的服务运行方式。
在项目管理界面中,在添加新依赖时,请注意以下几点:首先,在输入窗口中选择一个现有的项目库;其次,在下方的属性面板中依次指定其中的groupId、artifactId和version字段;最后,在包字段可选的情况下,默认设置为jar格式。
我们可以通过发布上述创建的Spring Boot项目来实现目标;然后只需告知他人Spring Boot-Chat 01项目的坐标即可;其他人即可直接使用;而且当其他人使用时无需关注其运行所需的依赖项;这些自动会被引入到环境中
maven导入依赖的构件
Maven能够提供所需的构建块(如jar等),那么它是如何定位到某个特定组件呢?
在项目中若需要引入外部依赖项时,请明确其坐标信息,并将其整合到pom.xml文件中的dependencies元素中
deps元素中可以包含多个dependency项(即依赖关系项),每个dependency存储当前项目所需依赖的一个构件的数据。
在依赖项中 groupId 作为主键标识符(即 artifactId 和 version),以及 version 是构建组件时不可或缺的信息。
type属性:用于表示所要依赖的不同类型的构建物。这些构建物与被依赖的对象进行关联配置。该属性通常情况下,默认设置为jar(即 jar包或 jar文件)。
scope:依赖的范围,后面详解
option:标记依赖是否可选,后面详解
exclusions:用来排除传递性的依赖
一般而言,在使用过程中我们通常会依赖一些jar包。因此,在大多数情况下仅需提供 groupId、artifactId 和 version 信息即可。
创建一个maven项目(maven-chat02)
打开idea,点击File->New->Project,选择Maven,如下:
外部链接中的图片无法正常存储。可能存在防盗链保护机制,请检查网络连接后重试。
点击Next,输入项目的maven坐标信息,如下:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hc8n5CN8-1629908465227)(media/fbddabd161558e7e92855be73c2501b9.png)]
点击Next->Finish,完成项目的创建,项目结构如下:
由于外部链接中的图片文件未能成功上传(图:be747e43a18a822b01c1979db9142f02),建议先将图片保存到本地设备后再尝试上传
打开pom.xml,引入springmvc依赖,如下:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>5.2.1.RELEASE</version>
</dependency>
pom.xml文件最终如下:
<?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/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.javacode2018</groupId>
<artifactId>maven-chat02</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>5.2.1.RELEASE</version>
</dependency>
</dependencies>
</project>
可以看到我们仅引入了一个spring-web相关的核心jar包。考虑到 springmvc 的运行机制,它不仅依赖于 spring-core 等相关的核心jar包,并且希望了解 Maven 是否也进行了必要的 imports.
在pom.xml文件内执行以下操作:单击右键并选择"显示依赖项"选项(如 Show Dependencies ),这将能够在下方展示当前项目的依赖jar包列表。
建议将图片保存下来后直接上传
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iqzYeC6E-1629908465231)(media/e9135d9608b259e5fd62f4a58e86a9df.png)]
上图中呈现了项目中的依赖信息网络结构。其中箭线呈多层次分布由左至右排列最左侧的箭线代表一级直接依赖关系其余的均属于二级及以上的间接依赖关系形成了传递性依赖关系网络
在Maven-chat-02项目中,我们引入了Spring-Web框架,并未包含Spring-Beans、Spring-Core以及Spring-JCL等组件。但这些额外的依赖项是由Maven自动管理。由于Spring-Web-POM.xml文件自定义包含了这些必要的库,因此当使用春豆网时,其所需的JAR文件会通过Maven机制自动生成。那么,Maven是否如此强大?
如果不使用 Maven 寻找 Jar 会感到相当痛苦;通常我们会遇到遗漏一些 Jar 的情况,并且由于版本不兼容的问题导致无法顺利构建项目;不过 Maven 简化了这一过程。
maven依赖范围(scope)
我们的需求:
在开发项目的过程中, 我们可能会需要用到JUnit编写一些测试用例. 因此, 需要引入JUnit对应的JAR文件. 不过, 当我们的项目被物理部署到线上后, 这些测试代码将不再被执行. 此时, JUnit JAR文件也就不再需要了. 因此, JUnit JAR文件仅用于编译测试代码, 并在运行测试用例时使用, 在线部署完成后则不再需要.
我们开发了一个基于Web的项目,在其中使用了与Servlet相关的JavaBean组件库。当我们进行部署操作时, 这些功能会被整合到Tomcat服务器中, 而Tomcat服务器本身包含了运行Servlet所需的JavaBean组件库。这意味着, 在我们的开发过程中(包括编译和单元测试阶段), 我们需要确保这些JavaBean组件库的存在。一旦上线至Web服务器运行环境中, 这些与Servlet相关的依赖项将由Web服务器提供的应用容器自动管理, 因此在打包成Web应用容器(如WAR文件)时, 我们不需要将这些与Servlet相关的依赖项直接包含进去就可以满足需求
像jdbc的驱动,只有在运行的时候才需要,编译的时候是不需要的
这些需求怎么实现呢?
我们都知道,在Java中编译与运行代码都离不开classpath这个变量。它负责管理项目所需的Java资源,并列出所有依赖的JAR包以确保项目的顺利运行。如果您对此还有疑问,则建议参考相关资料。
我们都知道,在Java中编译与运行代码都离不开classpath这个变量。它负责管理项目所需的Java资源,并列出所有依赖的JAR包以确保项目的顺利运行。如果您对此还有疑问,则建议参考相关资料。
在Maven使用中,classpath涉及的地方包括源码的构建过程中、测试阶段的构建与执行过程、测试阶段的执行过程中以及项目的全生命周期管理中。这些环节都需要依赖于classpath。
针对上述相关问题,在进行编译测试及运行操作时所需的classpath其具体配置可能有所不同,在maven框架中定义了相应的解决方案。从而能够有效解决相关问题。该参数的作用在于管理项目中依赖组件与其使用的classpath之间的关系(特别是涉及编译打包及运行时使用的classpath)。该参数有如下几种取值:
compile
编译所需的依赖范围,在未做特别指明的情况下,默认采用该范围的设置;适用于处理编译源码、编译测试代码以及运行测试时所使用的四种classpath配置(如上文所述)。
test
在测试范围内,在使用此maven依赖项时,请注意该依赖项仅适用于构建和执行测试类路径,在主代码构建和项目的实际运行过程中则不受影响。例如junit库,则仅在构建测试用例及其执行过程中起作用。
provide
已设置好所需组件。表明项目运行环境中已预先配置了必要的组件以满足当前需求。针对该maven依存项涉及的依赖关系,在构建源码及执行测试构建时classpath会起作用;而运行时则无需依赖这些类路径资源。例如前面提到的servlet-api依存项,在编译与测试阶段需使用该组件;但当Web应用进入运行状态后,默认情况下Web服务器会提供相应的服务资源以替代类路径配置。
runtime
运行时依赖范围内适用的Maven依赖,在编译测试、执行测试以及运行项目类路径下有效,在编译主代码时不适用。例如,JDBC驱动实现仅在运行时才需具体配置
system
系统依赖范围内的类依赖与其他项目中classpath的关系与provided依赖范围完全一致。然而,在使用系统范围的依赖时,请通过systemPath元素显式指定需要引用的具体文件路径。需要注意的是这类应用直接基于本地构建目录中的组件,在不同开发环境中可能由于构建目录路径不一致而导致问题发生。鉴于此建议谨慎采用这类结构
如下:
com.javacode2018
rt
1.8
system
${java.home}/lib/rt.jar
import
这个主题特别重要,在后续文章中专门介绍;在Spring Boot及Spring Cloud相关开发中应用广泛。
依赖范围与classpath的关系如下:
| 依赖范围 | 编译源码 | 编译测试代码 | 运行测试 | 运行项目 | 示例 |
|---|---|---|---|---|---|
| compile | Y | Y | Y | Y | spring-web |
| test | - | Y | Y | - | junit |
| provide | Y | Y | Y | - | servlet-api |
| runtime | - | Y | Y | Y | jdbc驱动 |
| system | Y | Y | Y | - | 本地的jar包 |
当scope为项目范围服务时,在构建完成后,
这些依赖类库会在项目的主类库中被包含,
在执行时会自动加入系统路径变量$CLASSPATH。如果scope不为项目范围服务,
构建过程中就不会包含这些外部依赖类库。
依赖的传递
在我们的Maven项目maven-chat02$中包含了对Spring Web框架的支持,并且我们在构建时仅引入了一个名为spring-web$的关键依赖项。由于Spring Web本身也需要一些必要的第三方库支持(如Spring Beans、Spring Core以及Spring JCL),因此这些必要的第三方库也会被自然包含进去。这种机制被称为依存关系传播(Dependency Injection)。
不过上面我们说的scope元素的值会对这种传递依赖会有影响。
基于A基于B基于C我们定义A对B为一级直接依存关系B对C为二级直接依存关系而A对C则表现为间接依存关系其中一级直接依存关系的覆盖范围与二级直接依存关系的覆盖范围共同决定了该间接依存关系的整体覆盖广度即主要取决于前者对后者的影响大小。
以表格的形式列出这种依赖关系的影响。其中,在表格的第一栏中表示第一直接依赖(即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的关系中\texttt{scope}被设定为\texttt{compile}值;而在其对应的B到C关系中\texttt{scope}被设定为\texttt{test}值。根据上表所示,则该关系在特定条件下不具备传递性特征;因此,在这种情况下,A不具备使用C的能力。
例如,在A\rightarrow B的关系中,
其scope为\texttt{compile},
而在B\rightarrow C的关系中,
其scope则为\texttt{runtime}。
根据上述表格所示的位置,
对应于该表格中的第二行第五列位置处,
其对应的值为\texttt{runtime},
这意味着A对于C的行为范围属于\texttt{runtime}范畴,
即当对A执行打包操作时,
系统会将与之相关的所有依赖项(如C)一并打包至A所在的包内。
上表呈现了一定规律性,在编译状态下(表格第二行),其作用域与前一环节相同;测试状态下(第三行),此作用无法向下级转移;在提供状态下(第四行),仅限于前一环节作用域为提供的场景;其余情况下则无法向下级转移。
在运行时情境下(第五行),则通过其作用域将作用传递给下一环节。
上面表格大家多看几遍,理解理解
maven依赖调解功能
在实际项目中可能存在这样的配置:当目标节点存在多个依赖路径时,默认会生成多个实现版本;具体而言,在这种情况下,Maven将如何选择目标版本?
解决这种问题,maven有2个原则:
路径最近原则
上面A->B->C->Y(1.0),A->D->Y(2.0),Y的2.0版本距离A更近一些,所以maven会选择2.0。
但是如果出现了路径是一样的,如:A->B->Y(1.0),A->D->Y(2.0),此时maven又如何选择呢?
最先声明原则
当遇到路径相同的情况时(如果出现了路径一样的),系统会对A的pom.xml中所依赖的B、D的位置进行查看(其中哪个项目的声明位于最前方),则以该项目的为主(例如,在dependencies部分中可以看到项目间的引用关系)。最终Y将选择1.0版本。
这两个原则希望大家记住:路径最近原则、最先声明原则。
可选依赖(optional元素)
有这么一种情况:
A->B中scope:compile
B->C中scope:compile
按照上面介绍的依赖传递性,C会传递给A,被A依赖。
假如B不想让C被A自动依赖,可以怎么做呢?
在dependency项下设置一个optional字段,并将其定义为布尔型变量来表示可选依赖关系
排除依赖
A项目的pom.xml中
com.javacode2018
B
1.0
B项目1.0版本的pom.xml中
com.javacode2018
C
1.0
其中A->B采用的是v1.0版本,B->C也采用的是v1.0版本,而scope默认设置为compile。基于前面提到的依赖传递性原则,在这种情况下,C会将变更传递给A,从而使A自动获得相关依赖项。然而,C现在有一个更新后的v2.0版本,A希望使用该v2.0版本
<dependency>
<groupId>com.javacode2018</groupId>
<artifactId>B</artifactId>
<version>1.0</version>
<exclusions>
<exclusion>
<groupId>com.javacode2018</groupId>
<artifactId>C</artifactId>
</exclusion>
</exclusions>
</dependency>
通过排除exclusions元素阻止了B到C依赖关系的传递,换句话说, B->C就不会被传递给A
在exclusions中可能存在多个exclusion元素,在声明时可能会排除单个或多个依赖项的传递,在声明过程中仅需提供groupId和artifactId即可完成配置,在版本信息可选的情况下不影响功能。
总结
本章节内容还是比较多的,也是相当重要的,大家多看几遍,加深理解!
<dependency>
<groupId>com.javacode2018</groupId>
<artifactId>B</artifactId>
<version>1.0</version>
<exclusions>
<exclusion>
<groupId>com.javacode2018</groupId>
<artifactId>C</artifactId>
</exclusion>
</exclusions>
</dependency>
在上文中通过exclusions组件排除了B到C依赖关系的传递 从而就不会被传递给A中的相关节点
在exclusions中可能存在多个带有exclusion标签的元素,在声明这些排除项时,则只需提供groupId和artifactId即可。有可能会跳过一个或多个依赖项的传递过程,在声明exclusion时,则只需提供groupId和artifactId即可。版本号可选省略不写。
总结
本章节内容还是比较多的,也是相当重要的,大家多看几遍,加深理解!
