Maven dependency and repository (part a)

系统 1530 0
我们看一个最常见到的例子:
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.mycompany.app</groupId>
<artifactId>my-app</artifactId>
<packaging>jar</packaging>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
 
该例子表示你的project有一个junit dependency。你可能会问:这个dependency从哪里来?junit jar在哪里?
 
A dependency 是对 repository 里的某个 artifact 的引用。 POM 定义了一个 dependency ,执行的时候就会根据 dependency groupId, artifactId and version ,来 search it from repository 你根本不需要在 pom.xml 里指明该 dependancy 来自哪个 repository maven 会先查找 local repository ,如果 local repository 存在该 dependancy 引用的 artifact ,就使用它,如果不存在,则搜索所有你设置的 remote repository ,如果找到它,就把它 download local repository 缺省状态下,通常都是从central maven repository( http://www.ibiblio.org/maven2 )来download artifact。 如果你的 pom.xml 定义了多个 remote repository ,那么就按顺序依次试图从 remote repository 下载 .
 
例如上面的例子,maven会先check local repository看是否有想要的junit artifact,如果没有,则从remote repository download到local repository。这时,local repository里artifact目录结构包含:
  Maven dependency and repository (part a)
 
下图是在repository里所有artifact通用的目录结构:
  Maven dependency and repository (part a)
 
groupId是fully qualified domain name,例如为x.y.z,则结构为:
  Maven dependency and repository (part a)
 
maven 是如何根据定义的 dependancy 来从 repository 里查找呢?例如上例,就会根据 groupId “junit”, artifactId “junit”, and version 3.8.1” ,在 repository 里查找 ~/.m2/repository/junit/junit/3.8.1/junit-3.8.1.jar
 
 
dependancy 功能是 maven 最强大的功能和最显著的优势。以前 maven 没出现之前,通常的 project 都会把要用到的 jar files 都放在 project subdirectory 下,或开发一个 web app ,你要把 10 多个 jar 添加到 classpath ,并把它们放到 lib 目录下。这样如果你开发 100 个类似的 web app ,你的每一个 web app 开发目录下面都会包含有这些 jar files 。这样如果某个 jar 的版本出现更新,就会要更新 100 project 里的 jar 。而使用 maven ,就会大大减轻你的工作量。
 
例如,你有100个web app都使用了spring 1.2.6 framework,如果你使用maven,你不需要存储所有的spring jars到各个project里,你只需要在POM.XML里定义一个spring dependancy,那么如果升级到spring 2.0,只需要把pom.xml里dependancy的<version>修改为2.0即可。
 
 
Dependency机制介绍
 
Dependency 机制的三个知识点
  • Transitive Dependencies
  • Dependency Scope
  • Dependency Management
Transitive Dependencies (可传递的依赖)
这是maven 2.0的新特征。 它使你不需要指定 dependency 的位置而自动定位。而且可传递的依赖就是说依赖能够自动继承和传递,例如 project A 依赖 project B artifact ,而 project B 则依赖 project C artifact ,那么在 build project A 时,就会使用到所有 project 、子 project 的依赖。
 
一个project的 依赖的总个数没有限制,但是如果出现死循环依赖则会出现问题。
 
由于依赖可以传递,因此有可能一个project要依赖的东东会很多,因此可以通过下列几种方式来限制要包括的dependency:
  • Dependency mediation 意思是 强烈建议显式设置你使用的 dependency 的版本号,因为 dependency 可能会有多种版本。目前 Maven 2.0 支持 "nearest definition" (见下面的解释)。 注意:如果在 dependency tree 的同一个 depth 里定义了同一个 dependency 2 个版本,那么使用先定义的那个版本
    • "nearest definition" 表示在 dependencies tree 里最靠近你的 project 的版本。例如,如果 project A 的依赖性为: A -> B -> C -> D 2.0 A -> E -> D 1.0, 那么 D 1.0 版本将会被使用。因为从 A 通过 E 到达 D 的路径是最短的。如果本例你硬是想要使用 D 2.0 ,那么你可以在 A 里定义一个 D dependency
 
  • Dependency management 表示 maven 允许你在你的 pom.xml 里设置你要使用的 depedency 的版本号,即使这个 depedency 你可能不知道是从哪里来的可传递依赖,也不知道该依赖定义的版本是什么,你都可以根据“ nearest definition ”法则来在你的 pom.xml 里设置版本号。 例如上面的例子,你可以直接在 A 里设置对 D 的依赖(设置版本号),即使 A 并不直接使用 D
 
  • Dependency scope 尽量为要包含的 dependencies 设置要用到它的 scope 下面会详细解释
 
 
Dependency Scope
Dependency scope 是设置什么 stage 要使用它,用来限制依赖的传递。
 
总共有5种Scopes:
  • compile 这是缺省 scope ,表明是所有任务所需的资源。“ Compile dependencies are available in all classpaths.
  • provided 表示该 dependency JDK 部分或应用服务器的 classpath 里已经自带的资源, 例如 EJB dependency jars ,只需要在 compile 时使用,在例如打包时就不应该把它打包进 jar, war or ear 里,因为 JDK or APP SERVER 里本身就有。
  • runtime - this scope indicates that the dependency is not required for compilation, but is for execution . It is in the runtime and test classpaths, but not the compile classpath.
  • test 表示该 dependency 只会在 test compilation and execution phases 使用。 例如在使用 junit 依赖 时, scope 参数的值为 test 来告诉 Maven 这个依赖项只是在测试阶段所需的,而不是运行时所需的资源。
  • system - this scope is similar to provided except that you have to provide the JAR which contains it explicitly. The artifact is always available and is not looked up in a repository. 后面会详细讲解
不同的 scope 会影响“依赖的依赖”的 scope 。下表列出的就是当一个“依赖”的scope设置为最左一列的scope,那么设置成最上一行scope的“依赖的依赖”的scope将发生的变化列表。
 
Compile
provided
runtime
test
compile
compile(*)
-
runtime
-
provided
Provided
provided
provided
-
runtime
Runtime
-
runtime
_
Test
Test
-
test
-
 
 
Dependency Management
在parent pom里 使用 < dependencyManagement> 来简化 dependency 设置 。举个例子:
Project A:
<project>
 ...
 <dependencies>
    <dependency>
      <groupId>group-a</groupId>
      <artifactId>artifact-a</artifactId>
      <version>1.0</version>
      <exclusions>
        <exclusion>
          <groupId>group-c</groupId>
          <artifactId>excluded-artifact</artifactId>
        </exclusion>
      </exclusions>
    </dependency>
    <dependency>
      <groupId>group-a</groupId>
      <artifactId>artifact-b</artifactId>
      <version>1.0</version>
      <type>bar</type>
      <scope>runtime</scope>
    </dependency>
 </dependencies>
</project>
 
Project B:
<project>
 ...
 <dependencies>
    <dependency>
      <groupId>group-c</groupId>
      <artifactId>artifact-b</artifactId>
      <version>1.0</version>
      <type>war</type>
      <scope>runtime</scope>
    </dependency>
    <dependency>
      <groupId>group-a</groupId>
      <artifactId>artifact-b</artifactId>
      <version>1.0</version>
      <type>bar</type>
      <scope>runtime</scope>
    </dependency>
 </dependencies>
</project>
 
下面通过在parent pom里使用< dependencyManagement>来管理child pom要使用的dependencies。
Parent Project:
<project>
 ...
 <dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>group-a</groupId>
        <artifactId>artifact-a</artifactId>
        <version>1.0</version>
 
        <exclusions>
          <exclusion>
            <groupId>group-c</groupId>
            <artifactId>excluded-artifact</artifactId>
          </exclusion>
        </exclusions>
 
      </dependency>
 
      <dependency>
        <groupId>group-c</groupId>
        <artifactId>artifact-b</artifactId>
        <version>1.0</version>
        <type>war</type>
        <scope>runtime</scope>
      </dependency>
 
      <dependency>
        <groupId>group-a</groupId>
        <artifactId>artifact-b</artifactId>
        <version>1.0</version>
        <type>bar</type>
        <scope>runtime</scope>
      </dependency>
    </dependencies>
 </dependencyManagement>
</project>
 
使用上面parent pom就会简化child pom的dependency设置:
<project>
 ...
 <dependencies>
    <dependency>
      <groupId>group-a</groupId>
      <artifactId>artifact-a</artifactId>
    </dependency>
 
    <dependency>
      <groupId>group-a</groupId>
      <artifactId>artifact-b</artifactId>
      <!-- This is not a jar dependency, so we must specify type. -->
      <type>bar</type>
    </dependency>
 </dependencies>
</project>
 
注意 : 在上面的 dependency 引用中,非 jar 的必须使用 <type> element
Dependency management 的另一个很有用的用处就是控制 dependency 的版本 。还是举例:
Project A:
<project>
 <modelVersion>4.0.0</modelVersion>
 <groupId>maven</groupId>
 <artifactId>A</artifactId>
 <packaging>pom</packaging>
 <name>A</name>
 <version>1.0</version>
 <dependencyManagement>
   <dependencies>
     <dependency>
       <groupId>test</groupId>
       <artifactId>a</artifactId>
       <version>1.2</version>
     </dependency>
     <dependency>
       <groupId>test</groupId>
       <artifactId>b</artifactId>
       <version>1.0</version>
       <scope>compile</scope>
     </dependency>
     <dependency>
       <groupId>test</groupId>
       <artifactId>c</artifactId>
       <version>1.2</version>
       <scope>compile</scope>
     </dependency>
     <dependency>
       <groupId>test</groupId>
       <artifactId>d</artifactId>
       <version>1.2</version>
     </dependency>
   </dependencies>
 </dependencyManagement>
</project>
 
Project B:
<project>
 <parent>
    <artifactId>A</artifactId>
    <groupId>maven</groupId>
    <version>1.0</version>
 </parent>
 <modelVersion>4.0.0</modelVersion>
 <groupId>maven</groupId>
 <artifactId>B</artifactId>
 <packaging>pom</packaging>
 <name>B</name>
 <version>1.0</version>
 <dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>test</groupId>
        <artifactId>d</artifactId>
        <version>1.0</version>
      </dependency>
    </dependencies>
 </dependencyManagement>
 <dependencies>
    <dependency>
      <groupId>maven-test</groupId>
      <artifactId>a</artifactId>
      <version>1.0</version>
      <scope>runtime</scope>
    </dependency>
    <dependency>
      <groupId>maven-test</groupId>
      <artifactId>c</artifactId>
      <scope>runtime</scope>
    </dependency>
 </dependencies>
</project>
 
上面可以看出project A是project B的parent,A和B都定义a, c, d dependencies,那么如果对project B执行maven命令,会采用哪个定义的呢?答案如下:
  • dependency a and c 将会采用 1.0 版本。 尽管在 parent project A 里定义的 a and d 的版本是 1.2 ,但根据 dependency mediation "nearest definition" 特性,采用的是 project B 定义的版本。
  • dependency b 只在 parent project A 里有定义,因此就采用 project A 的定义。 即使 Dependency c 会使用不同版本的 b, 如果执行 project B 还是会采用 project A 定义的版本 (还是根据 dependency mediation "nearest definition" 特性)。
  • dependency d 的情况和 dependency b 的差不多:由于它在 A B 都用定义,因此是采用 project B 定义的版本 1.0 。假如 Dependency c 会使用不同版本的 d, 如果执行 project B 还是会采用 project B 定义的版本(还是根据 dependency mediation "nearest definition" 特性)。
System scope Dependency
System scope dependencies 总是 available 的,而且不需要从 repository 里获取,因为定义成 system scope dependencies 都是由 JDK or VM 提供的。典型的例子就是 JDBC standard extensions Java Authentication and Authorization Service (JAAS).
例子 :
<project>
 ...
 <dependencies>
    <dependency>
      <groupId>javax.sql</groupId>
      <artifactId>jdbc-stdext</artifactId>
      <version>2.0</version>
      <scope>system</scope>
      <systemPath>${java.home}/lib/rt.jar</systemPath>
    </dependency>
 </dependencies>
 ...
</project>
如果你的 artifact 来自 JDK's tools.jar ,那么 system path 应该定义为:
<project>
 ...
 <dependencies>
    <dependency>
      <groupId>sun.jdk</groupId>
      <artifactId>tools</artifactId>
      <version>1.5.0</version>
      <scope>system</scope>
      <systemPath>${java.home}/../lib/tools.jar</systemPath>
    </dependency>
 </dependencies>
 ...
</project>
 

Maven dependency and repository (part a)


更多文章、技术交流、商务合作、联系博主

微信扫码或搜索:z360901061

微信扫一扫加我为好友

QQ号联系: 360901061

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描下面二维码支持博主2元、5元、10元、20元等您想捐的金额吧,狠狠点击下面给点支持吧,站长非常感激您!手机微信长按不能支付解决办法:请将微信支付二维码保存到相册,切换到微信,然后点击微信右上角扫一扫功能,选择支付二维码完成支付。

【本文对您有帮助就好】

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描上面二维码支持博主2元、5元、10元、自定义金额等您想捐的金额吧,站长会非常 感谢您的哦!!!

发表我的评论
最新评论 总共0条评论