二、坐标与依赖

坐标

前面一章已经讲过了,在maven的世界里,所有的一切都是以坐标定位的,是时候对坐标做一个详细解释了

TIM图片20170721230132.gif

在坐标中,有以下几个成员groupId,artifactId,version,packaging,classifier
groupId表示方式通常与包名表示方式类似,通常与域名反向一一对应,格式为域名或组织名反向.项目名。比如:groupId=org.sonatype.nexus, sonatype.org为一个组织,nexus为该组织下的一个实际项目
artifactId该元素定义实际项目中的某一个模块,推荐以实际项目名称做前缀
version定义maven项目当前所处版本,有snapshot,alpha,beta,release几种类型的版本类型,具体在后面章节专门介绍
packaging定义当前maven项目的打包方式,有jar,pom,war几种方式,打包方式通常与项目生成构建的文件扩展名对应,比如下面的依赖groupId:artifactId:version:packaging=org.sonatype.nexus:nexus-indexer:2.0.0:jar将会生成:nexus-indexer-2.0.0.jar
classifier用于定义构建输出一些附属构建,比如javadoc,source,但是不能直接定义classifier,因为附属构建不是项目直接生成的,需要借助插件

项目文件名
maven中项目文件名的生成完全依赖于坐标,生成的一般规则为:artifactId-version[-classifier].packaging

依赖

依赖是maven中一大核心,项目中用到的所有第三方资源都是通过依赖导入到项目中使用的,下面是依赖的基本架构:


    
        
        
        
        
        
        
        
            
                
                
            
        
    

  • groupId,artifactId,versionmaven坐标系的基本坐标,对于每一个构建来说都是必须的
  • type声明依赖的类型,与项目packaging对应,默认值为jar
  • scope依赖范围,maven中对编译,测试,运行三个环境提供了6种依赖范围test,provide,import,compile,runtime,system,他们之间的具体关系将在下面讲到
  • optional标记依赖是否为可选依赖,默认为false
  • exclusions用来排除一些传递性依赖

依赖范围scope
maven中有3中classpath编译测试运行
围绕这三种classpath又分出了6种不同的依赖范围
compile(default),test,provide,runtime,system,import

图片1.png

compile默认依赖范围,对于编译、测试、运行有效,比如我们需要用到的spring-core
test测试范围,只对测试环境有效,正式部署时将不会被打包,也就是只能在代码测试中起作用,比如junit
provided已提供范围,针对编译、测试有效,运行时无效,比如servlet-api,tomcat服务器内部已经提供了
runtime测试、运行时有效,对编译无效,比如jdbc驱动,项目主代码的编译只需要jdk提供的jdbc接口,只有在测试和运行时才需要上述接口的具体实现
system系统依赖范围,该依赖与三种classpath的关系和provided依赖范围完全一致,但是使用system范围的依赖时必须通过systemPath元素显示的指定依赖文件的路径,使用此类依赖主要目的是为了使用系统本机jar,会与本机系统绑定,可能造成构建的不可移植,因此应该谨慎使用
下面是一个system依赖范围的使用方式

    javax.sql
    jdbc-stdext
    2.0
    system
    ${java.home}/lib/dt.jar

import导入依赖范围,该依赖范围不会对上面提到的三种classpath产生实际的影响,只针对dependencyManagement有效

传递性依赖
在引入一个依赖的时候,被引入的依赖同时又依赖了其他开源类库,这时该项目就发生了传递性依赖
maven传递性依赖为用户减少了配置依赖不必要的麻烦,我们在实际引入一个依赖时无需考虑该依赖是否还需要额外的引入其他开源类库,maven传递性依赖自动为我们处理了这类问题

传递性依赖和依赖范围
依赖范围(scope)不仅可以控制与三种classpath的关系,而且还会影响传递性依赖

图片2.png
图片4.png

从上面的图片中可以得出一些结论:

  • 第二依赖如果是compile,那么最后得到的jar包依赖范围为第一依赖的值
  • 第二依赖如果是test,则jar包将不被包含(依赖范围为空)
  • 第二依赖如果是provide, 只有第一依赖为providejar包有效,且依赖范围为provide
  • 第二依赖如果是runtime, 当第一依赖为compile时,最终依赖为runtime,其他范围不变

依赖调节
既然maven中存在传递依赖,那么又会存在一系列问题,比如

图片5.png

针对上面情况产生规则:
1 最短路径优先原则
maven最终会使用A->D->C
如果原则一不能解决问题,比如两个方向的路径相同,这时会怎么办?
图片6.png

2 第一声明优先
也就是说在pom.xml中谁先声明则选谁,与版本没有关系,如果B先于D声明,则最后会取 A->B->Y

可选依赖
可选依赖的声明格式形如:


    ...
    true
    ...

可选依赖的一个使用场景是当对某一业务有不同实现,比如对数据库的操作,有jdbc,oracle等实现类库,但理想情况下是不应该使用可选依赖的,对于项目实现的多样性,可以抽离成不同的项目,让用户自己选择具体依赖实现,比如对jdbc实现分离出一个项目模块,对oracle实现又分离出另一个模块供用户选择性使用

依赖排除(exclusions)
在某些情况下,我们需要排除传递依赖的其他开源类库,而引入指定的类库,这时需要使用exclusions来对依赖进行排除


    
        
            
            
        
    

在对依赖进行排除时只需要指定groupId,artifactId即可,因为在一个pom文件中,优化的依赖不可能存在相同的groupId,artifactId不同的version的依赖存在

归类依赖(properties)
对于来自同一个项目的不同模块,他们的版本都是一致的,考虑到代码到简洁便于修改以及重复问题,可以将version放在一处统一管理,这里就需要用到properties元素


    4.2.3

在使用了属性变量后,在pom的依赖管理中使用到指定的变量就可以采用${property}的方式引用了,比如


    org.springframework
    spring-context
    ${spring.version}

依赖优化
我们可以借助maven提供的一些命令工具来了解当前依赖的具体情况

列表显示依赖情况list
mvn dependency:list
命令将会列出当前项目中使用的依赖包信息,包括版本、依赖范围等信息

图片7.png

树形结构显示依赖情况tree
mvn dependency:tree
将会以树形形式展现当前项目传递依赖的情况

图片8.png

分析依赖analyze
mvn dependency:analyze
使用上述命令可以了解当前项目在编译时有哪些使用到了但没有明确指定的依赖(used undeclared dependencies)以及明确指定但是没有被使用的依赖(unused declared dependencies)

图片9.png

used undeclared dependencies:
对于这类依赖意味着项目存在风险,因为项目直接使用了传递依赖,当依赖的包版本升级可能会导致传递依赖失效,这时项目极有可能会编译报错,针对这类型问题的解决方式是:在项目中显示指定所有使用到的依赖
unused declared dependencies:
针对这类依赖则需要小心分析,因为mvn dependency:analyze只会分析编译主代码和测试代码需要使用到的jar,对于执行测试和运行时的依赖是无法察觉的,删除需小心谨慎!!!

你可能感兴趣的:(二、坐标与依赖)