以下详解一下各个坐标元素:
groupId:定义当前Maven项目隶属的实际项目。首先,Maven项目和实际项目不一定是一对一的关系。比方SpringFramework这一实际项目。其相应的Maven项目会有非常多,如spring-core、spring-context等。一个实际项目一般会划分成多个项目模块。groupId不应该仅仅相应于项目隶属的组织或公司,原因是一个组织下会有非常多实际项目,假设groupId仅仅定义到组织级别,后面能够看到。artifactId仅仅能相应Maven项目。那么实际项目这个层将难以定义。
最后,groupId的表示方式与java包名的表示方式类似,通常与域名反向一一相应。
artifactId:该元素定义了实际项目中的一个Maven项目(模块)。推荐的做法是使用实际项目名称作为artifactId的前缀。比方上例的artifactId是nexus-indexer,使用了实际项目名nexus作为前缀。这样做的优点是方便寻找实际构件。
version:该元素定义了Maven项目当前所处的版本号。实际上,Maven定义了一套完整的版本号规范,以及快照(SNAPSHOT)的概念。在后面的章节将具体讨论。
packaging:该元素定义Maven项目的打包方式。首先,打包方式通常与所生成构件的文件扩展名相应,如上例中packaging为jar,终于的文件名称为nexus-indexer-2.0.0.jar。而是用war打包方式的Maven项目。终于生成的构件会有一个.war文件。但这不是绝对的。当不定义packaging时,Maven会是用默认值jar。
classifier:该元素用来帮助定义构件输出的一些附属构件。附属构件与主构件相应。如上例中的主构件是nexus-indexer-2.0.0.jar。该项目还会通过一些插件生成如nexus-indexer-2.0.0-javadoc.jar、nexus-indexer-2.0.0-sources.jar这样一些附属构件,其包括了Java文档和源码。这时候,javadoc和sources就是这两个附属构件的classifier。这样。附属构件也就拥有了自己唯一的坐标。注意:不能直接定义项目的classifier,由于附属构件不是项目直接默认生成的,而是由附加的插件帮助生成。
项目构件的文件名称是与坐标相相应的,一般的规则是artifactId-version[-classifier].packaging,[-classifier]表示可选。这里还要强调一点,packaging并不是一定与构件扩展名相应,比方packaging为maven-plugin的构件扩展名为jar。每一个依赖能够包括的元素有:
groupId、artifactId和version:依赖的基本坐标,对于不论什么一个依赖来说,基本坐标是最重要的,Maven依据坐标才干找到须要的依赖。type:依赖的类型,相应于项目坐标定义的packaging。大部分情况下。该元素不必声明,其默认值为jar。scope:依赖的范围。请见后面小节optional:标记依赖是否可选,请见后面小节exclusions:用来排除传递性依赖,请见后面小节假设没有指定,就会默认使用该依赖范围。该此依赖范围对于编译、測试、执行三种classpath都有效。典型的样例是spring-core,在编译、測试和执行的时候都须要使用该依赖。
test:測试依赖范围。该依赖范围仅仅对于測试classpath有效。在编译主代码或者执行项目的时将无法使用此类依赖。典型的样例就是JUnit。它仅仅有在编译測试代码及执行測试环境的时候才须要。
provided:已提供依赖范围。该依赖范围对于測试和执行class-path有效,但在执行时无效。典型的样例是servlet-api。编译和測试项目的时候须要该依赖。但在执行项目的时候。因为容器已经提供,就不须要Maven反复引入一遍。 runtime:执行时依赖范围。该范围依赖,对于执行和測试class-path有效,但在编译主代码时无效。典型的样例是JDBC驱动实现。项目主代码的编译仅仅须要JDK提供的JDBC接口,仅仅有在执行測试或者执行项目的时候才须要实现上述接口的详细的JDBC驱动。
system:系统依赖范围。该依赖与三种classpath的关系,和provided依赖范围全然一致。可是,使用system范围的依赖时必须通过systemPath元素显式地指定依赖文件的路径。因为此类依赖不是通过Maven仓库解析的,并且往往与本机系统绑定,可能造成构建的不可移植,因此应该慎重使用。systemPath元素能够引用环境变量。如:
<dependency> <groupId>javax.sql</groupId> <artifactId>jdbc-stdext</artifactId> <version>2.0</version> <scope>system</scope> <systemPath>${java.home}/lib/rt.jar</systemPath> </dependency> import: 导入依赖范围。该依赖范围不会对三种classPath产生实际的影响,我们将在后面的章节具体介绍该依赖。Maven会解析各个直接依赖的POM。将那些必要的间接依赖,以传递性依赖的形式引入到当前的项目之中。
传递性依赖和依赖范围: 如果A依赖与B,B依赖与C,我们说A对于B是第一直接依赖,B对于C是第二直接依赖。A对于C是传递性依赖。第一直接依赖的范围和第二直接依赖的范围决定了传递性依赖的范围。例如以下表所看到的,最左边一列表示第一直接依赖范围。最上面一行表示第二直接依赖范围。中间的交叉单元格则表示传递性依赖范围。
compiletestprovidedruntimecompilecompile - -runtimetesttest - -testprovidedprovided - -providedruntimeruntime - -runtime 细致观察该表,能够发现例如以下的规律:当第二直接依赖的范围是compile的时候。传递性依赖的范围与第一直接依赖的范围一致。当第二直接依赖的范围是test的时候,依赖不会得以传递;当第二直接依赖的范围是provided的时候,仅仅传递第一直接依赖范围也为provided的依赖,且传递性依赖的范围相同为provided;当第二直接依赖的范围是runtime的时候。传递性依赖的范围与第一直接依赖的范围一致,但compile例外。此时传递性依赖的范围为runtime。但有时候造成问题时。我们须要知道该传递性依赖是从哪条依赖路径引入的。
比如,项目A有这种依赖关系:A->B->C->X(1.0)、A->D->X(2.0),X是A的传递性依赖,可是两条依赖路径上有两个版本号的X,那么哪个X会被Maven解析使用呢?两个版本号都被解析是不行的,由于会造成反复依赖。Maven依赖的第一原则是:路径近期者优先。该例中X(1.0)的路径长度为3,而X(2.0)的路径长度为2。因此X(2.0)会被解析使用。 Maven定义了依赖调解的第二原则:第一声明者优先。在依赖路径长度相等的前提下,在POM中依赖声明的顺序决定了谁会被解析使用。顺序最靠前的那个依赖优胜。然而。因为这里X、Y是可选依赖,依赖将不会得以传递。
使用可选依赖的原因可能是B实现了两个特性,当中的特性一依赖于X。特性二依赖于Y,并且这两个特性是相互排斥的,用户不可能同一时候使用这两个特性。比方B是一个持久层隔离工具包,它支持多种数据库,包含MySQL,PostgreSQL等,在构建工具包的时候。须要这两种数据库的驱动程序。但在使用这个工具包的时候。仅仅会依赖一种数据库。 项目B的依赖声明见例如以下: <project> <modelVersion>4.0.0</modelVersion> <groupId>com.juvenxu.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> 在pom.xml中。使用 <optional>元素表示mysql-connector-java和postgresql这两个依赖为可选依赖,它们仅仅对当前项目B产生影响,当其它项目依赖于B的时候,这两个依赖不会被传递。因此,当项目A依赖于项目B的时候,假设事实上际使用基于MySql数据库。那么在A项目中就想要显示地声明mysql-connector-java这一依赖,见以下A项目pom.xml。 <project> <modelVersion>4.0.0</modelVersion> <groupId>com.juvenxu.mvnbook</groupId> <artifactId>project-a</artifactId> <version>1.0.0</version> <dependencies> <dependency> <groupId>com.juvenxu.mvnbook</groupId> <artifactId>project-b</artifactId> <version>1.0.0</version> </dependency> <dependency> <groupId>postgresql</groupId> <artifactId>postgresql</artifactId> <version>8.4-701.jdbc3</version> </dependency> </dependencies> </project> 在理想情况中,是不应该使用可选依赖的。使用可选依赖的背景是一个项目实现了多个特性,在面向对象的设计中,有个单一职责性原则,意指一个类应该仅仅有一项职责,而不是糅合太多的功能。在上面的样例中,更好的做法是为MySql和PostgreSQL分别创建一个Maven项目。基于相同的groupId分配不同的artifactId,如com.juvenxu.mvnbook;project-b-mysql和com.juvenxu.mvnbook:project-b-postgresql,在各自的POM中声明相应的JDBC驱动依赖,并且不适用可选依赖,用户则依据须要选择使用project-b-mysql或者project-b-postgresql。因为传递性依赖的作用。就不再声明JDBC驱动依赖。
也就是说。能够使用美元符号和大括弧围绕的方式引用Maven属性。然后,将全部Sping Framework依赖的版本号值用这一属性引用表示。
使用该工具能够得出两类内容:
Used undeclared dependencies 意指项目中使用到的。可是没有显式声明的依赖。这样的依赖意为着潜在的风险。当前项目直接在使用它们。比如有非常多相关Java import声明,而这样的依赖是通过直接依赖传递进来的。当升级直接依赖的时候,相关传递性依赖的版本号可能发生改变,接口就可能发生改变。那么就会导致当前项目中的相关代码无法编译。因此。一般应该显式声明不论什么项目中直接用到的依赖。
Unused declared dependencies 意指项目中未使用的,可是显式声明的依赖。对于这一类依赖,我们应该认真的分析,因为mvn dependency:analyze仅仅会分析编译主代码和測试代码须要用到的依赖。一些执行測试盒执行时须要的依赖它发现不了。所以我们应该认真分析该依赖是否会被用到再决定对该依赖的取舍。版权声明:本文博客原创文章。博客,未经同意,不得转载。
转载于:https://www.cnblogs.com/bhlsheji/p/4747621.html