02 坐标和依赖

一、坐标
Maven中的坐标用来标识构件。Maven中的任意构件都有一个唯一的坐标,Maven可以通过这个坐标在仓库中查找相关构件,我们开发自己的项目时也需要一个坐标。
坐标由groupId、artifactid、version、packaging、classifier构成,如:

<groupId>org.sonatype.nexus</groupId>
<artifactId>nexus-indexer</artifactId>
<version>1.0.0</version>
<packaging>jar</packaging>

 

1.groupId:
      定义当前Maven项目隶属的实际项目。首先,Maven和实际的项目不是一定的一一对应的关系。比如SpringFramework这个开源项目,由多个Maven项目如:spring-core、spring-context等。其次,groupId不应该对应到项目隶属的组织或公司。因为一个组织很可能会有多个实际项目。最后,groupId和表示方式和Java包名的表示方式类似。通常是域的反写。

 

2.artifactId
     定义实际项目中的一个Maven项目(模块),推荐的做法是使用实际项目的名称作为artifactId的前缀。这样的好处是方便寻找。

 


3.version
     定义Maven项目当前所处的版本。

4.packaging:(可选)
     定义Maven项目的打包方式。首先,打包方式通常与生成构件的文件扩展名对象。如上例生成的文件名为nexus-indexer-1.0.0.jar。使用war打包方式最终会生成一个.war文件。但这个不是绝对的。其次,打包方式会影响到项目构建的生命周期。例如jar打包和war打包会使用不同的命令。最后,当不定义packaging时,默认是jar。

5.classifer:(不可直接定义)
      该元素用来定义主构建的一些附属属性。附属属性与主构件对应。如上例中的nexus-indexer-1.0.0.jar是主构件。该项目还有一些附属构件如:nexus-indexer-1.0.0-source.jar、nexus-indexer-1.0.0-javadoc.jar。这时source和javadoc就是这两个构件的classifier。
注意:不能直接定义项目的classifer,因为附属构件项目的直接默认生成的,而是由附加的插件帮助生成的。

 

二、依赖
    声明依赖使用pom.xml的project根元素下dependencies元素。如:

 

    ...
	<dependencies>
		<dependency>
			<groupId>...</groupId>
			<artifactId>...</artifactId>
			<version>...</version>
			<type>...</type>
			<scope>...</scope>
			<optional>...</optional>
			<exclusions>
				<exclusion>
					...
				</exclusion>
				...
			</exclusions>
		</dependency>
		...
	</dependencies>
</project>

     每个dependencies可以包含任意个dependency元素,以声明一个一个依赖。每个依赖可用的属性有:
groupId、artifactId和version:依赖的基本坐标
type:依赖的类型,对应于项目坐标中的packaging。大部分情况下,该元素不必指定,其默认值是jar
scope:依赖范围
optional:标记依赖是否可选。
exclusions:用来排除传递性依赖。

 

三、依赖范围
      首先Maven在编译项目主代码时需要使用一套classpath;其实在编译的执行测试代码时会使用另一套classpath;最后,实际运行Maven项目时,又会使用一套classpath。
      依赖范围就是用来控制依赖与这三种classpath的关系。Maven有以下几种依赖范围:

  • compile:默认依赖范围。对于编译、测试和运行三种classpath都有效。 
  • test:只对于测试classpath有效
  • provided:只对编译和测试classpath有效,但在运行时无效。
  • runtime:对于测试和运行classpath有效,但在编译主代码时无效。
  • system:该依赖范围与三种classpath的关系和provided依赖范围完全一致。但是,使用system范围的依赖时,必须通过systemPath元素显式地指定依赖文件的路径。由于此类依赖不是通过Maven仓库获取的,而且往往与本机系统绑定,可能会造成不可移植,因此应该谨慎使用
  • import:该依赖范围不会对三种classpath产生实际影响。在继承和依赖管理时再介绍。


四、传递性依赖
     假设A依赖于B,B依赖于C,C就是A的传递性依赖。B是A的第一直接依赖,C是B的第二直接依赖。
     依赖范围不仅可控制依赖与三种classpath的关系,还会对传递性依赖产生影响。 第一直接依赖和第二直接依赖的范围会影响传递性依赖的范围。
当第二直接依赖的范围是compile时,传递性依赖的范围与第一直接依赖的范围一致;
当第二直接依赖的范围是test的时候,依赖不会传递;
当第二直接依赖的范围是provided时,只传递第一直接依赖范围也为provided的依赖,且传递性依赖的范围同样为provided;
当第二直接依赖的范围是runtime时,传递性依赖的范围与第一直接依赖的范围一致,但compile除外,此时传递性依赖的范围为runtime。


五、依赖调解
      Maven的依赖传递机器大大简化了依赖声明。大部分情况下,我们只需要关心项目的直接依赖,而不用考虑这些直接依赖会引入什么传递性依赖。但有时候,传递性依赖造成问题时,我们就需要清楚地知道传递性依赖是从哪条路径引入的。

例如,项目A的依赖关系为:A->B->C->X(1.0)、A->D->X(2.0)。X是A的传递性依赖,但是两条路径上的X版本不一致。
      Maven的依赖调解第一原则是:路径最近者优先,第二原则是:第一声明者优先。

 


六、可选依赖
      在声明依赖时可使用<optional>true<optional>标准,这表明是可选依赖,它们只会对当前项目产生影响,其他项目依赖于B时候,这两个依赖不会被传递。如果真要使用这个依赖,需要在项目中直接声明。
理想情况下,是不应该使用可选依赖的,使用可靠依赖的原因是某一个项目实现了多个特性,依据单一职责原则,更好的做法是他建多个Maven项目,用户根据需要选择使用哪个Maven项目。


七、最佳实践
1.排除依赖
      传递性依赖简化项目依赖的管理的同时,也可能会带来一些问题。例如,第当前项目有一个第三方依赖,而这个第三方依赖由于某些原因依赖了另一个类库的SNAPSHOT版本,而SNAPSHOT是不稳定的版本。这里就需要排除掉该SHAPSHOT版本,并在当前项目中声明该类库的某个正式版本。还有一些情况,比如Sun JTA API等由于版权因素,我们希望使用其他版本实现来代替。这时就可以使用:

 

<dependency>
	<exclusions>
		<exclusion>
			<groupId></groupId>
			<artifactId></artifactId>
		</exclusion>
	</exclusions>
</dependency>

 

     排除依赖不需要指定版本号

 

2.归类依赖
      在我们一些框架如Spring FrameWork时,会有很多依赖,它们的版本号是相同的。这时我们可以声明一个变量,然后在其他地方使用这个变量 。
声明变量如下:

<project>
<properties>
	<property>
		<springframework.version>2.5.6</springframework.version>
	</property>
</properties>
</project>

 

      使用方法如下:

<version>${springframework.version}</version>

 

 3.依赖分析优化
mvn dependency:list 查看解析后的最终依赖
mvn dependency:tree 查看解析后的依赖树
mvn dependency:analyze 帮助分析当前项目的依赖 
该命令的结果主要有两个部分:
首先是Used undeclared dependencies,指项目中使用到的,但是没有显式声明的依赖。
其次是Unused declared dependencies,指项目中未使用的显式依赖。

猜你喜欢

转载自lxmmt.iteye.com/blog/841044
02